| import { |
| createContext, |
| useCallback, |
| useContext, |
| useEffect, |
| useMemo, |
| useState, |
| type ReactNode, |
| } from "react"; |
| import { DICTIONARIES, type Dict, type Locale } from "./locales"; |
|
|
| const STORAGE_KEY = "signalmod.locale"; |
|
|
| type I18nValue = { |
| locale: Locale; |
| setLocale: (l: Locale) => void; |
| toggleLocale: () => void; |
| t: Dict; |
| }; |
|
|
| const I18nContext = createContext<I18nValue | null>(null); |
|
|
| function detectInitialLocale(): Locale { |
| if (typeof window === "undefined") return "es"; |
| const stored = window.localStorage.getItem(STORAGE_KEY); |
| if (stored === "es" || stored === "en") return stored; |
| const nav = window.navigator.language?.toLowerCase() ?? ""; |
| return nav.startsWith("es") ? "es" : "en"; |
| } |
|
|
| export function I18nProvider({ children }: { children: ReactNode }) { |
| const [locale, setLocaleState] = useState<Locale>(() => detectInitialLocale()); |
|
|
| useEffect(() => { |
| if (typeof document !== "undefined") { |
| document.documentElement.lang = locale; |
| } |
| if (typeof window !== "undefined") { |
| window.localStorage.setItem(STORAGE_KEY, locale); |
| } |
| }, [locale]); |
|
|
| const setLocale = useCallback((l: Locale) => setLocaleState(l), []); |
| const toggleLocale = useCallback( |
| () => setLocaleState((prev) => (prev === "es" ? "en" : "es")), |
| [] |
| ); |
|
|
| const value = useMemo<I18nValue>( |
| () => ({ locale, setLocale, toggleLocale, t: DICTIONARIES[locale] }), |
| [locale, setLocale, toggleLocale] |
| ); |
|
|
| return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>; |
| } |
|
|
| export function useI18n() { |
| const ctx = useContext(I18nContext); |
| if (!ctx) throw new Error("useI18n must be used within I18nProvider"); |
| return ctx; |
| } |
|
|