Skip to content

feat(i18n): ship CJK and FIGS locales alongside English - #178

Closed
iAstro wants to merge 2 commits into
Tencent:mainfrom
iAstro:feat/multi-language-support
Closed

feat(i18n): ship CJK and FIGS locales alongside English#178
iAstro wants to merge 2 commits into
Tencent:mainfrom
iAstro:feat/multi-language-support

Conversation

@iAstro

@iAstro iAstro commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

What this adds

Seven translated bundles on top of the existing English and Simplified Chinese: zh-TW, ja, ko, fr, it, de, es. The UI now follows the browser language across the major markets instead of falling back to Chinese (#168) or, after #174, to English only.

Resource keys

Bare language subtags for the new languages, so regional variants share one bundle:

Browser language Resource
en* en-US
zh-Hans*, zh-CN, zh-SG, zh zh-CN
zh-Hant*, zh-TW, zh-HK, zh-MO zh-TW
ja, ja-JP ja
ko, ko-KR ko
fr, fr-FR, fr-CA fr
it, it-IT it
de, de-DE, de-AT de
es, es-ES, es-MX es

Chinese stays split by script (zh-CN / zh-TW) because Simplified and Traditional differ by script rather than by region.

Fallback chain

fallbackLng: { en: ["en-US"], zh: ["zh-CN"], ja: ["ja"], ko: ["ko"],
               fr: ["fr"], it: ["it"], de: ["de"], es: ["es"],
               default: ["en-US"] }

An untranslated locale (pt-BR, ru-RU, ...) still lands on English rather than Chinese.

Tests

28 -> 80 cases. Beyond the expanded resolution table, the bundles are checked structurally - every locale must:

  • expose the same key set as en-US (catches a missing or leftover key)
  • keep identical {{placeholders}} (a dropped one renders as a blank gap)
  • leave no key empty
  • leave browser-skill / BrowserSkill untranslated
OK packages/i18n  80/80
OK apps/extension 798/798
OK tsc --noEmit, biome check, pnpm ext:build all clean

Notes for reviewers

  • Bundle size: 1.15 MB -> 1.24 MB (+90 KB, ~7.8%). All nine bundles are statically imported as decided. This is larger than the ~30 KB estimated during planning because the JSON is not tree-shaken per locale; switching to dynamic per-locale loading remains possible if this matters.
  • Built on fix(i18n): match browser locale by language subtag instead of exact code #174: this branch stacks on the locale-normalisation work, so it contains that commit too, and can be rebased once fix(i18n): match browser locale by language subtag instead of exact code #174 merges.
  • Translation notes: covers the 74 existing strings. Terms like daemon, protocol, instance ID and trace are kept consistent across languages. The stateBadge values (Standby / Igniting / Ready / Off) stay in English, matching the deliberate choice already made in the zh-CN bundle.

Closes #168

The extension ships en-US and zh-CN resources, but only en-US was ever
selected: every other browser language fell through to fallbackLng
("zh-CN"), so users on en, en-GB, en-CN, en-AU, ja-JP, fr-FR saw Chinese.

Match on the BCP 47 language subtag and normalise it to a resource key:

  en*                                -> en-US
  zh-Hans* / zh-CN / zh-SG / zh      -> zh-CN
  zh-Hant* / zh-TW / zh-HK / zh-MO   -> zh-TW
  anything else                      -> unchanged (fallbackLng default: en-US)

Simplified vs Traditional is decided by the script subtag (Hans/Hant) when
present, then by the region subtag, since Chrome reports zh-CN / zh-TW
rather than script subtags. The zh-TW branch is written now so adding a
Traditional translation later needs no code change.

chrome.i18n.getUILanguage() is now preferred over navigator.language, which
is unreliable on the chrome-extension:// origin the popup runs on.

Adds a locale-resolution regression matrix (28 cases).

Closes Tencent#168
Adds seven translated bundles — zh-TW, ja, ko, fr, it, de, es — so the
UI follows the browser language across major markets instead of falling
back to Chinese (Tencent#168) or, after Tencent#174, to English only.

Resource keys use bare language subtags (ja, ko, fr, it, de, es) so
regional variants share one bundle: fr-CA, fr-BE and fr all resolve to
fr. Chinese stays split by script, zh-CN / zh-TW, because Simplified
and Traditional differ by script rather than by region.

normalizeLanguageCode now resolves every shipped language from a single
map, and fallbackLng gained a per-language chain:

  fallbackLng: { en: [en-US], zh: [zh-CN], ja: [ja], ko: [ko],
                 fr: [fr], it: [it], de: [de], es: [es],
                 default: [en-US] }

so an untranslated locale still lands on English rather than Chinese.

Tests grow from 28 to 80 cases. Besides the expanded resolution table,
the bundles are now checked structurally: every locale must expose the
same key set as en-US, keep identical {{placeholders}} (a dropped one
renders as a blank gap), leave no key empty, and leave the product and
brand name untranslated.

Built on top of Tencent#174.

Closes Tencent#168
@iAstro iAstro closed this Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extension UI falls back to Chinese for any locale other than en-US | 除 en-US 外所有语言环境下扩展界面均显示中文

1 participant