Files
WhispAssist/scripts/check-i18n.mjs
T

33 lines
1.5 KiB
JavaScript

// i18n key-parity check: every locale file must have exactly en.json's keys,
// and every translation must use the same {placeholders} as its English
// source. Runs as part of `npm run lint` — English fallback otherwise hides
// missing translations silently (they shipped untranslated for months once).
import { readFileSync, readdirSync } from "node:fs";
const DIR = new URL("../src/lib/i18n/", import.meta.url);
const en = JSON.parse(readFileSync(new URL("en.json", DIR), "utf8"));
const placeholders = (s) =>
[...s.matchAll(/\{(\w+)\}/g)]
.map((m) => m[1])
.sort()
.join(",");
let failed = false;
for (const file of readdirSync(DIR).filter((f) => f.endsWith(".json") && f !== "en.json")) {
const dict = JSON.parse(readFileSync(new URL(file, DIR), "utf8"));
const missing = Object.keys(en).filter((k) => !(k in dict));
const extra = Object.keys(dict).filter((k) => !(k in en));
const badVars = Object.keys(dict).filter(
(k) => k in en && placeholders(dict[k]) !== placeholders(en[k]),
);
for (const k of missing) console.error(`${file}: missing "${k}"`);
for (const k of extra) console.error(`${file}: extra "${k}" (not in en.json)`);
for (const k of badVars) console.error(`${file}: "${k}" placeholders differ from en.json`);
if (missing.length || extra.length || badVars.length) failed = true;
}
if (failed) {
console.error("\ni18n parity check FAILED — keep every locale in lockstep with en.json.");
process.exit(1);
}
console.log("i18n parity OK");