chore: add check locales keys
This commit is contained in:
+99
-1
@@ -12,6 +12,7 @@ const existingEntries = new Set(fs.readdirSync(localesDir));
|
||||
|
||||
const errors: string[] = [];
|
||||
|
||||
// ================ check if all locales are correctly named start ====================
|
||||
Object.values(langConfigMap).forEach(({ lang }) => {
|
||||
const expectedDir = lang;
|
||||
const expectedFile = `${lang}.ts`;
|
||||
@@ -25,10 +26,107 @@ Object.values(langConfigMap).forEach(({ lang }) => {
|
||||
}
|
||||
});
|
||||
|
||||
// ================ check if all locales are correctly named end ====================
|
||||
|
||||
const baseLang = 'en-US'; // standard language
|
||||
const fileExt = '.ts';
|
||||
|
||||
function parseLangFile(filePath: string): Record<string, any> {
|
||||
if (!fs.existsSync(filePath)) return {};
|
||||
|
||||
const content = fs.readFileSync(filePath, 'utf-8').trim();
|
||||
|
||||
try {
|
||||
// 1. extract the default export object
|
||||
const match = content.match(/export\s+default\s+({[\s\S]*});?/);
|
||||
if (match) {
|
||||
let jsonString = match[1];
|
||||
|
||||
// 2. remove trailing commas
|
||||
jsonString = jsonString.replace(/,\s*}/g, '}');
|
||||
|
||||
// 3. parse the object
|
||||
return new Function(`return ${jsonString}`)();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`❌ Error parsing ${filePath}:`, error);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// get all modules in a language directory
|
||||
function getLangFiles(lang: string): Record<string, Record<string, any>> {
|
||||
const langPath = path.join(localesDir, lang);
|
||||
if (!fs.existsSync(langPath)) return {};
|
||||
|
||||
return fs
|
||||
.readdirSync(langPath)
|
||||
.filter((file) => file.endsWith(fileExt))
|
||||
.reduce(
|
||||
(acc, file) => {
|
||||
const filePath = path.join(langPath, file);
|
||||
acc[file] = parseLangFile(filePath);
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, Record<string, any>>
|
||||
);
|
||||
}
|
||||
|
||||
function compareKeys(
|
||||
base: Record<string, any>,
|
||||
target: Record<string, any>
|
||||
): { missing: string[]; extra: string[] } {
|
||||
const baseKeys = new Set(Object.keys(base));
|
||||
const targetKeys = new Set(Object.keys(target));
|
||||
|
||||
return {
|
||||
missing: [...baseKeys].filter((key) => !targetKeys.has(key)),
|
||||
extra: [...targetKeys].filter((key) => !baseKeys.has(key))
|
||||
};
|
||||
}
|
||||
|
||||
// varify all locales base on en-US
|
||||
function validateLocales() {
|
||||
const baseFiles = getLangFiles(baseLang); // en-US as base
|
||||
const languages = fs
|
||||
.readdirSync(localesDir)
|
||||
.filter(
|
||||
(dir) =>
|
||||
fs.statSync(path.join(localesDir, dir)).isDirectory() &&
|
||||
dir !== baseLang
|
||||
);
|
||||
|
||||
let hasErrors = false;
|
||||
|
||||
languages.forEach((lang) => {
|
||||
console.log(`🔍 Checking ${lang}...`);
|
||||
const targetFiles = getLangFiles(lang);
|
||||
|
||||
Object.entries(baseFiles).forEach(([fileName, baseData]) => {
|
||||
const targetData = targetFiles[fileName] || {};
|
||||
|
||||
const { missing, extra } = compareKeys(baseData, targetData);
|
||||
|
||||
if (missing.length || extra.length) {
|
||||
hasErrors = true;
|
||||
console.log(`❌ [${lang}] ${fileName}:`);
|
||||
if (missing.length)
|
||||
console.log(` ===== Missing keys: ===== \n`, missing);
|
||||
if (extra.length) console.log(' ===== Extra keys: ===== \n', extra);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return !hasErrors;
|
||||
}
|
||||
|
||||
if (errors.length) {
|
||||
console.error('❌ Errors found:');
|
||||
errors.forEach(console.error);
|
||||
process.exit(1);
|
||||
} else if (!validateLocales()) {
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log('✅ All locales are correctly named.');
|
||||
console.log('✅ All keys are consistent!');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user