import assert from "node:assert/strict"; import { describe, it } from "node:test"; import { isSupportedLocale, resolveInitialLocale, resolveLocaleFromNavigator } from "./locales.ts"; import { messages } from "./messages.ts"; import { readStoredLocale, writeStoredLocale } from "./storage.ts"; import { defaultLocale, supportedLocales } from "./types.ts"; function flattenKeys(value: unknown, prefix = ""): string[] { if (!value || typeof value !== "object" || Array.isArray(value)) { return [prefix]; } return Object.entries(value as Record).flatMap(([key, nestedValue]) => flattenKeys(nestedValue, prefix ? `${prefix}.${key}` : key), ); } describe("i18n locale model", () => { it("supports Chinese, English, and Thai", () => { assert.deepEqual([...supportedLocales], ["zh-CN", "en-US", "th-TH"]); assert.equal(defaultLocale, "zh-CN"); }); it("accepts only supported locale codes", () => { assert.equal(isSupportedLocale("zh-CN"), true); assert.equal(isSupportedLocale("en-US"), true); assert.equal(isSupportedLocale("th-TH"), true); assert.equal(isSupportedLocale("en"), false); assert.equal(isSupportedLocale("fr-FR"), false); }); it("maps browser languages to supported locales", () => { assert.equal(resolveLocaleFromNavigator(["zh-Hans-CN"]), "zh-CN"); assert.equal(resolveLocaleFromNavigator(["en-GB"]), "en-US"); assert.equal(resolveLocaleFromNavigator(["th"]), "th-TH"); assert.equal(resolveLocaleFromNavigator(["fr-FR"]), defaultLocale); }); it("prefers stored locale over browser language", () => { assert.equal(resolveInitialLocale({ storedLocale: "th-TH", navigatorLanguages: ["en-US"] }), "th-TH"); }); it("falls back to browser language when stored locale is invalid", () => { assert.equal(resolveInitialLocale({ storedLocale: "invalid", navigatorLanguages: ["en-US"] }), "en-US"); }); it("keeps translation key structure consistent across locales", () => { const referenceKeys = flattenKeys(messages["zh-CN"]).sort(); for (const locale of supportedLocales) { assert.deepEqual(flattenKeys(messages[locale]).sort(), referenceKeys, locale); } }); it("does not throw when browser storage is unavailable", () => { const descriptor = Object.getOwnPropertyDescriptor(globalThis, "localStorage"); Object.defineProperty(globalThis, "localStorage", { configurable: true, get() { throw new Error("storage blocked"); }, }); try { assert.equal(readStoredLocale(), null); assert.doesNotThrow(() => writeStoredLocale("zh-CN")); } finally { if (descriptor) { Object.defineProperty(globalThis, "localStorage", descriptor); } else { Reflect.deleteProperty(globalThis, "localStorage"); } } }); });