2.4 KiB
Localization (i18n)
Tracking issue: #606. Goal: adding a language is a catalog change, not a code change.
Where UI text lives
| Surface | Source |
|---|---|
| Web, desktop renderer, API, browser extension | Shared catalogs in packages/shared/src/i18n/ (zh-CN.ts, en-US.ts, ja.ts, pl.ts, ru.ts) — the source of truth. |
| Desktop main process | apps/desktop/src/main/desktop-copy.mjs and desktop-menu.mjs keep their own tables keyed by the same codes (desktopLocales), because the main process cannot import the TS catalogs. |
Android (apps/mobile), iOS (apps/ios) |
Not migrated yet; follow-up PRs under #606. |
Locale codes and helpers are in packages/shared/src/i18n/locales.ts: supportedLocales, matchSupportedLocale, resolveSupportedLocale, localeEnglishNames (English names used in AI prompts such as "Reply in Polish").
Rule
Resolve a locale code, then read text from the catalog. Do not compare language strings in code (if (lang === "zh-CN") ...). Format dates and numbers with Intl using the locale code.
packages/shared/src/i18n/hardcoded-locale-guard.test.mjs rejects new hard-coded language comparisons outside i18n code. It has an explicit allowlist for content-language logic, such as subtitle tracks, sample data, and docs that exist only in some languages.
Adding a language
- In
locales.ts: add the code tosupportedLocales, a branch inmatchSupportedLocale(e.g.xx/xx-*), and an entry inlocaleEnglishNames. - Add
packages/shared/src/i18n/<code>.tswith every key.catalog.test.mjsenforces key parity across locales. - Export it from
packages/shared/src/i18n/index.tsand add./i18n/<code>toexportsinpackages/shared/package.json. - Web: add
apps/web/src/i18n/resources/<code>.ts(re-export), load it lazily inapps/web/src/i18n/index.ts(isOptionalLocale,loadOptionalCatalog,fallbackLng), and add a label inlocaleLabels(apps/web/src/i18n/locales.ts). - Desktop main: add the code to
desktopLocalesand its entries to the tables indesktop-copy.mjsanddesktop-menu.mjs. - Run the tests:
bun test packages/shared/src/i18n, thenbun run typecheck.
Adding a string
Add the key to all five catalogs in the same change. The parity test fails if any catalog is missing it. Strings shown by the desktop main process go into its tables instead, again for every code.