front/IDE官网/scripts/audit-i18n.js
zzh 70d59a0ea9 feat: 接入 IDE 官网与地区地图,并同步运营/财务/订单前端改动
新增 IDE 官网静态资源与 D3 分区域地图布局,构建时复制至 dist/site;同步应收应付、代发打包、订单详情等页面优化。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-24 19:24:05 +08:00

53 lines
1.7 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const root = path.join(__dirname, '..');
const js = fs.readFileSync(path.join(root, 'assets/js/main.js'), 'utf8');
const mapMatch = js.match(/const textMap = \{([\s\S]*?)\n \};/);
const keys = new Set();
const re = /^\s*,?'((?:\\'|[^'])*)':/gm;
let m;
while ((m = re.exec(mapMatch[1]))) {
keys.add(m[1].replace(/\\'/g, "'"));
}
const files = [];
function walk(dir) {
for (const f of fs.readdirSync(dir)) {
const p = path.join(dir, f);
if (fs.statSync(p).isDirectory()) {
if (f === 'vendor' || f === 'node_modules' || f === 'scripts') continue;
walk(p);
} else if (f.endsWith('.html')) files.push(p);
}
}
walk(root);
const missingKeys = new Set();
const missingLeaf = new Set();
for (const file of files) {
const html = fs.readFileSync(file, 'utf8');
const i18nKeys = [...html.matchAll(/data-i18n-key="([^"]+)"/g)].map((x) => x[1]);
for (const t of i18nKeys) {
if (!keys.has(t)) missingKeys.add(t);
}
const stripped = html
.replace(/<script[\s\S]*?<\/script>/gi, '')
.replace(/<style[\s\S]*?<\/style>/gi, '');
const leaf = [...stripped.matchAll(/>([^<>]{2,140})</g)]
.map((x) => x[1].replace(/\s+/g, ' ').trim())
.filter((t) => /^[A-Za-z0-9]/.test(t) && !/^\d+$/.test(t));
for (const t of new Set(leaf)) {
if (t.includes('http') || t.includes('assets/') || t.includes('©') || t.includes('@')) continue;
if (!keys.has(t) && !i18nKeys.includes(t)) missingLeaf.add(t);
}
}
console.log('=== data-i18n-key not in textMap ===');
[...missingKeys].sort().forEach((k) => console.log(k));
console.log('\n=== leaf text not in textMap (sample) ===');
[...missingLeaf].sort().slice(0, 60).forEach((k) => console.log(k));