mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-24 06:46:09 +00:00
98 lines
2.5 KiB
JavaScript
98 lines
2.5 KiB
JavaScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
const root = process.cwd();
|
|
const localesDir = path.join(root, "src", "i18n", "locales");
|
|
|
|
const locales = fs
|
|
.readdirSync(localesDir)
|
|
.filter((entry) => {
|
|
const fullPath = path.join(localesDir, entry);
|
|
return fs.statSync(fullPath).isDirectory();
|
|
})
|
|
.sort((left, right) => left.localeCompare(right));
|
|
|
|
if (!locales.includes("en")) {
|
|
console.error('i18n-check: expected base locale directory "en"');
|
|
process.exit(1);
|
|
}
|
|
|
|
function loadJson(filePath) {
|
|
try {
|
|
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
throw new Error(`i18n-check: failed to load ${path.relative(root, filePath)}: ${message}`);
|
|
}
|
|
}
|
|
|
|
function collectKeyPaths(obj, prefix = "") {
|
|
if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
|
|
return prefix ? [prefix] : [];
|
|
}
|
|
|
|
const keys = Object.keys(obj);
|
|
if (keys.length === 0) {
|
|
return prefix ? [prefix] : [];
|
|
}
|
|
|
|
const paths = [];
|
|
for (const key of keys) {
|
|
const nextPrefix = prefix ? `${prefix}.${key}` : key;
|
|
const value = obj[key];
|
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
paths.push(...collectKeyPaths(value, nextPrefix));
|
|
} else {
|
|
paths.push(nextPrefix);
|
|
}
|
|
}
|
|
return paths;
|
|
}
|
|
|
|
const baseLocaleDir = path.join(localesDir, "en");
|
|
const namespaceFiles = fs
|
|
.readdirSync(baseLocaleDir)
|
|
.filter((file) => file.endsWith(".json"))
|
|
.sort((left, right) => left.localeCompare(right));
|
|
|
|
let hasErrors = false;
|
|
|
|
for (const namespaceFile of namespaceFiles) {
|
|
const baseData = loadJson(path.join(baseLocaleDir, namespaceFile));
|
|
const baseKeys = new Set(collectKeyPaths(baseData));
|
|
|
|
for (const locale of locales) {
|
|
if (locale === "en") continue;
|
|
|
|
const localeFile = path.join(localesDir, locale, namespaceFile);
|
|
if (!fs.existsSync(localeFile)) {
|
|
console.error(`i18n-check: missing namespace file ${locale}/${namespaceFile}`);
|
|
hasErrors = true;
|
|
continue;
|
|
}
|
|
|
|
const localeData = loadJson(localeFile);
|
|
const localeKeys = new Set(collectKeyPaths(localeData));
|
|
|
|
for (const key of baseKeys) {
|
|
if (!localeKeys.has(key)) {
|
|
console.error(`i18n-check: missing key ${locale}/${namespaceFile}:${key}`);
|
|
hasErrors = true;
|
|
}
|
|
}
|
|
|
|
for (const key of localeKeys) {
|
|
if (!baseKeys.has(key)) {
|
|
console.error(`i18n-check: extra key ${locale}/${namespaceFile}:${key}`);
|
|
hasErrors = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hasErrors) {
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log("i18n-check: locale files are structurally consistent");
|