import { mkdirSync, writeFileSync } from "node:fs";
import { createLunaria } from "@lunariajs/core";
const lunaria = await createLunaria();
const status = await lunaria.getFullStatus();
const { sourceLocale, locales } = lunaria.config;
const links = lunaria.gitHostingLinks();
const fileStatus = status[0];
if (!fileStatus) {
console.log("No tracked files found.");
process.exit(0);
}
interface LocaleStatus {
lang: string;
label: string;
totalKeys: number;
completedKeys: number;
missingKeys: string[];
percentComplete: number;
editUrl: string;
historyUrl: string;
}
const AMP = /&/g;
const LT = //g;
const QUOT = /"/g;
function countPoEntries(contents: string): number {
let count = 0;
for (const line of contents.split("\n")) {
if (line.startsWith("msgid ") && line !== 'msgid ""') {
count++;
}
}
return count;
}
const totalKeys = countPoEntries(fileStatus.source.contents);
const localeStatuses: LocaleStatus[] = locales.map((locale) => {
const localization = fileStatus.localizations.find((l) => l.lang === locale.lang);
const missingKeys: string[] = [];
if (localization && "missingKeys" in localization && localization.missingKeys) {
for (const keyPath of localization.missingKeys) {
missingKeys.push(Array.isArray(keyPath) ? keyPath.join(".") : String(keyPath));
}
}
const completedKeys = totalKeys - missingKeys.length;
const editUrl = localization
? links.source(localization.path)
: links.create(`packages/admin/src/locales/${locale.lang}/messages.po`);
const historyUrl = localization ? links.history(localization.path) : "";
return {
lang: locale.lang,
label: locale.label,
totalKeys,
completedKeys,
missingKeys,
percentComplete: totalKeys > 0 ? Math.round((completedKeys / totalKeys) * 100) : 100,
editUrl,
historyUrl,
};
});
function barClass(percent: number): string {
if (percent >= 100) return "completed";
if (percent > 90) return "very-good";
if (percent > 75) return "good";
if (percent > 50) return "help-needed";
return "basic";
}
function escapeHtml(s: string): string {
return s.replace(AMP, "&").replace(LT, "<").replace(GT, ">").replace(QUOT, """);
}
function localeCard(s: LocaleStatus): string {
return `
All strings translated 🎉
${s.label} ${s.lang}
${s.completedKeys}/${s.totalKeys} · ${s.percentComplete}%
${s.missingKeys.length} missing keys
${s.missingKeys.map((k) => `
Admin UI · ${totalKeys} translatable strings
${localeStatuses.map(localeCard).join("\n")} `; const jsonStatus = { generatedAt: new Date().toISOString(), sourceLocale: { lang: sourceLocale.lang, label: sourceLocale.label, totalKeys }, locales: localeStatuses, }; mkdirSync("i18n/dist", { recursive: true }); writeFileSync("i18n/dist/index.html", html); writeFileSync("i18n/dist/status.json", JSON.stringify(jsonStatus, null, "\t")); console.log(`Generated dashboard: ${localeStatuses.length} locales, ${totalKeys} keys`); for (const s of localeStatuses) { console.log(` ${s.label} (${s.lang}): ${s.percentComplete}% — ${s.missingKeys.length} missing`); }