Update Owliver language and suggestions
This commit is contained in:
58
scripts/i18n-audit.mjs
Normal file
58
scripts/i18n-audit.mjs
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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;
|
||||
Reference in New Issue
Block a user