/** * Apply English-value → locale phrase map across all packs (force update). * Phrase map: scripts/phrase-map.json { "English": { es, fr, de, it, pt, nl, pl, ja } } */ import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { SAME_AS_EN } from "./locale-extra.mjs"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const messagesDir = path.join(__dirname, "../src/lib/i18n/messages"); const locales = ["es", "fr", "de", "it", "pt", "nl", "pl", "ja"]; const mapPath = path.join(__dirname, "phrase-map.json"); function parseDict(source) { const dict = {}; const re = /"([^"\\]+)"\s*:\s*((?:"(?:\\.|[^"\\])*")|(?:`(?:\\.|[^`\\])*`))/gs; let m; while ((m = re.exec(source))) { const key = m[1]; const raw = m[2]; dict[key] = raw.startsWith("`") ? raw.slice(1, -1).replace(/\\`/g, "`").replace(/\\\$/g, "$").replace(/\\n/g, "\n") : JSON.parse(raw); } return dict; } function emitPack(exportName, comment, dict, keyOrder) { const lines = [ `import type { MessageDict } from "./types";`, ``, `/** ${comment} */`, `export const ${exportName}: MessageDict = {` ]; for (const key of keyOrder) { lines.push(`\t${JSON.stringify(key)}: ${JSON.stringify(dict[key])},`); } lines.push(`};`, ``); return lines.join("\n"); } const comments = { es: "Spanish (es) UI pack — keys must stay in sync with en.ts.", fr: "French (fr) UI pack — keys must stay in sync with en.ts.", de: "German (de) UI pack — keys must stay in sync with en.ts.", it: "Italian (it) UI pack — keys must stay in sync with en.ts.", pt: "Portuguese (pt) UI pack — keys must stay in sync with en.ts.", nl: "Dutch (nl) UI pack — keys must stay in sync with en.ts.", pl: "Polish (pl) UI pack — keys must stay in sync with en.ts.", ja: "Japanese (ja) UI pack — keys must stay in sync with en.ts." }; if (!fs.existsSync(mapPath)) { console.error("missing phrase-map.json — run fill scripts first"); process.exit(1); } const phraseMap = JSON.parse(fs.readFileSync(mapPath, "utf8")); const en = parseDict(fs.readFileSync(path.join(messagesDir, "en.ts"), "utf8")); const keyOrder = Object.keys(en); let hit = 0; let miss = 0; for (const code of locales) { const existing = parseDict(fs.readFileSync(path.join(messagesDir, `${code}.ts`), "utf8")); const dict = {}; for (const key of keyOrder) { const enVal = en[key]; const mapped = phraseMap[enVal]?.[code]; if (typeof mapped === "string" && mapped.trim()) { dict[key] = mapped; if (existing[key] === enVal || !existing[key]) hit++; } else if (typeof existing[key] === "string" && existing[key].trim()) { dict[key] = existing[key]; } else { dict[key] = enVal; if (!SAME_AS_EN.has(key)) miss++; } } fs.writeFileSync( path.join(messagesDir, `${code}.ts`), emitPack(code, comments[code], dict, keyOrder), "utf8" ); const same = keyOrder.filter((k) => dict[k] === en[k] && !SAME_AS_EN.has(k)).length; console.log(code, "keys", keyOrder.length, "sameAsEn", same); } console.log("phrase hits(approx)", hit, "pads", miss);