Guard language switching failures (#1002)

This commit is contained in:
ZacharyZcR
2026-07-10 08:01:48 +08:00
committed by GitHub
parent 57effd2405
commit d908d9dc57
6 changed files with 80 additions and 37 deletions
+21
View File
@@ -0,0 +1,21 @@
import { describe, expect, it, beforeEach } from "vitest";
import { changeAppLanguage, normalizeLanguageCode } from "./i18n";
describe("i18n language handling", () => {
beforeEach(() => {
localStorage.clear();
});
it("normalizes persisted desktop language codes", () => {
expect(normalizeLanguageCode("zh_CN")).toBe("zh-CN");
expect(normalizeLanguageCode("pt_br")).toBe("pt-BR");
expect(normalizeLanguageCode("EN-us")).toBe("en");
expect(normalizeLanguageCode("unknown")).toBe("en");
});
it("stores the normalized language after a successful switch", async () => {
await expect(changeAppLanguage("zh_CN")).resolves.toBe("zh-CN");
expect(localStorage.getItem("i18nextLng")).toBe("zh-CN");
});
});
+29 -10
View File
@@ -43,31 +43,43 @@ const localeLoaders = {
"zh-TW": () => import("../locales/translated/zh_TW.json"),
} satisfies Record<string, () => Promise<LocaleModule>>;
const supportedLngs = ["en", ...Object.keys(localeLoaders)];
export const supportedLngs = ["en", ...Object.keys(localeLoaders)];
export function normalizeLanguageCode(language?: string | null): string {
if (!language) return "en";
const normalized = language.replaceAll("_", "-");
if (supportedLngs.includes(normalized)) return normalized;
const exactMatch = supportedLngs.find(
(supported) => supported.toLowerCase() === normalized.toLowerCase(),
);
if (exactMatch) return exactMatch;
const baseLanguage = normalized.split("-")[0];
return supportedLngs.includes(baseLanguage) ? baseLanguage : "en";
}
const localeBackend: BackendModule = {
type: "backend",
init: () => {},
read: (language, _namespace, callback) => {
if (language === "en") {
const normalizedLanguage = normalizeLanguageCode(language);
if (normalizedLanguage === "en") {
callback(null, enTranslation);
return;
}
const loadLocale = localeLoaders[language];
const loadLocale = localeLoaders[normalizedLanguage];
if (!loadLocale) {
callback(new Error(`Unsupported language: ${language}`), false);
callback(null, enTranslation);
return;
}
loadLocale()
.then((module) => callback(null, module.default))
.catch((error: unknown) => {
callback(
error instanceof Error ? error : new Error(String(error)),
false,
);
});
.catch(() => callback(null, enTranslation));
},
};
@@ -104,4 +116,11 @@ i18n
},
});
export async function changeAppLanguage(language: string): Promise<string> {
const normalizedLanguage = normalizeLanguageCode(language);
await i18n.changeLanguage(normalizedLanguage);
localStorage.setItem("i18nextLng", normalizedLanguage);
return normalizedLanguage;
}
export default i18n;