UNPKG

fast-react-i18n

Version:
145 lines (140 loc) 4.03 kB
// src/I18nProvider.tsx import { createContext, useContext, useEffect, useRef, useState } from "react"; // src/loadTranslations.ts var loadTranslations = async (path, locale) => { try { const res = await fetch(`${path}/${locale}.json`); if (!res.ok) throw new Error(`No se pudo cargar: ${path}/${locale}.json`); return await res.json(); } catch { console.warn(`[i18n] No se pudo cargar: ${path}/${locale}.json`); return {}; } }; // src/utils/load.ts async function load(path, locale, fallbackLocale) { try { return await loadTranslations(path, locale); } catch (error) { console.warn(`[i18n] No se pudo cargar ${locale}, intentando fallback...`); if (fallbackLocale && fallbackLocale !== locale) { try { return await loadTranslations(path, fallbackLocale); } catch (fallbackError) { console.error( `[i18n] Tampoco se pudo cargar el fallback: ${fallbackLocale}`, fallbackError ); } } return {}; } } // src/I18nProvider.tsx import { jsx } from "react/jsx-runtime"; var I18nContext = createContext({ locale: "en", translations: {}, setLocale: () => { }, setTranslations: () => { } }); var useI18nContext = () => useContext(I18nContext); var I18nProvider = ({ initialLocale, fallbackLocale, translationsPath, persist = false, children }) => { const [locale, setLocale] = useState(initialLocale || "auto"); const [translations, setTranslations] = useState({}); const cacheRef = useRef(/* @__PURE__ */ new Map()); useEffect(() => { const resolvedLocale = locale === "auto" ? typeof navigator !== "undefined" ? navigator.language.split("-")[0] : "en" : locale; if (locale === "auto") { setLocale(resolvedLocale); } async function fetchTranslations() { if (persist) { const cached = localStorage.getItem(`i18n_${resolvedLocale}`); if (cached) { setTranslations(JSON.parse(cached)); return; } } const cachedInMemory = cacheRef.current.get(resolvedLocale); if (cachedInMemory) { setTranslations(cachedInMemory); return; } const res = await load(translationsPath, resolvedLocale, fallbackLocale); setTranslations(res); cacheRef.current.set(resolvedLocale, res); if (persist) { localStorage.setItem(`i18n_${resolvedLocale}`, JSON.stringify(res)); } } fetchTranslations(); }, [locale, translationsPath, fallbackLocale, persist]); return /* @__PURE__ */ jsx( I18nContext.Provider, { value: { locale, translations, setLocale, setTranslations }, children } ); }; // src/utils/functions.ts var clearTranslationsCache = () => { Object.keys(localStorage).forEach((key) => { if (key.startsWith("i18n_")) { localStorage.removeItem(key); } }); }; var useTranslation = () => { const { translations } = useI18nContext(); return { translations }; }; var detectUserLocale = () => { if (typeof window === "undefined") return "en"; const urlParams = new URLSearchParams(window.location.search); const langQuery = urlParams.get("lang"); if (langQuery) return langQuery.split("-")[0]; const match = document.cookie.match(/(^| )lang=([^;]+)/); if (match) return match[2].split("-")[0]; if (navigator.language) return navigator.language.split("-")[0]; return "en"; }; var useForceReloadTranslations = () => { const { locale, setTranslations } = useI18nContext(); return async (path, fallbackLocale) => { const data = await load(path, locale, fallbackLocale); setTranslations(data); }; }; var loadAvailableLocales = async (path) => { try { const res = await fetch(`${path}/locales.json`); if (!res.ok) throw new Error("Failed to load locales"); return await res.json(); } catch { return []; } }; export { I18nProvider, clearTranslationsCache, detectUserLocale, loadAvailableLocales, useForceReloadTranslations, useTranslation };