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([]); } });