59 lines
2.4 KiB
JavaScript
59 lines
2.4 KiB
JavaScript
/**
|
|
* Every t('key') in the source, checked against the catalogues.
|
|
*
|
|
* A key the code calls and the catalogue lacks renders as humanised English at
|
|
* best, so this is the check that says the extraction is actually complete.
|
|
* The reverse — a catalogue entry nothing calls — is only waste, and reported
|
|
* separately.
|
|
*/
|
|
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
|
|
const walk = (dir, acc = []) => {
|
|
for (const e of readdirSync(dir)) {
|
|
if (e === 'node_modules' || e.startsWith('.')) continue;
|
|
const p = join(dir, e);
|
|
if (statSync(p).isDirectory()) walk(p, acc);
|
|
else if (/\.(tsx|ts|jsx|js)$/.test(p)) acc.push(p);
|
|
}
|
|
return acc;
|
|
};
|
|
|
|
const flat = (obj, prefix = '', out = {}) => {
|
|
for (const [k, v] of Object.entries(obj)) {
|
|
const key = prefix ? `${prefix}.${k}` : k;
|
|
if (v && typeof v === 'object') flat(v, key, out);
|
|
else out[key] = v;
|
|
}
|
|
return out;
|
|
};
|
|
|
|
const en = flat(JSON.parse(readFileSync('src/lib/i18n/locales/en.json', 'utf8')));
|
|
const es = flat(JSON.parse(readFileSync('src/lib/i18n/locales/es.json', 'utf8')));
|
|
|
|
const used = new Set();
|
|
const dynamic = [];
|
|
for (const file of walk('src')) {
|
|
const src = readFileSync(file, 'utf8');
|
|
for (const m of src.matchAll(/\bt\(\s*'([^']+)'/g)) used.add(m[1]);
|
|
for (const m of src.matchAll(/\bt\(\s*`([^`]+)`/g)) dynamic.push(`${file}: ${m[1]}`);
|
|
}
|
|
|
|
/* A plural key is stored as name_one / name_other, so the base name is never
|
|
itself in the catalogue and is not missing. */
|
|
const present = (k) => k in en || `${k}_other` in en || `${k}_one` in en;
|
|
|
|
const missingEn = [...used].filter((k) => !present(k)).sort();
|
|
const missingEs = [...used].filter((k) => present(k) && !(k in es || `${k}_other` in es)).sort();
|
|
const unused = Object.keys(en).filter((k) => !used.has(k) && !used.has(k.replace(/_(one|other)$/, ''))).sort();
|
|
|
|
console.log(`\n t() calls with a literal key : ${used.size}`);
|
|
console.log(` built from a template : ${dynamic.length} (checked by hand)`);
|
|
console.log(` MISSING from en.json : ${missingEn.length}`);
|
|
console.log(` MISSING from es.json : ${missingEs.length}`);
|
|
console.log(` in en.json, never called : ${unused.length}`);
|
|
|
|
for (const k of missingEn.slice(0, 15)) console.log(` missing en: ${k}`);
|
|
for (const k of missingEs.slice(0, 10)) console.log(` missing es: ${k}`);
|
|
if (missingEn.length) process.exitCode = 1;
|