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
JavaScript
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);