From 7a8df2c21623bec8e67b6e57e1abdf73fa0647fc Mon Sep 17 00:00:00 2001 From: Hibryda Date: Sun, 22 Mar 2026 10:42:25 +0100 Subject: [PATCH] feat(electrobun): 10 locales + system language auto-detection --- ui-electrobun/src/mainview/i18n.svelte.ts | 34 ++++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/ui-electrobun/src/mainview/i18n.svelte.ts b/ui-electrobun/src/mainview/i18n.svelte.ts index 0f1d4b8..8c51084 100644 --- a/ui-electrobun/src/mainview/i18n.svelte.ts +++ b/ui-electrobun/src/mainview/i18n.svelte.ts @@ -21,9 +21,16 @@ export interface LocaleMeta { } export const AVAILABLE_LOCALES: LocaleMeta[] = [ - { tag: 'en', label: 'English', nativeLabel: 'English', dir: 'ltr' }, - { tag: 'pl', label: 'Polish', nativeLabel: 'Polski', dir: 'ltr' }, - { tag: 'ar', label: 'Arabic', nativeLabel: '\u0627\u0644\u0639\u0631\u0628\u064a\u0629', dir: 'rtl' }, + { tag: 'en', label: 'English', nativeLabel: 'English', dir: 'ltr' }, + { tag: 'de', label: 'German', nativeLabel: 'Deutsch', dir: 'ltr' }, + { tag: 'es', label: 'Spanish', nativeLabel: 'Español', dir: 'ltr' }, + { tag: 'fr', label: 'French', nativeLabel: 'Français', dir: 'ltr' }, + { tag: 'ja', label: 'Japanese', nativeLabel: '日本語', dir: 'ltr' }, + { tag: 'pl', label: 'Polish', nativeLabel: 'Polski', dir: 'ltr' }, + { tag: 'uk', label: 'Ukrainian', nativeLabel: 'Українська', dir: 'ltr' }, + { tag: 'zh', label: 'Chinese', nativeLabel: '中文', dir: 'ltr' }, + { tag: 'ar', label: 'Arabic', nativeLabel: 'العربية', dir: 'rtl' }, + { tag: 'he', label: 'Hebrew', nativeLabel: 'עברית', dir: 'rtl' }, ]; // ── Reactive state ─────────────────────────────────────────────────────────── @@ -44,8 +51,15 @@ let _intl: IntlShape = createIntl({ locale: 'en', messages: {} }, cache) const loaders: Record Promise> = { en: () => import('../../locales/en.json').then(m => m.default as Messages), + de: () => import('../../locales/de.json').then(m => m.default as Messages), + es: () => import('../../locales/es.json').then(m => m.default as Messages), + fr: () => import('../../locales/fr.json').then(m => m.default as Messages), + ja: () => import('../../locales/ja.json').then(m => m.default as Messages), pl: () => import('../../locales/pl.json').then(m => m.default as Messages), + uk: () => import('../../locales/uk.json').then(m => m.default as Messages), + zh: () => import('../../locales/zh.json').then(m => m.default as Messages), ar: () => import('../../locales/ar.json').then(m => m.default as Messages), + he: () => import('../../locales/he.json').then(m => m.default as Messages), }; // ── Public API ─────────────────────────────────────────────────────────────── @@ -140,8 +154,9 @@ export async function initI18n(): Promise { // Load PluralRules polyfill for WebKitGTK (needed for Arabic 6-form plurals) await import('@formatjs/intl-pluralrules/polyfill-force.js').catch(() => {}); - let savedLocale = 'en'; + let savedLocale: string | null = null; + // 1. Try saved preference from settings try { const result = await appRpc?.request['settings.get']({ key: 'locale' }); if (result?.value && loaders[result.value]) { @@ -149,5 +164,16 @@ export async function initI18n(): Promise { } } catch { /* use default */ } + // 2. If no saved preference, detect system language + if (!savedLocale) { + const systemLang = navigator.language ?? navigator.languages?.[0] ?? 'en'; + const langBase = systemLang.split('-')[0].toLowerCase(); // 'en-US' → 'en' + if (loaders[langBase]) { + savedLocale = langBase; + } else { + savedLocale = 'en'; // fallback + } + } + await setLocale(savedLocale); }