From 2b6ea1b4a4d9b1964c58f68ae60027873e28d4d5 Mon Sep 17 00:00:00 2001 From: Anders Olsson Date: Mon, 8 Jun 2026 09:15:35 +0200 Subject: [PATCH] test(web): enforce en/sv i18n key parity + non-empty values (#60) --- web/src/i18n/parity.test.ts | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 web/src/i18n/parity.test.ts diff --git a/web/src/i18n/parity.test.ts b/web/src/i18n/parity.test.ts new file mode 100644 index 0000000..fba3e25 --- /dev/null +++ b/web/src/i18n/parity.test.ts @@ -0,0 +1,46 @@ +import { expect, test } from "vitest"; + +import en from "./en.json"; +import sv from "./sv.json"; + +// Flatten a nested translation object into a map of dotted leaf keys → string +// values, e.g. { objects: { columns: { number: "…" } } } → "objects.columns.number". +function flatten(obj: Record, prefix = ""): Map { + const out = new Map(); + + for (const [key, value] of Object.entries(obj)) { + const path = prefix ? `${prefix}.${key}` : key; + + if (value !== null && typeof value === "object" && !Array.isArray(value)) { + for (const [childPath, childValue] of flatten(value as Record, path)) { + out.set(childPath, childValue); + } + } else { + out.set(path, value); + } + } + + return out; +} + +const enFlat = flatten(en as Record); +const svFlat = flatten(sv as Record); + +test("en and sv have identical translation key sets", () => { + const missingInSv = [...enFlat.keys()].filter((k) => !svFlat.has(k)).sort(); + const missingInEn = [...svFlat.keys()].filter((k) => !enFlat.has(k)).sort(); + + expect(missingInSv, `keys present in en.json but missing from sv.json:\n${missingInSv.join("\n")}`).toEqual([]); + expect(missingInEn, `keys present in sv.json but missing from en.json:\n${missingInEn.join("\n")}`).toEqual([]); +}); + +test("every translation value is a non-empty string in both locales", () => { + for (const [name, flat] of [["en", enFlat], ["sv", svFlat]] as const) { + const bad = [...flat.entries()] + .filter(([, v]) => typeof v !== "string" || v.trim() === "") + .map(([k]) => k) + .sort(); + + expect(bad, `${name}.json has empty or non-string values at:\n${bad.join("\n")}`).toEqual([]); + } +});