import { test } from "node:test"; import assert from "node:assert/strict"; import { createLocalizer, createLanguageController, overlayPack, fetchPack } from "./runtime.mjs"; const pack = locale => ({ version: 1, locale, ruleVersion: "cldr-46.1", pluralRules: { en: { one: "i = 1 and v = 0" }, fr: { one: "i = 0,1" }, de: { one: "i = 1 and v = 0" } }, config: { sourceLocale: "en", defaultLocale: "en", locales: ["en", "fr", "de"] }, documents: [ { version: 1, locale: "en", namespace: "ui", messages: { title: { value: { text: "English" } }, greet: { params: { name: "string" }, value: { text: "Hello {name}" } } } }, ... (locale === "en" ? [] : [{ version: 1, locale, namespace: "ui", messages: { title: { value: { text: locale } } } }]) ] }); test("detached resources, explicit overrides, text arguments and fallback", () => { const data = pack("fr"), localizer = createLocalizer(data); data.documents[0].messages.greet.value.text = "changed"; assert.equal(localizer.t("ui", "greet", { name: "{name}" }), "Hello {name}"); assert.equal(localizer.render("ui", "greet", { name: "x" }).locale, "en"); const original = pack("en"); const overridden = overlayPack(original, [{ version: 1, namespace: "ui", locale: "en", messages: { title: { value: { text: "Custom" } } } }]); assert.equal(createLocalizer(overridden).t("ui", "title"), "Custom"); assert.equal(createLocalizer(original).t("ui", "title"), "English"); assert.throws(() => overlayPack(original, [{ version: 1, namespace: "ui", locale: "en", messages: { unknown: { value: {} } } }])); }); test("latest selection wins and failures preserve committed state", async () => { const pending = new Map(); const controller = createLanguageController(pack("en"), locale => new Promise((resolve, reject) => pending.set(locale, { resolve, reject }))); const french = controller.setLanguage("fr"), german = controller.setLanguage("de"); pending.get("de").resolve(pack("de")); assert.equal(await german, true); pending.get("fr").resolve(pack("fr")); assert.equal(await french, false); assert.equal(controller.current.locale, "de"); const failed = controller.setLanguage("fr"); pending.get("fr").reject(Error("offline")); await assert.rejects(failed); assert.equal(controller.current.locale, "de"); const stale = controller.setLanguage("fr"); await controller.setLanguage("de"); pending.get("fr").reject(Error("stale failure")); assert.equal(await stale, false); assert.equal(controller.current.t("ui", "title"), "de"); }); test("bad packs cannot commit or change enabled languages/schemas", async () => { const controller = createLanguageController(pack("en"), async () => { const data = pack("fr"); delete data.documents[0].messages.greet; return data; }); await assert.rejects(controller.setLanguage("fr")); assert.equal(controller.current.locale, "en"); await assert.rejects(controller.setLanguage("zz")); const cycle = pack("en"); cycle.config.fallbacks = { en: ["fr"], fr: ["en"] }; assert.throws(() => createLocalizer(cycle)); const duplicate = pack("en"); duplicate.documents.push(duplicate.documents[0]); assert.throws(() => createLocalizer(duplicate)); }); test("bounded fetching and validation before switching", async () => { const data = await fetchPack("/en.json", { fetch: async () => new Response(JSON.stringify(pack("en"))) }); assert.equal(createLocalizer(data).locale, "en"); await assert.rejects(fetchPack("/bad", { fetch: async () => new Response("bad", { status: 500 }) })); await assert.rejects(fetchPack("/bad", { fetch: async () => new Response("bad") })); await assert.rejects(fetchPack("/huge", { fetch: async () => new Response(new Uint8Array(4194305)) })); });