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

81 lines
2.8 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const root = 'src';
const exts = ['.tsx', '.ts', '.jsx', '.js'];
const excludeDirs = ['locales', 'node_modules'];
const cjk = /[\u4e00-\u9fff]/;
function walk(dir) {
const out = [];
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
if (excludeDirs.includes(entry.name)) continue;
out.push(...walk(full));
} else if (exts.includes(path.extname(entry.name))) {
out.push(full);
}
}
return out;
}
// Load locale keys (flattened)
function load(localePath) {
let src = fs.readFileSync(localePath, 'utf8');
src = src.replace(/const\s+\w+\s*=\s*\{/, 'var obj = {');
src = src.replace(/export\s+default\s+\w+;?/, '');
src = src.replace(/\bconst\b/g, 'var');
return new Function(src + '\nreturn obj;')();
}
function flatten(obj, prefix = '', res = {}) {
for (const k of Object.keys(obj)) {
const key = prefix ? prefix + '.' + k : k;
if (obj[k] && typeof obj[k] === 'object' && !Array.isArray(obj[k])) flatten(obj[k], key, res);
else res[key] = obj[k];
}
return res;
}
const zhF = flatten(load('src/locales/zh/index.ts'));
const enF = flatten(load('src/locales/en/index.ts'));
// 1) Find all t('...') / i18n.t('...') referenced keys
const files = walk(root);
const refKeys = new Set();
const refRegex = /(?:i18n\.t|[^a-zA-Z]t)\(\s*['"`]([a-zA-Z][a-zA-Z0-9_.]*?)['"`]/g;
for (const f of files) {
const content = fs.readFileSync(f, 'utf8');
let m;
while ((m = refRegex.exec(content))) {
refKeys.add(m[1]);
}
}
const refArr = [...refKeys].sort();
const missingInZh = refArr.filter(k => !(k in zhF));
const missingInEn = refArr.filter(k => !(k in enF));
console.log('=== t() referenced keys missing in ZH (' + missingInZh.length + ') ===');
console.log(missingInZh.join('\n'));
console.log('\n=== t() referenced keys missing in EN (' + missingInEn.length + ') ===');
console.log(missingInEn.join('\n'));
console.log('\nTotal referenced keys:', refArr.length);
// 2) Find user-facing hardcoded Chinese strings.
// Exclude lines that are only comments or console.* (developer-facing).
const userHits = [];
for (const f of files) {
const lines = fs.readFileSync(f, 'utf8').split('\n');
lines.forEach((line, i) => {
const t = line.trim();
if (!cjk.test(line)) return;
if (t.startsWith('//') || t.startsWith('*') || t.startsWith('/*')) return;
if (/^\{\/\*/.test(t)) return; // {/* ... */}
// exclude console.* (browser console only)
if (/\bconsole\.(log|error|warn|info|debug)\s*\(/.test(line)) return;
userHits.push({ file: f, line: i + 1, text: t.slice(0, 220) });
});
}
console.log('\n=== USER-FACING hardcoded CJK lines (' + userHits.length + ') ===');
for (const h of userHits) {
console.log(h.file + ':' + h.line + ' | ' + h.text);
}