/** * UI i18n unit tests (node:test). * Pure modules only — no $app / i18n.svelte.ts ($state) imports. * * Run from apps/web: * node --experimental-strip-types --test src/lib/i18n/*.test.ts */ import assert from "node:assert/strict"; import { describe, it } from "node:test"; import { DEFAULT_UI_LOCALE, UI_LOCALE_KEY, UI_LOCALES, buildUILocaleCookie, isUILocale, normalizeUILocale, persistUILocale, preferredAcceptLanguage, preferredAcceptLanguageFor, readPreferredUILocale, resolvePreferredUILocale } from "./locales.ts"; import { MESSAGE_CATALOG, isRegisteredCatalogLocale, loadAllMessages, loadMessages, messagesFor } from "./messages/catalog.ts"; import { en } from "./messages/en.ts"; import { baseMessageKeys, coverageSummary, missingKeysForLocale } from "./coverage.ts"; import { resolveMessage } from "./resolve.ts"; /** Mirrors setLocale's in-memory switch (normalize + active locale). */ function setLocale(next: string): string { return normalizeUILocale(next); } describe("setLocale / locale switching", () => { it("normalizes supported codes and rejects unknown to English", () => { assert.equal(setLocale("es"), "es"); assert.equal(setLocale("FR"), "fr"); assert.equal(setLocale(" de "), "de"); assert.equal(setLocale("xx"), DEFAULT_UI_LOCALE); assert.equal(setLocale(""), DEFAULT_UI_LOCALE); assert.equal(setLocale(null as unknown as string), DEFAULT_UI_LOCALE); }); it("isUILocale matches every UI_LOCALES entry", () => { for (const { code } of UI_LOCALES) { assert.equal(isUILocale(code), true, code); } assert.equal(isUILocale("xx"), false); }); it("switching locale changes resolved pack strings", async () => { await loadMessages("es"); const key = "common.cancel"; const enText = resolveMessage("en", key); const esText = resolveMessage(setLocale("es"), key); assert.equal(enText, en[key]); assert.notEqual(esText, enText); assert.equal(esText, messagesFor("es")[key]); }); }); describe("English fallback for missing keys", () => { it("falls back to English when the active pack omits a key", () => { const key = "common.cancel"; const english = en[key]; assert.ok(english); const missingLocale = "zz"; assert.deepEqual(messagesFor(missingLocale), {}); assert.equal(resolveMessage(missingLocale, key), english); }); it("falls back to the key itself when English also lacks it", () => { assert.equal(resolveMessage("en", "totally.missing.key"), "totally.missing.key"); assert.equal(resolveMessage("es", "totally.missing.key"), "totally.missing.key"); }); it("HTML-escapes interpolation vars", () => { const sampleKey = Object.keys(en).find((k) => en[k]?.includes("{name}")); if (!sampleKey) { assert.equal(resolveMessage("en", "totally.missing.key"), "totally.missing.key"); return; } const out = resolveMessage("en", sampleKey, { name: "" }); assert.match(out, /<script>/); assert.doesNotMatch(out, /