// Catalog completeness AND a byte-exact snapshot.
//
// The completeness half is the CLJS replacement for the TS-era MsgKey type
// check: every EN key must exist in ro/hu, no stray keys, and the plural shapes
// carry the documented variants.
//
// The snapshot half is what proves the port CHANGED NO STRINGS: the catalogs
// were transliterated from the TypeScript line by line (never retyped), and
// every one of the 147 keys x 3 languages is compared against the values the
// real TS modules exported.
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 v = 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 >= 40);
assert.ok(en.some((k) => k.startsWith("social.")));
});
for (const lang of ["ro", "hu"]) {
test(`${lang} covers every EN key, and nothing else`, () => {
assert.deepEqual([...lib.catalogKeys(lang)], en);
});
}
test("the key set matches the TypeScript catalogs exactly", () => {
assert.deepEqual(en, v.keys);
for (const lang of ["en", "ro", "hu"]) {
assert.deepEqual([...lib.catalogKeys(lang)], Object.keys(v.catalogs[lang]).sort(), lang);
}
});
test("every string is byte-identical to the TypeScript original", () => {
for (const lang of ["en", "ro", "hu"]) {
const got = lib.catalogEntries(lang);
for (const [k, want] of Object.entries(v.catalogs[lang])) {
if (typeof want === "string") {
assert.equal(got[k], want, `${lang} ${k}`);
} else {
assert.deepEqual({ ...got[k] }, want, `${lang} ${k} (plural variants)`);
}
}
assert.deepEqual(Object.keys(got).sort(), Object.keys(v.catalogs[lang]).sort(), lang);
}
});
test("plural shapes: ro one/few/other, hu other-only, en one/other", () => {
for (const lang of ["en", "ro", "hu"]) {
for (const k of lib.catalogKeys(lang)) {
const got = lib.catalogMsg(lang, k);
const want = v.shapes[lang][k];
if (want === "s") assert.equal(typeof got, "string", `${lang} ${k} should be a plain string`);
else assert.deepEqual([...got], want, `${lang} ${k} variants`);
}
}
assert.deepEqual([...lib.catalogMsg("en", "hud.lines")], ["one", "other"]);
assert.deepEqual([...lib.catalogMsg("ro", "hud.lines")], ["few", "one", "other"]);
assert.deepEqual([...lib.catalogMsg("hu", "hud.lines")], ["other"]);
});
test("romanian keeps comma-below diacritics (ș ț, never ş ţ)", () => {
for (const k of lib.catalogKeys("ro")) {
const m = lib.catalogMsg("ro", k);
const strings = typeof m === "string" ? [m] : Object.values({ ...lib.catalogEntries("ro")[k] });
for (const s of strings) {
assert.ok(!s.includes("ş"), `ro ${k}: cedilla ş`);
assert.ok(!s.includes("ţ"), `ro ${k}: cedilla ţ`);
}
}
});
test("no catalog value leaks the wire protocol prefix", () => {
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("/game2/2/"), `${lang} ${k}`);
}
}
});