/**
* 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, /