125 lines
3.9 KiB
JavaScript
125 lines
3.9 KiB
JavaScript
// Removes useless entries (and resulting empty sections) from every locale
|
|
// file in loc/ except en.json:
|
|
//
|
|
// 1. Empty-string values — at runtime they render a blank string instead of
|
|
// falling back to the English source, so they should not be committed.
|
|
// 2. Orphan keys — keys present in a locale file that no longer exist in
|
|
// en.json (the source of truth). They are dead weight: react-localization
|
|
// indexes by en.json structure, so the runtime never reads them, and code
|
|
// grep confirms zero references. Usually leftovers from renamed/removed
|
|
// strings in en.json (e.g. `details_from` → `details_inputs`).
|
|
// 3. Orphan sections — top-level sections that don't exist in en.json.
|
|
//
|
|
// Run: `node scripts/clean-loc-strings.js`
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const LOC_DIR = path.join(__dirname, '..', 'loc');
|
|
const SOURCE = 'en.json';
|
|
|
|
function buildEnSchema(en) {
|
|
// Returns Map<section, Set<key>> reflecting en.json's structure.
|
|
const schema = new Map();
|
|
for (const sectionName of Object.keys(en)) {
|
|
const section = en[sectionName];
|
|
if (typeof section !== 'object' || section === null) continue;
|
|
schema.set(sectionName, new Set(Object.keys(section)));
|
|
}
|
|
return schema;
|
|
}
|
|
|
|
function cleanLocale(filePath, enSchema) {
|
|
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
let removedEmpty = 0;
|
|
let removedOrphans = 0;
|
|
let removedSections = 0;
|
|
|
|
for (const sectionName of Object.keys(data)) {
|
|
const section = data[sectionName];
|
|
if (typeof section !== 'object' || section === null) continue;
|
|
|
|
const enKeys = enSchema.get(sectionName);
|
|
if (!enKeys) {
|
|
// Whole section gone from en.json — drop it.
|
|
delete data[sectionName];
|
|
removedSections++;
|
|
continue;
|
|
}
|
|
|
|
for (const key of Object.keys(section)) {
|
|
if (section[key] === '') {
|
|
delete section[key];
|
|
removedEmpty++;
|
|
} else if (!enKeys.has(key)) {
|
|
delete section[key];
|
|
removedOrphans++;
|
|
}
|
|
}
|
|
|
|
if (Object.keys(section).length === 0) {
|
|
delete data[sectionName];
|
|
removedSections++;
|
|
}
|
|
}
|
|
|
|
return { data, removedEmpty, removedOrphans, removedSections };
|
|
}
|
|
|
|
function main() {
|
|
const enPath = path.join(LOC_DIR, SOURCE);
|
|
if (!fs.existsSync(enPath)) {
|
|
console.error(`Cannot find source file: ${enPath}`);
|
|
process.exit(2);
|
|
}
|
|
const en = JSON.parse(fs.readFileSync(enPath, 'utf8'));
|
|
const enSchema = buildEnSchema(en);
|
|
|
|
const files = fs.readdirSync(LOC_DIR)
|
|
.filter(name => name.endsWith('.json') && name !== SOURCE)
|
|
.sort();
|
|
|
|
let touched = 0;
|
|
let totalEmpty = 0;
|
|
let totalOrphans = 0;
|
|
let totalSections = 0;
|
|
|
|
for (const name of files) {
|
|
const filePath = path.join(LOC_DIR, name);
|
|
let result;
|
|
try {
|
|
result = cleanLocale(filePath, enSchema);
|
|
} catch (e) {
|
|
console.error(`${name}: parse error — ${e.message}`);
|
|
process.exitCode = 1;
|
|
continue;
|
|
}
|
|
|
|
const { data, removedEmpty, removedOrphans, removedSections } = result;
|
|
if (removedEmpty === 0 && removedOrphans === 0 && removedSections === 0) continue;
|
|
|
|
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n');
|
|
touched++;
|
|
totalEmpty += removedEmpty;
|
|
totalOrphans += removedOrphans;
|
|
totalSections += removedSections;
|
|
const parts = [];
|
|
if (removedEmpty) parts.push(`${removedEmpty} empty`);
|
|
if (removedOrphans) parts.push(`${removedOrphans} orphan key(s)`);
|
|
if (removedSections) parts.push(`${removedSections} empty/orphan section(s)`);
|
|
console.log(`${name}: removed ${parts.join(', ')}`);
|
|
}
|
|
|
|
if (touched === 0) {
|
|
console.log('OK — no empty strings or orphan keys found in locale files.');
|
|
} else {
|
|
console.log(
|
|
`\nDone. ${touched} file(s) touched: ` +
|
|
`${totalEmpty} empty key(s), ${totalOrphans} orphan key(s), ` +
|
|
`${totalSections} empty/orphan section(s) removed.`
|
|
);
|
|
}
|
|
}
|
|
|
|
main();
|