File size: 1,692 Bytes
21e8095 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | 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;
}
|