import { createContext, useContext, useState, useCallback, useEffect, useMemo, useRef } from 'react' import en from './en' import fr from './fr' import { getLayout, getLayoutList } from './keyboards' import api from '../api/client' const translations = { en, fr } const STORAGE_KEY_LANG = 'muyue-language' const STORAGE_KEY_KBD = 'muyue-keyboard' const I18nContext = createContext(null) function resolveLocale(layout) { const l = getLayout(layout) return l.locale } export function I18nProvider({ children }) { const [language, setLanguageState] = useState(() => localStorage.getItem(STORAGE_KEY_LANG) || 'fr') const [keyboard, setKeyboardState] = useState(() => localStorage.getItem(STORAGE_KEY_KBD) || 'azerty') const [loaded, setLoaded] = useState(false) const pendingSave = useRef(null) useEffect(() => { api.getConfig() .then(d => { const prefs = d.profile?.preferences if (prefs?.language) setLanguageState(prefs.language) if (prefs?.keyboard_layout) setKeyboardState(prefs.keyboard_layout) }) .catch(() => {}) .finally(() => setLoaded(true)) }, []) useEffect(() => { if (!loaded) return if (pendingSave.current) clearTimeout(pendingSave.current) pendingSave.current = setTimeout(() => { api.savePreferences({ language, keyboard_layout: keyboard }).catch(() => {}) }, 500) return () => { if (pendingSave.current) clearTimeout(pendingSave.current) } }, [language, keyboard, loaded]) const setLanguage = useCallback((lang) => { setLanguageState(lang) localStorage.setItem(STORAGE_KEY_LANG, lang) }, []) const setKeyboard = useCallback((kbd) => { setKeyboardState(kbd) localStorage.setItem(STORAGE_KEY_KBD, kbd) }, []) const layout = useMemo(() => getLayout(keyboard), [keyboard]) const t = useCallback((key, params) => { const dict = translations[language] || translations.fr const keys = key.split('.') let value = dict for (const k of keys) { if (value == null) return key value = value[k] } if (typeof value !== 'string') return key if (params) { return Object.entries(params).reduce((str, [k, v]) => str.replace(`{${k}}`, v), value) } return value }, [language]) const clockLocale = useMemo(() => resolveLocale(keyboard), [keyboard]) const contextValue = useMemo(() => ({ language, keyboard, layout, setLanguage, setKeyboard, t, clockLocale, layouts: getLayoutList(), }), [language, keyboard, layout, t, clockLocale]) return ( {children} ) } export function useI18n() { const ctx = useContext(I18nContext) if (!ctx) throw new Error('useI18n must be used within I18nProvider') return ctx } export const LANGUAGES = [ { id: 'fr', name: 'Fran\u00e7ais' }, { id: 'en', name: 'English' }, ]