Skip to content

fix(i18n): match browser locale by language subtag instead of exact code - #174

Open
iAstro wants to merge 1 commit into
Tencent:mainfrom
iAstro:fix/extension-locale-normalization
Open

fix(i18n): match browser locale by language subtag instead of exact code#174
iAstro wants to merge 1 commit into
Tencent:mainfrom
iAstro:fix/extension-locale-normalization

Conversation

@iAstro

@iAstro iAstro commented Sep 2, 2026

Copy link
Copy Markdown

Problem

The extension ships en-US and zh-CN, 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 a Chinese UI.

Fix

Match on the BCP 47 language subtag instead of the full locale code:

  • en* -> en-US (every English variant)
  • zh-Hans* / zh-CN / zh-SG / zh -> zh-CN
  • zh-Hant* / zh-TW / zh-HK / zh-MO -> zh-TW
  • anything else -> unchanged, resolved by fallbackLng

Three layers, all in packages/i18n:

  1. Custom detector preferring chrome.i18n.getUILanguage() over navigator.language, which is unreliable on the chrome-extension:// origin the popup runs on.
  2. convertDetectedLanguage applying the table above.
  3. fallbackLng is now an object: { en: ["en-US"], zh: ["zh-CN"], default: ["en-US"] } - unmatched languages land on English, not Chinese.

Simplified vs Traditional

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 - only a new zh-TW resource. Until then i18next falls back to zh-CN (graceful degradation, not a misroute).

Tests

Adds packages/i18n/tests/locale-resolution.test.ts (28 cases) locking the table in as regression tests; the package previously had no tests.

28/28 tests pass; tsc --noEmit, biome check, and pnpm ext:build are all clean.

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
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