'use client'; import React, { createContext, useContext, useState, useCallback, ReactNode, useEffect } from 'react'; import en from '@/i18n/en.json'; import es from '@/i18n/es.json'; import ptBR from '@/i18n/pt-BR.json'; type Locale = 'en' | 'es' | 'pt-BR'; interface I18nContextType { locale: Locale; setLocale: (locale: Locale) => void; t: (key: string, params?: Record) => string; } const dictionaries: Record = { en, es, 'pt-BR': ptBR, }; const I18nContext = createContext(null); const localeStorageKey = 'locale'; const normalizeLocale = (language: string): Locale => { if (language.startsWith('pt')) return 'pt-BR'; if (language.startsWith('es')) return 'es'; return 'en'; }; const getInitialLocale = (): Locale => { if (typeof window === 'undefined') return 'en'; const storedLocale = localStorage.getItem(localeStorageKey); if (storedLocale && storedLocale in dictionaries) { return storedLocale as Locale; } // Default to English instead of browser language for consistency return 'en'; }; export function I18nProvider({ children }: { children: ReactNode }) { // FIX: Initialize with 'en' to match Server-Side Rendering (SSR) // This prevents hydration mismatch errors. const [locale, setLocaleState] = useState('en'); const setLocale = (newLocale: Locale) => { console.log(`[I18n] Setting locale to: ${newLocale}`); setLocaleState(newLocale); }; const t = useCallback((key: string, params?: Record) => { const keys = key.split('.'); let value: unknown = dictionaries[locale]; for (const k of keys) { if (value && typeof value === 'object' && value !== null && k in value) { value = (value as Record)[k]; } else { return key; // Return key if not found } } if (typeof value !== 'string') return key; // Replace parameters like {count}, {time}, {year} if (params) { return Object.entries(params).reduce( (str, [paramKey, paramValue]) => str.replace(`{${paramKey}}`, String(paramValue)), value ); } return value; }, [locale]); // Sync from localStorage on mount (Client-side only) useEffect(() => { const stored = getInitialLocale(); if (stored !== 'en') { console.log('[I18n] Restoring locale from storage on client:', stored); setLocaleState(stored); } }, []); useEffect(() => { if (typeof window === 'undefined') return; localStorage.setItem(localeStorageKey, locale); document.documentElement.lang = locale; }, [locale]); return ( {children} ); } export function useI18n() { const context = useContext(I18nContext); if (!context) { throw new Error('useI18n must be used within an I18nProvider'); } return context; } export function useTranslation() { const { t, locale, setLocale } = useI18n(); return { t, locale, setLocale }; } export const locales: { code: Locale; name: string; flag: string }[] = [ { code: 'en', name: 'English', flag: '🇺🇸' }, { code: 'es', name: 'Español', flag: '🇪🇸' }, { code: 'pt-BR', name: 'Português', flag: '🇧🇷' }, ];