"use client"; import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode, } from "react"; import { isChinaUser } from "is-china-user"; import { dictionaries, type Dictionary, type Locale } from "~/lib/i18n"; const STORAGE_KEY = "nomadro-locale"; type LocaleContextValue = { locale: Locale; isChina: boolean; ready: boolean; t: Dictionary; setLocale: (locale: Locale) => void; }; const LocaleContext = createContext(null); function isLocale(value: string | null): value is Locale { return value === "zh" || value === "en"; } export function LocaleProvider({ children }: { children: ReactNode }) { const [locale, setLocaleState] = useState("zh"); const [ready, setReady] = useState(false); useEffect(() => { let cancelled = false; try { // Prefer auto detection; only keep a locale if user unlocked and switched. const unlocked = window.sessionStorage.getItem("nomadro-lang-unlock") === "1"; const saved = window.localStorage.getItem(STORAGE_KEY); if (unlocked && isLocale(saved)) { if (!cancelled) { setLocaleState(saved); setReady(true); } return; } const china = Boolean(isChinaUser()); if (!cancelled) { setLocaleState(china ? "zh" : "en"); setReady(true); } } catch { if (!cancelled) { setLocaleState("zh"); setReady(true); } } return () => { cancelled = true; }; }, []); useEffect(() => { if (!ready) return; document.documentElement.lang = dictionaries[locale].htmlLang; }, [locale, ready]); const setLocale = useCallback((next: Locale) => { setLocaleState(next); try { window.localStorage.setItem(STORAGE_KEY, next); } catch { // ignore storage failures } }, []); const value = useMemo( () => ({ locale, isChina: locale === "zh", ready, t: dictionaries[locale], setLocale, }), [locale, ready, setLocale], ); return ( {children} ); } export function useLocale() { const ctx = useContext(LocaleContext); if (!ctx) { throw new Error("useLocale must be used within LocaleProvider"); } return ctx; }