import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import de from "@/locales/de.json"; import en from "@/locales/en.json"; import es from "@/locales/es.json"; import fr from "@/locales/fr.json"; import it from "@/locales/it.json"; import sv from "@/locales/sv.json"; const bundles = { en, es, fr, de, it, sv } as const; export type Locale = keyof typeof bundles; export type MessageKey = string; export type LocaleOption = { code: Locale; name: string; emoji: string; }; const localeOptions: LocaleOption[] = [ { code: "en", name: "English", emoji: "🇺🇸" }, { code: "es", name: "Español", emoji: "🇪🇸" }, { code: "fr", name: "Français", emoji: "🇫🇷" }, { code: "de", name: "Deutsch", emoji: "🇩🇪" }, { code: "it", name: "Italiano", emoji: "🇮🇹" }, { code: "sv", name: "Svenska", emoji: "🇸🇪" }, ]; export function useI18n(defaultLocale: Locale = "en") { const [locale, setLocale] = useState(defaultLocale); const hasDetectedLocale = useRef(false); useEffect(() => { if (hasDetectedLocale.current) return; hasDetectedLocale.current = true; const navLangs = typeof navigator !== "undefined" ? navigator.languages || [navigator.language] : []; const mapToLocale = (lang: string | undefined | null): Locale | null => { if (!lang) return null; const lower = lang.toLowerCase(); if (lower.startsWith("es")) return "es"; if (lower.startsWith("fr")) return "fr"; if (lower.startsWith("de")) return "de"; if (lower.startsWith("it")) return "it"; if (lower.startsWith("sv")) return "sv"; if (lower.startsWith("en")) return "en"; return null; }; const detected = navLangs.map((l) => mapToLocale(l)).find(Boolean); if (detected && detected !== locale) { setLocale(detected); } }, [locale]); const t = useCallback( (key: MessageKey, vars?: Record): string => { const parts = key.split("."); const dict = bundles[locale] ?? bundles.en; const fallbackDict = bundles.en; const resolveKey = (source: unknown) => parts.reduce( (acc, part) => acc && typeof acc === "object" ? (acc as Record)[part] : undefined, source ); const value = resolveKey(dict) ?? resolveKey(fallbackDict); const text = typeof value === "string" ? value : key; if (!vars) return text; return text.replace(/\{(\w+)\}/g, (_: string, k: string) => (vars[k] ? vars[k] : `{${k}}`)); }, [locale] ); const options = useMemo(() => localeOptions, []); return { locale, setLocale, t, localeOptions: options }; }