diff --git a/frontend/src/lib/i18n.tsx b/frontend/src/lib/i18n.tsx new file mode 100644 index 0000000..c9a3d5e --- /dev/null +++ b/frontend/src/lib/i18n.tsx @@ -0,0 +1,76 @@ +'use client'; + +import React, { createContext, useContext, useState, useCallback, ReactNode } 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); + +export function I18nProvider({ children }: { children: ReactNode }) { + const [locale, setLocale] = useState('en'); + + const t = useCallback((key: string, params?: Record): string => { + const keys = key.split('.'); + let value: any = dictionaries[locale]; + + for (const k of keys) { + if (value && typeof value === 'object' && k in value) { + value = value[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]); + + 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: '🇧🇷' }, +];