Files

255 lines
5.3 KiB
JavaScript
Raw Permalink Normal View History

/**
* Count keys identical to English across locale packs.
* Brands/loanwords/symbols are excluded from the "unfinished" total.
*
* Run: node apps/web/scripts/count-identical-to-en.mjs
* Optional: --json writes apps/web/scripts/_identical-to-en-report.json
*/
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 LOCALES = ["es", "fr", "de", "it", "pt", "nl", "pl", "ja"];
const BRAND_VALUES = new Set([
" · upgrade",
" (v{version})",
"—",
".",
"…",
"· upgrade",
"(v{version})",
"{count} file",
"{count} options",
"{credits} credits",
"{used} / {max} SKUs",
"→",
"Account",
"Action",
"Actions",
"Admin",
"AI",
"Alias",
"Allowlist",
"Analytics",
"API",
"Assistant",
"Audience",
"Azure OpenAI",
"Base",
"Black Friday 2026",
"Business",
"Client ID",
"cm",
"colleague@example.com",
"Commerce",
"Compliance",
"CSV",
"Date",
"Description",
"Descrybe",
"Dimension",
"Directory",
"Docs:",
"EAN/GTIN",
"Enterprise",
"EPREL",
"EPREL ID",
"EUR",
"Exact",
"Exports",
"FAQ auto-match",
"Feeds",
"Format",
"Format:",
"format: csv",
"Fuzzy",
"Google OAuth",
"GPS",
"Growth",
"Host",
"https://…",
"IA",
"ID",
"Insight",
"Integration",
"item: {path}",
"Job {id}",
"kg",
"Knowledge",
"Knowledge base",
"Last Updated",
"Legacy",
"Live",
"Mail",
"Mapping",
"Marketing",
"Material",
"Media",
"Model",
"Name (A-Z)",
"Name (Z-A)",
"Namespace",
"No",
"Normalize",
"Notes",
"OAuth, EPREL, Pinecone, Stripe, feeds",
"OK",
"Ollama",
"OpenAI",
"OpenAPI",
"OpenRouter",
"Ops",
"Optional",
"Parent",
"pcs",
"Pinecone",
"Plan:",
"Popular",
"Product",
"Prompt",
"Re: {subject}",
"REST",
"Reviewer",
"reviews",
"Reviews: {status}",
"SEO",
"Service",
"Shopify",
"Single",
"SKU",
"Source",
"source {source}",
"Staff",
"Starter",
"Stripe",
"Sync: {status}",
"Tenant vs platform",
"Tenants · volume",
"Test: {status}",
"Ticket",
"Tickets",
"Timeout",
"TSV",
"Type",
"Uploads",
"URL",
"via Stripe",
"Volume",
"W",
"WooCommerce",
"you@company.com",
]);
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 isBrandOrLoanword(value) {
const raw = String(value ?? "");
const t = raw.trim();
if (!t) return true;
if (BRAND_VALUES.has(raw) || BRAND_VALUES.has(t)) return true;
if (/^\{[^}]+\}$/.test(t)) return true;
// Short all-caps / code-like tokens kept identical by policy
if (/^[A-Z0-9][A-Z0-9._/-]{0,14}$/.test(t) && t === t.toUpperCase()) return true;
return false;
}
function load(code) {
return parseMessageDict(fs.readFileSync(path.join(messagesDir, `${code}.ts`), "utf8"));
}
const en = load("en");
const enKeys = Object.keys(en);
const byLocale = {};
let totalIdentical = 0;
let totalIdenticalExBrand = 0;
let totalTranslated = 0;
let totalBrandIdentical = 0;
for (const code of LOCALES) {
const pack = load(code);
let identical = 0;
let identicalExBrand = 0;
let brandIdentical = 0;
let translated = 0;
let missing = 0;
const unfinishedSamples = [];
for (const key of enKeys) {
if (!(key in pack)) {
missing += 1;
identicalExBrand += 1;
if (unfinishedSamples.length < 8) unfinishedSamples.push(key);
continue;
}
if (pack[key] === en[key]) {
identical += 1;
if (isBrandOrLoanword(en[key])) {
brandIdentical += 1;
} else {
identicalExBrand += 1;
if (unfinishedSamples.length < 8) unfinishedSamples.push(`${key}=${JSON.stringify(en[key])}`);
}
} else {
translated += 1;
}
}
byLocale[code] = {
keys: Object.keys(pack).length,
identical,
identicalExBrand,
brandIdentical,
translated,
missing,
unfinishedSamples,
};
totalIdentical += identical;
totalIdenticalExBrand += identicalExBrand;
totalBrandIdentical += brandIdentical;
totalTranslated += translated;
console.log(
`${code}: identical=${identical} identicalExBrand=${identicalExBrand} brandIdentical=${brandIdentical} translated=${translated} missing=${missing}`,
);
}
const report = {
enKeys: enKeys.length,
locales: LOCALES,
byLocale,
totals: {
identical: totalIdentical,
identicalExBrand: totalIdenticalExBrand,
brandIdentical: totalBrandIdentical,
translated: totalTranslated,
avgIdenticalExBrandPerLocale: Math.round(totalIdenticalExBrand / LOCALES.length),
},
measuredAt: new Date().toISOString(),
};
console.log("---");
console.log(`enKeys=${report.enKeys}`);
console.log(`TOTAL identical=${totalIdentical}`);
console.log(`TOTAL identicalExBrand (excl brands)=${totalIdenticalExBrand}`);
console.log(`AVG identicalExBrand/locale=${report.totals.avgIdenticalExBrandPerLocale}`);
console.log(`TOTAL brandIdentical=${totalBrandIdentical}`);
console.log(`TOTAL translated=${totalTranslated}`);
if (process.argv.includes("--json")) {
const out = path.join(__dirname, "_identical-to-en-report.json");
fs.writeFileSync(out, JSON.stringify(report, null, 2), "utf8");
console.log(`wrote ${out}`);
}