Files
lage-chat-control/frontend/src/lib/i18n/index.svelte.ts
T

55 lines
1.7 KiB
TypeScript
Raw Normal View History

import fr from './fr.json'
import gcf from './gcf.json'
import { browser } from '$app/environment'
import { defaultLocale, type Locale } from './locales'
export { locales, localeNames, defaultLocale, type Locale } from './locales'
type Dict = typeof fr
// gcf est vérifié par TypeScript contre la forme du français : une clé
// manquante est une erreur de build, pas un fallback silencieux (ADR-001).
const dicts: Record<Locale, Dict> = { fr, gcf }
const STORAGE_KEY = 'oki-lang'
function initialLocale(): Locale {
if (!browser) return defaultLocale
const saved = localStorage.getItem(STORAGE_KEY)
return saved === 'gcf' || saved === 'fr' ? saved : defaultLocale
}
// Rune d'état partagée (Svelte 5) : la langue de l'interface.
// Le HTML prérendu est en fr ; le créole est une amélioration progressive
// (persistance localStorage — mission §4.3, doctrine §4.2).
const state = $state({ locale: initialLocale() })
export function getLocale(): Locale {
return state.locale
}
export function setLocale(locale: Locale) {
state.locale = locale
if (browser) {
localStorage.setItem(STORAGE_KEY, locale)
document.documentElement.lang = locale
}
}
function lookup(dict: Dict, path: string): unknown {
return path.split('.').reduce<unknown>((node, key) => {
if (node && typeof node === 'object' && key in node) {
return (node as Record<string, unknown>)[key]
}
return undefined
}, dict)
}
/** Chaîne d'interface pour `path` dans la langue courante (réactif). */
export function t(path: string): string {
const hit = lookup(dicts[state.locale], path) ?? lookup(dicts[defaultLocale], path)
if (typeof hit !== 'string') {
throw new Error(`Clé i18n manquante « ${path} » (locale : ${state.locale})`)
}
return hit
}