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.
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* MERGE-preserve recovery: fill locale values that still equal English
|
||||
* from phrase-map.json. Never overwrite a value that already differs from en.
|
||||
*
|
||||
* Run: node apps/web/scripts/merge-preserve-packs.mjs
|
||||
*/
|
||||
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.resolve(__dirname, "../src/lib/i18n/messages");
|
||||
const mapPath = path.join(__dirname, "phrase-map.json");
|
||||
const LOCALES = ["es", "fr", "de", "it", "pt", "nl", "pl", "ja"];
|
||||
|
||||
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.",
|
||||
};
|
||||
|
||||
function parseMessageDict(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");
|
||||
}
|
||||
|
||||
function load(code) {
|
||||
return parseMessageDict(fs.readFileSync(path.join(messagesDir, `${code}.ts`), "utf8"));
|
||||
}
|
||||
|
||||
if (!fs.existsSync(mapPath)) {
|
||||
console.error(`missing phrase-map: ${mapPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const phraseMap = JSON.parse(fs.readFileSync(mapPath, "utf8"));
|
||||
const en = load("en");
|
||||
const keyOrder = Object.keys(en);
|
||||
|
||||
let totalApplied = 0;
|
||||
let totalSkippedGood = 0;
|
||||
let totalNoMap = 0;
|
||||
const byLocale = {};
|
||||
|
||||
for (const code of LOCALES) {
|
||||
const pack = load(code);
|
||||
const next = { ...pack };
|
||||
let applied = 0;
|
||||
let skippedGood = 0;
|
||||
let noMap = 0;
|
||||
let missingKeys = 0;
|
||||
|
||||
for (const key of keyOrder) {
|
||||
const enVal = en[key];
|
||||
const cur = next[key];
|
||||
|
||||
if (typeof cur === "string" && cur !== enVal) {
|
||||
skippedGood += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Identical to EN (or missing) — try phrase-map by English string
|
||||
const mapped = phraseMap[enVal];
|
||||
const tr = mapped && typeof mapped[code] === "string" ? mapped[code].trim() : "";
|
||||
if (tr && tr !== enVal) {
|
||||
next[key] = mapped[code];
|
||||
applied += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(key in next)) {
|
||||
next[key] = enVal;
|
||||
missingKeys += 1;
|
||||
}
|
||||
noMap += 1;
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(messagesDir, `${code}.ts`),
|
||||
emitPack(code, comments[code], next, keyOrder),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
byLocale[code] = { applied, skippedGood, noMap, missingKeys };
|
||||
totalApplied += applied;
|
||||
totalSkippedGood += skippedGood;
|
||||
totalNoMap += noMap;
|
||||
console.log(
|
||||
`${code}: applied=${applied} skippedGood=${skippedGood} noMap=${noMap} missingKeys=${missingKeys}`,
|
||||
);
|
||||
}
|
||||
|
||||
console.log("---");
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
{
|
||||
phraseMapEntries: Object.keys(phraseMap).length,
|
||||
enKeys: keyOrder.length,
|
||||
totalApplied,
|
||||
totalSkippedGood,
|
||||
totalNoMap,
|
||||
byLocale,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
Reference in New Issue
Block a user