import React from 'react'; import { DEFAULT_LOCALE, SUPPORTED_LOCALES, type LocaleCode, isLocaleCode } from './messages'; export interface LocaleContextValue { locale: LocaleCode; setLocale: (next: LocaleCode) => void; resetLocale: () => void; hydrated: boolean; defaultLocale: LocaleCode; storageKey: string; availableLocales: typeof SUPPORTED_LOCALES; } const LocaleContext = React.createContext(undefined); function sanitizeLocale(value: string | null | undefined, fallback: LocaleCode = DEFAULT_LOCALE): LocaleCode { if (value && isLocaleCode(value)) { return value; } return fallback; } export interface LocaleProviderProps { children: React.ReactNode; defaultLocale?: LocaleCode; storageKey?: string; } export function LocaleProvider({ children, defaultLocale = DEFAULT_LOCALE, storageKey = 'guestLocale_global', }: LocaleProviderProps) { const resolvedDefault = sanitizeLocale(defaultLocale, DEFAULT_LOCALE); const [locale, setLocaleState] = React.useState(resolvedDefault); const [userLocale, setUserLocale] = React.useState(null); const [hydrated, setHydrated] = React.useState(false); React.useEffect(() => { setHydrated(false); if (typeof window === 'undefined') { setLocaleState(resolvedDefault); setUserLocale(null); setHydrated(true); return; } let stored: string | null = null; try { stored = window.localStorage.getItem(storageKey); } catch (error) { console.warn('Failed to read stored locale', error); } const nextLocale = sanitizeLocale(stored, resolvedDefault); setLocaleState(nextLocale); setUserLocale(isLocaleCode(stored) ? stored : null); setHydrated(true); }, [storageKey, resolvedDefault]); React.useEffect(() => { if (!hydrated || userLocale !== null) { return; } setLocaleState(resolvedDefault); }, [hydrated, userLocale, resolvedDefault]); const setLocale = React.useCallback( (next: LocaleCode) => { const safeLocale = sanitizeLocale(next, resolvedDefault); setLocaleState(safeLocale); setUserLocale(safeLocale); if (typeof window !== 'undefined') { try { window.localStorage.setItem(storageKey, safeLocale); } catch (error) { console.warn('Failed to persist locale', error); } } }, [storageKey, resolvedDefault], ); const resetLocale = React.useCallback(() => { setUserLocale(null); setLocaleState(resolvedDefault); if (typeof window !== 'undefined') { try { window.localStorage.removeItem(storageKey); } catch (error) { console.warn('Failed to clear stored locale', error); } } }, [resolvedDefault, storageKey]); const value = React.useMemo( () => ({ locale, setLocale, resetLocale, hydrated, defaultLocale: resolvedDefault, storageKey, availableLocales: SUPPORTED_LOCALES, }), [locale, setLocale, resetLocale, hydrated, resolvedDefault, storageKey], ); return {children}; } export function useLocale(): LocaleContextValue { const ctx = React.useContext(LocaleContext); if (!ctx) { throw new Error('useLocale must be used within a LocaleProvider'); } return ctx; } export function useOptionalLocale(): LocaleContextValue | undefined { return React.useContext(LocaleContext); }