// (c) 2025 TWWIM UG. All rights reserved. import { createContext, useContext, useState, useEffect, type ReactNode } from 'react'; import { defaultLocale, isValidLocale, type Locale } from './config'; interface TranslationContextType { locale: Locale; setLocale: (locale: Locale) => void; t: (key: string, variables?: Record) => string; } const TranslationContext = createContext(undefined); const STORAGE_KEY = 'archer-locale'; function getInitialLocale(): Locale { try { const stored = localStorage.getItem(STORAGE_KEY); if (stored && isValidLocale(stored)) return stored; } catch { // SSR or localStorage unavailable } return defaultLocale; } let translationsCache: Record> | null = null; async function loadTranslations(): Promise>> { if (translationsCache) return translationsCache; const [de, en] = await Promise.all([ import('./translations/de.json'), import('./translations/en.json'), ]); translationsCache = { de: de.default, en: en.default }; return translationsCache; } function resolve(obj: unknown, keys: string[]): string | undefined { let current = obj; for (const k of keys) { if (current == null || typeof current !== 'object') return undefined; current = (current as Record)[k]; } return typeof current === 'string' ? current : undefined; } export function TranslationProvider({ children }: { children: ReactNode }) { const [locale, setLocaleState] = useState(getInitialLocale); const [translations, setTranslations] = useState> | null>(null); useEffect(() => { loadTranslations().then(setTranslations); }, []); const setLocale = (l: Locale) => { setLocaleState(l); try { localStorage.setItem(STORAGE_KEY, l); } catch { // ignore } }; const t = (key: string, variables?: Record): string => { if (!translations) return key; const keys = key.split('.'); let value = resolve(translations[locale], keys); // Fallback to other locale if (value === undefined) { const fallback = locale === 'de' ? 'en' : 'de'; value = resolve(translations[fallback], keys); } if (value === undefined) return key; if (variables) { return value.replace(/\{\{(\w+)\}\}/g, (_match, variable: string) => { return variables[variable] != null ? String(variables[variable]) : `{{${variable}}}`; }); } return value; }; return ( {children} ); } export function useTranslation() { const context = useContext(TranslationContext); if (!context) { throw new Error('useTranslation must be used within a TranslationProvider'); } return context; }