test+refactor(i18n): close code-review residuals

- Extract a shared normalizeToSupportedLocale helper in @fusion/i18n used by
  both the CLI env detection and the dashboard navigator detection
  (convertDetectedLanguage), fixing multi-subtag navigator tags (zh-Hans-CN)
  and unifying Chinese script resolution.
- Add a cross-tab storage listener to useLanguage so a language change in one
  tab propagates to others.
- Dedup the namespace lists into packages/i18n/namespaces.json, consumed by
  config.ts and all three build scripts (no more 3-way drift risk).
- Add tests: dashboard i18n/index.ts (document.lang mirror, init non-blocking),
  useLanguage concurrent-hydration race + cross-tab adoption,
  normalizeToSupportedLocale, namespace-source consistency.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-06-03 09:03:16 -07:00
parent f707b62155
commit 4f6013ff3a
12 changed files with 180 additions and 41 deletions

View File

@@ -4,6 +4,7 @@ import {
CLI_NAMESPACES,
cliResources,
DEFAULT_NAMESPACE,
normalizeToSupportedLocale,
} from "@fusion/i18n";
import i18next, { type i18n as I18nInstance, type Resource } from "i18next";
import { initReactI18next } from "react-i18next";
@@ -24,30 +25,10 @@ import { initReactI18next } from "react-i18next";
export function detectEnvLocale(env: NodeJS.ProcessEnv = process.env): Locale | undefined {
const raw = env.LC_ALL || env.LC_MESSAGES || env.LANG || env.LANGUAGE;
if (!raw) return undefined;
// Strip encoding/modifier (`.UTF-8`, `@euro`) and normalize `_` to `-`.
const code = raw.split(/[.:@\s]/)[0].replaceAll("_", "-");
if (isLocale(code)) return code;
const lower = code.toLowerCase();
// Script/region-aware Chinese resolution BEFORE the bare-language fallback,
// so Traditional-script tags (zh_Hant, zh_Hant_TW, zh_HK, zh_MO) are not
// silently served Simplified. Region-only zh_CN/zh_TW already matched above.
if (lower.startsWith("zh")) {
if (
lower.includes("hant") ||
lower.includes("-tw") ||
lower.includes("-hk") ||
lower.includes("-mo")
) {
return "zh-TW";
}
return "zh-CN";
}
const lang = lower.split("-")[0];
if (isLocale(lang)) return lang;
return undefined;
// Strip encoding/modifier (`.UTF-8`, `@euro`), then normalize via the shared
// helper so env detection matches the dashboard's navigator detection
// (incl. Traditional-script Chinese → zh-TW).
return normalizeToSupportedLocale(raw.split(/[.:@\s]/)[0]);
}
/**