feat(i18n-ko): core — add ko to UiLocale model - #5011
Conversation
Add `ko` to UI_LOCALES so the closed locale vocabulary carries Korean: the `isUiLocale`/`isUiLocalePreference` guards accept it, and `resolveSystemUiLocale` recognizes the `ko` prefix through the existing case-insensitive, `_`-normalizing path (`ko`, `ko-KR`, `ko_KR`, `ko_KR.UTF-8`), so an `auto` preference resolves to it without being persisted. `uiLocaleToIntlLocale` stops being identity. Every locale so far was already the tag `Intl` wants; bare `ko` leaves the region open, and the region is what selects Korean date, number, and plural formatting, so it is widened to `ko-KR`. The return type becomes the literal union of the tags actually emitted — `'zh-CN' | 'zh-TW' | 'en' | 'ko-KR'` — rather than `string`, so the set stays visible in the signature. Every call site feeds an `Intl` constructor, `toLocaleString`, or `localeCompare`, all of which take `string`, so narrowing it is safe. The formatter test can no longer assert identity, so it pins the tag table instead and checks each tag is canonical, which keeps a locale added later from reaching `Intl` without a deliberate tag. Refs apache#3975 Generated-by: Claude Code
`ko` joined `UI_LOCALES` in the previous commit, and `UiCatalog<T>` is `Record<UiLocale, T>`, so every catalog in the package became structurally incomplete at once. Three carried copy without a Korean branch: `GENERALIZED_ERROR_COPY`, `JUST_NOW`, and `STRINGS_BY_LOCALE`. Fill them in so `@maka/core` typechecks again. The generalized-error and just-now catalogs are direct translations. The quiet-preview strings follow the English branch rather than the Chinese one where the two disagree: `moreQuestions` reports the remainder past the previewed entry (`외 1개` for two questions) instead of the total the Chinese branches state, since that is how the count reads naturally in Korean. `bytes` and `replacements` likewise drop the `共`/`等` prefixes that have no Korean counterpart. `uiLocaleToIntlLocale` already widens `ko` to `ko-KR`, so the relative formatter picks up Korean units without further work; the test pins `1분 전` to keep that path honest. Tests mirror the existing per-locale coverage: a full classification table for Korean asserting Hangul output and no secret leakage, the shared cross-catalog routing assertions, the just-now and sidebar-unit cases, and the quiet-preview question-count and background-terminal lines. Verified with `npm run build:test` through `@maka/core`, the three suites under `packages/core/dist/__tests__` (54 passing), the full core suite (841 passing), and biome lint/format on the touched files. `@maka/core` typechecks clean. Downstream packages still carry catalogs without `ko` and are left to their own commits. Refs apache#3975 Generated-by: Claude Code
|
The three core catalogs are on the branch now (36a4377):
@ggbdpq — one item is off your plate: CI on 36a4377 is red, as expected, and every one of the 7 errors is the same shape: These are Worth recording for the integration plan: these maps are not among the 126 |
|
@heeoneie — one contribution-attribution choice before we turn the Korean work into its final integration shape. The repository cannot grant upstream write access to contributors, and GitHub native stacked PRs require every branch to live in You do not need to manage an integration branch or rebase other contributors. Please choose the shape you prefer:
Both preserve #5011 as your public PR and #5075 as your public audit contribution. The difference is whether the final history has a separate Korean-core squash commit. Please reply |
|
Two reasons, and one request. Option 1 is the only one of the two that leaves the locale contract revertible on its own. If It also fits what #3853 established, and improves on it slightly. That PR merged four commits from The request: please carry the Happy to rebase #5011 onto whatever you need, or to leave it untouched as the reviewed reference — whichever makes the bridge branch easier to cut. I will keep #5075 updated as the audit gate either way. |
|
@heeoneie — option 1 is confirmed. I reviewed the exact I will recreate the reviewed core layer on an Please reply with the email address associated with your GitHub account that you want in that trailer (a GitHub noreply address is fine). This avoids guessing an identity address. You do not need to rebase #5011 or manage the bridge branch. |
|
@heeoneie — the official bridge is now open as #5100: #5100 It is based on current #5011 remains the canonical reviewed source and public record of the work. #5100 is draft-only stack infrastructure; it will not merge by itself. No rebase is needed from you. |
Do not merge. This is the shared core base for the Korean locale stack, opened as a draft at @me2seeks's request on #3975. It must not land on
mainon its own.Refs #3975. Part of #3974.
Why this cannot merge alone
UiCatalog<T>isRecord<UiLocale, T>, so addingkotoUI_LOCALESmakes every catalog in the repository require akoentry — 126 of them at the time I counted. This branch enables the locale; the catalogs arrive here and in the slice PRs. CI on this branch is expected to be red until every strict catalog is complete. That is the atomic/stacked delivery model working as intended, not a regression.Delivery contract
Per @me2seeks's decision on #3975:
UiCatalog<T>stays strict — no widening to an optional catalog type.What is here now
UI_LOCALESgainsko;isUiLocaleandisUiLocalePreferenceaccept it.resolveSystemUiLocalerecogniseskovia/^ko(?:[-.]|$)/iu, reusing the existing trim and_→-normalisation.uiLocaleToIntlLocalemapsko→ko-KRand returns the literal union'zh-CN' | 'zh-TW' | 'en' | 'ko-KR'rather than widening tostring, so the set of tags we actually emit stays visible in the signature. Adopted from @scs0209's shape in feat(i18n-ko): native surfaces and E2E fixtures #4515 — we reached the same mapping independently.Locale tests, including
kok-IN → enso that a later simplification of the pattern to/^ko/icannot silently start matching Konkani, and both system-language ordering assertions (['en', 'ko'] → en,['ko', 'en'] → ko).redaction.ts(GENERALIZED_ERROR_COPY),relative-time.ts(JUST_NOW) andtool-quiet-preview.ts(STRINGS_BY_LOCALE) carry theirkoentries — the three catalogs@maka/coreneeds in order to compile withko, per the delivery decision. Their tests mirror the existingzh-CN/zh-TWblocks: the same raw-to-expected table for the error copy plus a Hangul assertion, the just-now string across all three relative-time formatters, and thekoquiet-preview lines.The core base is complete
@maka/corebuilds, typechecks and tests green withkoas of 36a4377. What remains red is downstream and belongs to the slice PRs, not to this branch.Notes
['zh', 'en']in feat(i18n-ko): core — add ko to UiLocale model #3975's body is stale.UI_LOCALESis['zh-CN', 'zh-TW', 'en']onmainsince feat(i18n): add Traditional Chinese locale #3853, andzhsurvives only as a legacy persisted value thatnormalizeUiLocalePreferencefolds intozh-CN.uiLocaleToIntlLocale(locale) === locale.kois the first locale to break that identity, so it is replaced with a pinned tag table plus anew Intl.Locale(tag).baseName === tagcanonicality check.parseLocaleFlag— are not addressed here. @me2seeks asked for them to be assigned before integration; I will open a tracking issue and link it from this PR.as constlocale maps that are indexed with aUiLocalerather than declared asUiCatalog<T>. They are not among the 126 catalog sites, and they only fail oncekois in the union, so the census understates the remaining work. I will fold them into the same tracking issue.@scs0209 @ggbdpq @xiechimon — this is the branch to rebase onto.
Verification
Run on this branch at 36a4377:
@maka/coretypecheck — clean.redaction.test.ts,relative-time.test.tsandtool-quiet-preview.test.ts.biomelint and format on the six changed files — clean.npm run build:test— does not complete. It now gets past@maka/coreand fails inpackages/cli.testjob fails with 7 errors, every one of them the same shape: aUiLocaleexpression indexing anas constlocale map that carriesen,zh-CNandzh-TWbut noko. Two of them are TUI surfaces (the transcript view and the todo panel). None is in@maka/core, and none is introduced by the catalog commit — they follow fromkoenteringUI_LOCALESin 7b45e32.Repo-wide typecheck and the full test run are expected to stay red until every strict catalog is complete.
AI use
Select exactly one:
Tool(s) and scope: Claude Code — drafted the
ui-locale.tschange and the locale tests, and this description. Reviewed, verified and submitted by me; the affected commit carries aGenerated-by: Claude Codetrailer, which must survive the eventual squash.Checklist
Lint, format, and
@maka/core's typecheck and full suite pass. Repo-wide typecheck andbuild:testdo not, and are not expected to on this branch alone — see Verification and "Why this cannot merge alone".Does this PR entail a change in behavior?