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 `
${s.label} ${s.lang} ${s.completedKeys}/${s.totalKeys} · ${s.percentComplete}%
${ s.missingKeys.length > 0 ? `
${s.missingKeys.length} missing keys
` : `

All strings translated 🎉

` }
`; } const html = ` EmDash Translation Status

EmDash Translation Status

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`); }