// Builds src/i18n/{sv,en}.json from docs/ux/strings.csv (the app's strings, SPEC §13.4) and src/i18n/web-strings.csv // (web-only keys, prefix web_, same columns). Android placeholders become positional braces: %1$s and %1$d -> {1}, // a bare %d or %s -> {1}, {2}, … in order of appearance, %% -> %. Strings marked formatted=false are copied as is. // Plurals keep their key:one / key:other keys. `--check` compares with the files on disk instead of writing. import { existsSync, readFileSync, writeFileSync } from 'node:fs'; import { parseCsvRecords } from '../src/lib/csv.ts'; const root = new URL('../', import.meta.url); const sources = [new URL('../docs/ux/strings.csv', root), new URL('src/i18n/web-strings.csv', root)]; export function convertPlaceholders(text, formatted) { if (!formatted) return text; let next = 0; return text.replace(/%(?:(\d+)\$)?([sd%])/g, (_match, index, type) => { if (type === '%') return '%'; if (index) return `{${index}}`; next += 1; return `{${next}}`; }); } export function buildCatalogs() { const catalogs = { en: {}, sv: {} }; for (const source of sources) { for (const record of parseCsvRecords(readFileSync(source, 'utf-8'))) { const key = record.key; if (!key) continue; if (key in catalogs.en) throw new Error(`duplicate string key ${key} in ${source.pathname}`); const formatted = !(record.notes ?? '').includes('formatted=false'); catalogs.en[key] = convertPlaceholders(record.en, formatted); catalogs.sv[key] = convertPlaceholders(record.sv, formatted); } } const sorted = (obj) => Object.fromEntries( Object.keys(obj) .sort() .map((k) => [k, obj[k]]), ); return { en: sorted(catalogs.en), sv: sorted(catalogs.sv) }; } const check = process.argv.includes('--check'); const catalogs = buildCatalogs(); let stale = false; for (const lang of ['sv', 'en']) { const target = new URL(`src/i18n/${lang}.json`, root); const text = JSON.stringify(catalogs[lang], null, 2) + '\n'; if (check) { const current = existsSync(target) ? readFileSync(target, 'utf-8') : ''; if (current !== text) { console.error(`src/i18n/${lang}.json is stale: run npm run i18n:import`); stale = true; } } else { writeFileSync(target, text); console.log(`src/i18n/${lang}.json: ${Object.keys(catalogs[lang]).length} keys`); } } if (stale) process.exit(1);