feat(electrobun): i18n system — @formatjs/intl + Svelte 5 runes + 3 locales

- i18n.svelte.ts: store with $state locale + createIntl(), t() function,
  formatDate/Number/RelativeTime, getDir() for RTL, async setLocale()
- i18n.types.ts: TranslationKey union (codegen from en.json)
- locales/en.json: 200+ strings in ICU MessageFormat
- locales/pl.json: full Polish translation
- locales/ar.json: partial Arabic (validates 6-form plural + RTL)
- scripts/i18n-types.ts: codegen script for type-safe keys
- 6 components wired: StatusBar, AgentPane, CommandPalette,
  SettingsDrawer, SplashScreen, ChatInput
- Language selector in AppearanceSettings
- App.svelte: document.dir reactive for RTL
- CONTRIBUTING_I18N.md: guide for adding languages

Note: currently Electrobun-only. Will extract to @agor/i18n shared
package for both Tauri and Electrobun.
This commit is contained in:
Hibryda 2026-03-22 10:28:13 +01:00
parent eee65070a8
commit aae86a4001
16 changed files with 947 additions and 64 deletions

View file

@ -0,0 +1,37 @@
#!/usr/bin/env bun
/**
* Reads locales/en.json and generates src/mainview/i18n.types.ts
* with a TranslationKey union type covering all keys.
*
* Usage: bun scripts/i18n-types.ts
*/
import { readFileSync, writeFileSync } from 'fs';
import { resolve } from 'path';
const ROOT = resolve(import.meta.dir, '..');
const EN_PATH = resolve(ROOT, 'locales/en.json');
const OUT_PATH = resolve(ROOT, 'src/mainview/i18n.types.ts');
const en: Record<string, string> = JSON.parse(readFileSync(EN_PATH, 'utf-8'));
const keys = Object.keys(en).sort();
const lines: string[] = [
'/**',
' * Auto-generated by scripts/i18n-types.ts — do not edit manually.',
' * Run: bun scripts/i18n-types.ts',
' */',
'',
'export type TranslationKey =',
];
keys.forEach((key, i) => {
const prefix = i === 0 ? ' | ' : ' | ';
const suffix = i === keys.length - 1 ? ';' : '';
lines.push(`${prefix}'${key}'${suffix}`);
});
lines.push('');
writeFileSync(OUT_PATH, lines.join('\n'), 'utf-8');
console.log(`[i18n-types] Generated ${keys.length} keys -> ${OUT_PATH}`);