Files
Toju/tools/sync-app-i18n-catalog.mjs
Myx ee293d7daf
Some checks failed
Deploy Web Apps / deploy (push) Successful in 5m52s
Build Android APK / build-android-apk (push) Failing after 23m15s
Queue Release Build / prepare (push) Successful in 1m42s
Queue Release Build / build-linux (push) Failing after 9m33s
Queue Release Build / build-windows (push) Successful in 26m5s
Queue Release Build / finalize (push) Has been skipped
feat: Rename to Toju and add translation
2026-06-05 17:17:29 +02:00

113 lines
3.0 KiB
JavaScript

#!/usr/bin/env node
/**
* Builds toju-app/public/i18n/en.json from the base catalog plus extracted
* labels from theme-registry and access-control constants.
*/
import { readFileSync, readdirSync, writeFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const repoRoot = resolve(__dirname, '..');
const catalogDir = resolve(repoRoot, 'toju-app/public/i18n/catalog');
function extractLabelDescriptionBlocks(source, blockPattern) {
const entries = {};
let match;
while ((match = blockPattern.exec(source)) !== null) {
const [, key, label, description] = match;
entries[key] = { label, description };
}
return entries;
}
function extractThemeRegistry(source) {
return extractLabelDescriptionBlocks(
source,
/key: '([^']+)',\s*\n\s*label: '((?:\\'|[^'])*)',\s*\n\s*description: '((?:\\'|[^'])*)',/g
);
}
function extractPermissions(source) {
return extractLabelDescriptionBlocks(
source,
/key: '([^']+)',\s*\n\s*label: '((?:\\'|[^'])*)',\s*\n\s*description: '((?:\\'|[^'])*)'/g
);
}
function unescape(value) {
return value.replace(/\\'/g, "'");
}
function deepMerge(target, source) {
for (const [key, value] of Object.entries(source)) {
if (value && typeof value === 'object' && !Array.isArray(value)) {
target[key] ??= {};
deepMerge(target[key], value);
continue;
}
target[key] = value;
}
return target;
}
function mergeAtPath(catalog, pathSegments) {
let target = catalog;
for (const segment of pathSegments) {
target[segment] ??= {};
target = target[segment];
}
return target;
}
function mergeExtracted(catalog, extracted, prefix) {
const target = mergeAtPath(catalog, prefix.split('.'));
for (const [key, { label, description }] of Object.entries(extracted)) {
target[key] ??= {};
target[key].label = unescape(label);
target[key].description = unescape(description);
}
}
function loadCatalogFragments() {
const catalog = {};
const files = readdirSync(catalogDir)
.filter((name) => name.endsWith('.json'))
.sort();
for (const file of files) {
const fragment = JSON.parse(readFileSync(resolve(catalogDir, file), 'utf8'));
deepMerge(catalog, fragment);
}
return catalog;
}
function main() {
const themeRegistrySource = readFileSync(
resolve(repoRoot, 'toju-app/src/app/domains/theme/domain/logic/theme-registry.logic.ts'),
'utf8'
);
const permissionsSource = readFileSync(
resolve(repoRoot, 'toju-app/src/app/domains/access-control/domain/constants/access-control.constants.ts'),
'utf8'
);
const catalog = loadCatalogFragments();
mergeExtracted(catalog, extractThemeRegistry(themeRegistrySource), 'theme.registry');
mergeExtracted(catalog, extractPermissions(permissionsSource), 'permissions');
const outputPath = resolve(repoRoot, 'toju-app/public/i18n/en.json');
writeFileSync(outputPath, `${JSON.stringify(catalog, null, 2)}\n`, 'utf8');
console.log(`Wrote ${outputPath}`);
}
main();