// Catalog fidelity — the CLJS replacement for the TS-era MsgKey type check.
// Two gates: every EN key exists in ro/hu with nothing stray (a missing
// translation fails the suite), and every message VALUE is byte-equal to the TS
// catalogs' snapshot in vectors/i18n.json (so the port never quietly reworded a
// string). The catalogs were transliterated mechanically, never retyped.
import test from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import * as lib from "../test-dist/testlib.js";
const ts = JSON.parse(readFileSync(new URL("./vectors/i18n.json", import.meta.url), "utf8"));
const en = [...lib.catalogKeys("en")];
test("EN catalog is non-empty and carries the social.* block", () => {
assert.ok(en.length >= 80);
assert.ok(en.some((k) => k.startsWith("social.")));
assert.ok(en.includes("room.study") && en.includes("room.parlour") && en.includes("room.cellar"));
});
for (const lang of ["ro", "hu"]) {
test(`${lang} covers every EN key, and nothing else`, () => {
assert.deepEqual([...lib.catalogKeys(lang)], en);
});
}
for (const lang of ["en", "ro", "hu"]) {
test(`${lang} messages are byte-identical to the TS catalog`, () => {
assert.deepEqual([...lib.catalogKeys(lang)], Object.keys(ts[lang]).sort(), `${lang} key set`);
for (const k of Object.keys(ts[lang])) {
const got = lib.catalogMsg(lang, k);
const want = ts[lang][k];
if (typeof want === "string") {
assert.equal(got, want, `${lang} ${k}`);
} else {
// a plural site: compare the variant map, categories included
assert.deepEqual(JSON.parse(JSON.stringify(got)), want, `${lang} ${k}`);
}
}
});
}
test("plural sites: ro one/few/other, hu other-only, en one/other", () => {
const cats = (lang, k) => Object.keys(JSON.parse(JSON.stringify(lib.catalogMsg(lang, k)))).sort();
for (const k of ["status.linked", "reveal.cold", "over.you.sub", "over.solo.sub"]) {
assert.deepEqual(cats("en", k), ["one", "other"], `en ${k}`);
assert.deepEqual(cats("ro", k), ["few", "one", "other"], `ro ${k}`);
assert.deepEqual(cats("hu", k), ["other"], `hu ${k}`);
}
});
test("the room names the game renders exist in every catalog", () => {
for (const lang of ["en", "ro", "hu"]) {
for (const k of ["room.study", "room.parlour", "room.cellar"]) {
assert.equal(typeof lib.catalogMsg(lang, k), "string", `${lang} ${k}`);
assert.ok(lib.catalogMsg(lang, k).length > 0);
}
}
});
test("wire-adjacent strings are never translated (brand + protocol)", () => {
for (const lang of ["en", "ro", "hu"]) {
for (const k of lib.catalogKeys(lang)) {
const m = lib.catalogMsg(lang, k);
if (typeof m === "string") assert.ok(!m.includes("/seance/"), `${lang} ${k}`);
}
}
});