UNPKG

pagamio-frontend-commons-lib

Version:

Pagamio library for Frontend reusable components like the form engine and table container

152 lines (151 loc) 6.07 kB
import { jsx as _jsx } from "react/jsx-runtime"; import React, { createContext, useContext, useEffect, useState } from 'react'; import { loadTranslations } from '../utils'; const DEFAULT_LOCALE = 'en'; const LOCALE_STORAGE_KEY = 'pagamio-locale'; const defaultContextValue = { locale: DEFAULT_LOCALE, setLocale: () => { }, t: (key, defaultValue, variables) => defaultValue ?? key, isLoading: true, availableLocales: [DEFAULT_LOCALE], }; export const TranslationContext = createContext(defaultContextValue); export const TranslationProvider = ({ children, defaultLocale = DEFAULT_LOCALE, localeData, loadPath, }) => { // Get initial locale from localStorage or use browser's language or fallback to default const getInitialLocale = () => { if (typeof window === 'undefined') return defaultLocale; try { const savedLocale = localStorage.getItem(LOCALE_STORAGE_KEY); if (savedLocale) return savedLocale; // Try to use browser language as fallback const browserLang = navigator.language.split('-')[0]; return browserLang || defaultLocale; } catch (e) { // In case localStorage is not available (e.g., incognito mode) console.log('Failed to access localStorage:', e); return defaultLocale; } }; const [localeState, setLocaleState] = useState(getInitialLocale); const [translations, setTranslations] = useState({}); const [isLoading, setIsLoading] = useState(true); const [availableLocales, setAvailableLocales] = useState([defaultLocale]); // Custom setLocale function that also updates localStorage const setLocale = (newLocale) => { try { localStorage.setItem(LOCALE_STORAGE_KEY, newLocale); } catch (e) { console.warn('Failed to store locale preference:', e); } setLocaleState(newLocale); }; useEffect(() => { // If locale data is provided directly, use it if (localeData) { const translationsMap = localeData.reduce((acc, { locale, messages }) => { acc[locale] = messages; return acc; }, {}); setTranslations(translationsMap); setAvailableLocales(localeData.map((data) => data.locale)); setIsLoading(false); } // Otherwise load from file path if provided else if (loadPath) { setIsLoading(true); loadTranslations(localeState, loadPath) .then(({ messages, availableLocales }) => { setTranslations((prevTranslations) => ({ ...prevTranslations, [localeState]: messages, })); setAvailableLocales(availableLocales); setIsLoading(false); }) .catch((error) => { console.error('Failed to load translations:', error); setIsLoading(false); }); } else { setIsLoading(false); } }, [localeData, loadPath]); useEffect(() => { if (localeData && localeState !== defaultLocale) { // Make sure we have the translations for the current locale loaded const localeExists = localeData.some((data) => data.locale === localeState); if (localeExists && !translations[localeState]) { const localeMessages = localeData.find((data) => data.locale === localeState)?.messages; if (localeMessages) { setTranslations((prev) => ({ ...prev, [localeState]: localeMessages, })); } } } }, [localeState, localeData, translations]); // When locale changes, load translations if they're not already loaded useEffect(() => { if (!translations[localeState] && loadPath) { setIsLoading(true); loadTranslations(localeState, loadPath) .then(({ messages }) => { setTranslations((prevTranslations) => ({ ...prevTranslations, [localeState]: messages, })); setIsLoading(false); }) .catch((error) => { console.error('Failed to load translations:', error); setIsLoading(false); }); } }, [localeState, loadPath, translations]); const getNestedTranslation = (obj, path) => { let current = obj; for (const segment of path) { if (current[segment] === undefined) { return undefined; } current = current[segment]; } return typeof current === 'string' ? current : undefined; }; const t = (key, defaultValue, variables) => { const currentTranslations = translations[localeState] ?? {}; const keyPath = key.split('.'); let result = getNestedTranslation(currentTranslations, keyPath); if (!result) { if (defaultValue) result = defaultValue; else { console.warn(`Translation key not found: ${key}`); result = key; } } // Replace variables in the string if provided if (variables && result) { Object.entries(variables).forEach(([varName, value]) => { result = result.replace(new RegExp(`{${varName}}`, 'g'), String(value)); }); } return result; }; const contextValue = React.useMemo(() => ({ locale: localeState, setLocale, t, isLoading, availableLocales, }), [localeState, t, isLoading, availableLocales]); return _jsx(TranslationContext.Provider, { value: contextValue, children: children }); }; export const useTranslationContext = () => useContext(TranslationContext);