Files
dwellops-platform/scripts/aggregate-translations.ts
2026-03-10 21:30:52 -03:00

83 lines
2.7 KiB
TypeScript

/**
* Translation aggregation script.
*
* Scans all `translations.json` files alongside components/widgets/views
* in apps/web/src, merges them with the shared common messages, and writes
* a combined per-locale message file to apps/web/messages/<locale>.json.
*
* Usage:
* pnpm i18n:aggregate
*
* During development, run this after adding new translation keys.
* A watch-mode version should be wired into the dev workflow (future work).
*/
import { readFileSync, writeFileSync, readdirSync, statSync, existsSync } from 'fs';
import { join, dirname, relative } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const repoRoot = join(__dirname, '..');
const webSrc = join(repoRoot, 'apps/web/src');
const messagesDir = join(repoRoot, 'apps/web/messages');
const locales = ['en'];
type TranslationTree = Record<string, unknown>;
/**
* Recursively finds all `translations.json` files within a directory.
*/
function findTranslationFiles(dir: string): string[] {
const results: string[] = [];
for (const entry of readdirSync(dir)) {
const full = join(dir, entry);
const stat = statSync(full);
if (stat.isDirectory()) {
results.push(...findTranslationFiles(full));
} else if (entry === 'translations.json') {
results.push(full);
}
}
return results;
}
/**
* Deep-merges two translation trees. Conflicts are overwritten by `source`.
*/
function merge(target: TranslationTree, source: TranslationTree): TranslationTree {
const result = { ...target };
for (const [key, value] of Object.entries(source)) {
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
result[key] = merge(
(result[key] as TranslationTree | undefined) ?? {},
value as TranslationTree,
);
} else {
result[key] = value;
}
}
return result;
}
for (const locale of locales) {
const baseFile = join(messagesDir, `${locale}.json`);
let base: TranslationTree = existsSync(baseFile)
? (JSON.parse(readFileSync(baseFile, 'utf-8')) as TranslationTree)
: {};
const translationFiles = findTranslationFiles(webSrc);
for (const file of translationFiles) {
const raw = JSON.parse(readFileSync(file, 'utf-8')) as TranslationTree;
const localeData = (raw[locale] ?? raw) as TranslationTree;
base = merge(base, localeData);
const rel = relative(repoRoot, file);
console.log(` merged: ${rel}`);
}
writeFileSync(baseFile, JSON.stringify(base, null, 2) + '\n', 'utf-8');
console.log(`${locale}: wrote ${baseFile}`);
}
console.log('Translation aggregation complete.');