Files
web-Iot/tmp_verify_i18n.cjs
2026-08-14 09:02:52 +08:00

75 lines
2.0 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const ts = require('typescript');
function transpile(file) {
const code = fs.readFileSync(file, 'utf8');
const out = ts.transpileModule(code, {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2019 },
});
return out.outputText;
}
function load(file) {
const out = transpile(file);
const module = { exports: {} };
const fn = new Function('module', 'exports', out);
fn(module, module.exports);
return module.exports.default || module.exports;
}
function flatten(obj, prefix = '') {
const keys = new Set();
for (const k of Object.keys(obj)) {
const v = obj[k];
const p = prefix ? prefix + '.' + k : k;
if (v && typeof v === 'object' && !Array.isArray(v)) {
for (const sk of flatten(v, p)) keys.add(sk);
} else {
keys.add(p);
}
}
return keys;
}
const zhKeys = flatten(load('src/locales/zh/index.ts'));
const enKeys = flatten(load('src/locales/en/index.ts'));
console.log('zh keys:', zhKeys.size, 'en keys:', enKeys.size);
const dir = 'src';
const exts = ['.tsx', '.ts', '.jsx', '.js'];
function walk(d) {
let r = [];
for (const f of fs.readdirSync(d)) {
const p = path.join(d, f);
if (fs.statSync(p).isDirectory()) {
r = r.concat(walk(p));
} else if (exts.some((e) => f.endsWith(e)) && !p.includes('locales')) {
r.push(p);
}
}
return r;
}
const used = new Set();
const fileKey = {};
for (const f of walk(dir)) {
const code = fs.readFileSync(f, 'utf8');
const re = /(?:[^.\w]|^)(?:t|i18n\.t)\(\s*['"]([a-zA-Z0-9_.-]+)['"]/g;
let m;
while ((m = re.exec(code)) !== null) {
const k = m[1];
used.add(k);
(fileKey[k] = fileKey[k] || new Set()).add(f);
}
}
console.log('Total distinct keys used in source:', used.size);
const missing = [...used].filter((k) => !zhKeys.has(k) || !enKeys.has(k));
console.log('Keys used but missing in locale files:', missing.length);
for (const k of missing.sort()) {
console.log(' ' + k + ' <- ' + [...(fileKey[k] || [])].join(', '));
}
// Also detect literal raw t('...') keys that might be dynamic (skip)