//! i18n scaffolding via svelte-i18n. //! //! Scope for the initial pass: wire the stack (loader, persisted choice, //! Settings selector) so strings can be migrated incrementally. Only a //! handful of labels are actually translated today — everything else //! continues to render as-is via hardcoded text until extracted. //! //! Locales currently shipped: en (source of truth), es, de. Adding a new //! locale is one `register` call + a new `locales/.json`. import { init, register, locale as svelteLocale } from "svelte-i18n"; import { derived, get } from "svelte/store"; export type Locale = "en" | "es" | "de"; export const SUPPORTED_LOCALES: { code: Locale; label: string }[] = [ { code: "en", label: "English" }, { code: "es", label: "Español" }, { code: "de", label: "Deutsch" }, ]; const STORAGE_KEY = "kon_locale"; register("en", () => import("./locales/en.json")); register("es", () => import("./locales/es.json")); register("de", () => import("./locales/de.json")); function detectInitialLocale(): Locale { if (typeof localStorage !== "undefined") { const stored = localStorage.getItem(STORAGE_KEY); if (stored && SUPPORTED_LOCALES.some((option) => option.code === stored)) { return stored as Locale; } } if (typeof navigator !== "undefined" && navigator.language) { const short = navigator.language.split("-")[0] as Locale; if (SUPPORTED_LOCALES.some((option) => option.code === short)) { return short; } } return "en"; } let initialised = false; export function initI18n(): void { if (initialised) return; initialised = true; init({ fallbackLocale: "en", initialLocale: detectInitialLocale(), }); } export function setLocale(code: Locale): void { svelteLocale.set(code); if (typeof localStorage !== "undefined") { try { localStorage.setItem(STORAGE_KEY, code); } catch { // non-fatal: private browsing, quota, etc. } } } export const currentLocale = derived(svelteLocale, ($locale) => ((($locale ?? "en").split("-")[0]) as Locale), ); export function getCurrentLocale(): Locale { return get(currentLocale); }