mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 23:23:55 +08:00
Merge pull request #3274 from xinnan-tech/i18n-duplicate-check
test: 增加 i18n 重复 key 检测
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"check:i18n": "node scripts/check-i18n.js",
|
||||
"build": "vue-cli-service build",
|
||||
"analyze": "cross-env ANALYZE=true vue-cli-service build"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const rootDir = path.resolve(__dirname, '..');
|
||||
const locales = [
|
||||
{ name: 'zh_CN', file: 'src/i18n/zh_CN.js' },
|
||||
{ name: 'zh_TW', file: 'src/i18n/zh_TW.js' },
|
||||
{ name: 'en', file: 'src/i18n/en.js' },
|
||||
{ name: 'de', file: 'src/i18n/de.js' },
|
||||
{ name: 'vi', file: 'src/i18n/vi.js' },
|
||||
{ name: 'pt_BR', file: 'src/i18n/pt_BR.js' },
|
||||
];
|
||||
|
||||
function readLocale(locale) {
|
||||
const filePath = path.join(rootDir, locale.file);
|
||||
const lines = fs.readFileSync(filePath, 'utf8').split(/\r?\n/);
|
||||
const keys = [];
|
||||
const seen = new Map();
|
||||
const duplicates = [];
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
const match = line.match(/^\s*['"]([^'"]+)['"]\s*:/);
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
|
||||
const key = match[1];
|
||||
keys.push(key);
|
||||
if (!seen.has(key)) {
|
||||
seen.set(key, []);
|
||||
}
|
||||
seen.get(key).push(index + 1);
|
||||
});
|
||||
|
||||
seen.forEach((lineNumbers, key) => {
|
||||
if (lineNumbers.length > 1) {
|
||||
duplicates.push({ key, lineNumbers });
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
...locale,
|
||||
filePath,
|
||||
keys,
|
||||
keySet: new Set(keys),
|
||||
duplicates,
|
||||
};
|
||||
}
|
||||
|
||||
function diffKeys(left, right) {
|
||||
return [...left].filter((key) => !right.has(key)).sort();
|
||||
}
|
||||
|
||||
function formatKeyList(keys) {
|
||||
return keys.length ? keys.map((key) => ` - ${key}`).join('\n') : '';
|
||||
}
|
||||
|
||||
function main() {
|
||||
const results = locales.map(readLocale);
|
||||
const base = results.find((locale) => locale.name === 'zh_CN');
|
||||
const errors = [];
|
||||
|
||||
results.forEach((locale) => {
|
||||
locale.duplicates.forEach(({ key, lineNumbers }) => {
|
||||
errors.push(
|
||||
`${locale.file} has duplicate key "${key}" on lines ${lineNumbers.join(', ')}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
results
|
||||
.filter((locale) => locale !== base)
|
||||
.forEach((locale) => {
|
||||
const missing = diffKeys(base.keySet, locale.keySet);
|
||||
const extra = diffKeys(locale.keySet, base.keySet);
|
||||
|
||||
if (missing.length) {
|
||||
errors.push(`${locale.file} is missing keys from ${base.file}:\n${formatKeyList(missing)}`);
|
||||
}
|
||||
|
||||
if (extra.length) {
|
||||
errors.push(`${locale.file} has keys that do not exist in ${base.file}:\n${formatKeyList(extra)}`);
|
||||
}
|
||||
});
|
||||
|
||||
if (errors.length) {
|
||||
console.error(`i18n check failed with ${errors.length} issue(s):`);
|
||||
console.error(errors.join('\n\n'));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const keyCount = base.keySet.size;
|
||||
console.log(`i18n check passed: ${results.length} locale files, ${keyCount} keys each.`);
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user