Files
descrybe/apps/web/scripts/sync-i18n-from-en.mjs
T
greeneclipse 8580c996c3 Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
2026-08-09 22:47:43 +02:00

81 lines
2.3 KiB
JavaScript

import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const messagesDir = path.join(__dirname, "..", "src", "lib", "i18n", "messages");
const locales = ["de", "es", "fr", "it", "ja", "nl", "pl", "pt"];
const names = {
de: "German (de)",
es: "Spanish (es)",
fr: "French (fr)",
it: "Italian (it)",
ja: "Japanese (ja)",
nl: "Dutch (nl)",
pl: "Polish (pl)",
pt: "Portuguese (pt)"
};
/** Parse flat `"key": "value",` MessageDict bodies (JSON-string keys/values). */
function parseMessageDict(source) {
const start = source.indexOf("{");
const end = source.lastIndexOf("}");
if (start < 0 || end <= start) {
throw new Error("MessageDict object braces not found");
}
const body = source.slice(start, end + 1);
// Keys/values are JSON strings in this repo's packs.
const out = {};
const re = /("(?:\\.|[^"\\])*")\s*:\s*("(?:\\.|[^"\\])*")\s*,?/g;
let m;
while ((m = re.exec(body)) !== null) {
out[JSON.parse(m[1])] = JSON.parse(m[2]);
}
return out;
}
function writePack(code, dict, enKeys) {
const lines = [
'import type { MessageDict } from "./types";',
"",
`/** ${names[code]} UI pack — keys must stay in sync with en.ts. */`,
`export const ${code}: MessageDict = {`
];
for (const k of enKeys) {
lines.push(`\t${JSON.stringify(k)}: ${JSON.stringify(dict[k])},`);
}
lines.push("};", "");
fs.writeFileSync(path.join(messagesDir, `${code}.ts`), lines.join("\n"), "utf8");
}
const enSource = fs.readFileSync(path.join(messagesDir, "en.ts"), "utf8");
const en = parseMessageDict(enSource);
const enKeys = Object.keys(en);
let totalFilled = 0;
let totalRemoved = 0;
for (const code of locales) {
const filePath = path.join(messagesDir, `${code}.ts`);
const pack = parseMessageDict(fs.readFileSync(filePath, "utf8"));
const extras = Object.keys(pack).filter((k) => !(k in en));
const next = {};
let filled = 0;
for (const k of enKeys) {
const cur = pack[k];
if (cur == null || !String(cur).trim()) {
next[k] = en[k];
filled += 1;
} else {
next[k] = cur;
}
}
totalFilled += filled;
totalRemoved += extras.length;
writePack(code, next, enKeys);
console.log(`${code}: filled=${filled} removed_extra=${extras.length} keys=${enKeys.length}`);
}
console.log(`DONE filled_total=${totalFilled} removed_total=${totalRemoved}`);