Files
lage-chat-control/frontend/src/lib/i18n/index.svelte.ts
T
sucupira db5a997e50 feat(oki): fondations de la migration vers la stack souveraine OKI
Architecture décidée et documentée dans ADR.md : SvelteKit natif en
fichiers plats plutôt que Strapi (55 outils, données statiques,
souveraineté et budget performance prioritaires — doctrine §1.2, §4.4).

- frontend/ : SvelteKit 2 + Svelte 5 (runes), adapter-static, 58 pages
  prérendues, CSS natif en @layer (reset→tokens→base→layouts→components),
  tokens oklch(), container queries, typo fluide clamp(), 2 polices WOFF2
  auto-hébergées (Atkinson Hyperlegible, Fraunces), zéro CDN tiers
- i18n FR/gcf typé (clé manquante = erreur de build), bascule Kréyòl
  persistée en localStorage, micro-textes créoles (« Ou pa manké ayen »)
- Composants : ToolCard, DifficultyBadge (forme+texte+couleur, jamais la
  couleur seule), CategoryNav (≤5 entrées, divulgation progressive),
  SearchBar (raccourci /), LanguageSwitcher, EndMarker
- content/ : 55 fiches migrées depuis src/ (script frontend/scripts/
  migrate-tools.mjs, idempotent), licences SPDX reprises de directory.json
- docs/ : DESIGN_SYSTEM.md et CONTENT_GUIDE.md

Budgets vérifiés : JS 41 Ko gzip, CSS 2,9 Ko gzip, svelte-check 0 erreur.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 12:51:17 -04:00

55 lines
1.7 KiB
TypeScript

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
}