release: WRNexusJS 0.8.0
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import { existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs";
|
||||
import { extname, join, resolve } from "node:path";
|
||||
import {
|
||||
auditLocaleKeys,
|
||||
extractTranslationKeysFromFiles,
|
||||
flattenMessageKeys,
|
||||
loadLocales,
|
||||
} from "@wrnexus/i18n";
|
||||
|
||||
function sourceFiles(root: string): string[] {
|
||||
const output: string[] = [];
|
||||
const visit = (directory: string) => {
|
||||
if (!existsSync(directory)) return;
|
||||
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
||||
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist")
|
||||
continue;
|
||||
const path = join(directory, entry.name);
|
||||
if (entry.isDirectory()) visit(path);
|
||||
else if ([".wrn", ".ts", ".tsx", ".js", ".jsx"].includes(extname(entry.name)))
|
||||
output.push(path);
|
||||
}
|
||||
};
|
||||
visit(join(root, "app"));
|
||||
return output.sort();
|
||||
}
|
||||
export function runI18nCommand(appRoot: string, command: string): boolean {
|
||||
const root = resolve(appRoot);
|
||||
const extracted = extractTranslationKeysFromFiles(sourceFiles(root));
|
||||
const keys = [...new Set(extracted.map((entry) => entry.key))].sort();
|
||||
const messages = loadLocales(join(root, "app", "locales"), { strict: true });
|
||||
const locales = Object.keys(messages).sort();
|
||||
const reference = locales[0] ?? "en";
|
||||
const audit = auditLocaleKeys(messages, reference);
|
||||
const referenceKeys = new Set(flattenMessageKeys(messages[reference] ?? {}));
|
||||
const unused = [...referenceKeys].filter((key) => !keys.includes(key)).sort();
|
||||
const missingFromReference = keys.filter((key) => !referenceKeys.has(key));
|
||||
const report = { reference, locales, extracted: keys, missingFromReference, unused, audit };
|
||||
if (command === "extract") {
|
||||
const directory = join(root, ".wrnexus");
|
||||
mkdirSync(directory, { recursive: true });
|
||||
const file = join(directory, "i18n-keys.json");
|
||||
writeFileSync(file, `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
||||
console.log(`✓ Extracted ${keys.length} translation keys to ${file}`);
|
||||
return true;
|
||||
}
|
||||
if (command !== "validate")
|
||||
throw new Error("WRN-I18N-COMMAND: use i18n extract or i18n validate.");
|
||||
for (const locale of locales) {
|
||||
const missing = [
|
||||
...new Set([...(audit[locale]?.missing ?? []), ...missingFromReference]),
|
||||
].sort();
|
||||
if (missing.length) {
|
||||
console.log(`Missing in ${locale}:`);
|
||||
missing.forEach((key) => console.log(`- ${key}`));
|
||||
}
|
||||
}
|
||||
if (unused.length) {
|
||||
console.log("Unused keys:");
|
||||
unused.forEach((key) => console.log(`- ${key}`));
|
||||
}
|
||||
const healthy =
|
||||
missingFromReference.length === 0 &&
|
||||
Object.values(audit).every((value) => value.missing.length === 0);
|
||||
if (healthy) console.log(`✓ ${locales.length} locales contain every extracted key.`);
|
||||
return healthy;
|
||||
}
|
||||
Reference in New Issue
Block a user