Lots of technical improvements
This commit is contained in:
65
scripts/check-i18n.mjs
Normal file
65
scripts/check-i18n.mjs
Normal file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env node
|
||||
// Verifies that all i18n translation files share the exact same set of keys.
|
||||
// Exits with a non-zero status (and prints the differences) if any key is
|
||||
// present in one language but missing in another, so CI can catch drift.
|
||||
|
||||
import { readFileSync, readdirSync } from 'node:fs';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
||||
const i18nDir = join(scriptDir, '..', 'src', 'assets', 'i18n');
|
||||
|
||||
function collectLeafKeys(value, prefix, keys) {
|
||||
for (const key of Object.keys(value)) {
|
||||
const fullKey = prefix ? `${prefix}.${key}` : key;
|
||||
const child = value[key];
|
||||
const isNestedObject = child !== null && typeof child === 'object' && !Array.isArray(child);
|
||||
if (isNestedObject) {
|
||||
collectLeafKeys(child, fullKey, keys);
|
||||
} else {
|
||||
keys.add(fullKey);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
function loadKeys(fileName) {
|
||||
const content = readFileSync(join(i18nDir, fileName), 'utf8');
|
||||
const parsed = JSON.parse(content);
|
||||
return collectLeafKeys(parsed, '', new Set());
|
||||
}
|
||||
|
||||
const files = readdirSync(i18nDir).filter((name) => name.endsWith('.json'));
|
||||
if (files.length < 2) {
|
||||
console.log('i18n check: nothing to compare (fewer than two language files).');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const keysByFile = new Map(files.map((file) => [file, loadKeys(file)]));
|
||||
|
||||
const allKeys = new Set();
|
||||
for (const keys of keysByFile.values()) {
|
||||
for (const key of keys) {
|
||||
allKeys.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
let hasError = false;
|
||||
for (const [file, keys] of keysByFile) {
|
||||
const missing = [...allKeys].filter((key) => !keys.has(key)).sort();
|
||||
if (missing.length > 0) {
|
||||
hasError = true;
|
||||
console.error(`\n[${file}] missing ${missing.length} key(s):`);
|
||||
for (const key of missing) {
|
||||
console.error(` - ${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
console.error('\ni18n check failed: translation files are out of sync.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`i18n check passed: ${files.join(', ')} share ${allKeys.size} keys.`);
|
||||
Reference in New Issue
Block a user