test: add i18n duplicate key check

This commit is contained in:
Tyke Chen
2026-07-09 15:25:36 +08:00
parent ef2ed07c1c
commit af5fbb5282
2 changed files with 98 additions and 0 deletions
+96
View File
@@ -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();