Files
mue/src/contexts/TranslationContext.jsx

135 lines
3.9 KiB
JavaScript

import {
createContext,
useContext,
useState,
useEffect,
useCallback,
useMemo,
useRef,
} from 'react';
import {
initTranslations,
loadTranslationWithFallback,
getLoadedTranslation,
} from 'lib/translations';
import variables from 'config/variables';
import EventBus from 'utils/eventbus';
const RTL_LANGUAGES = ['ar', 'arz', 'azb', 'fa', 'peo'];
const isRTLLanguage = (lang) => RTL_LANGUAGES.includes(lang.split('_')[0]);
const TranslationContext = createContext();
export function TranslationProvider({ children, initialLanguage, initialTranslations }) {
const [currentLanguage, setCurrentLanguage] = useState(initialLanguage);
const [isLoading, setIsLoading] = useState(false);
const i18nInstance = useRef(initTranslations(initialLanguage, initialTranslations));
useEffect(() => {
variables.language = i18nInstance.current;
variables.languagecode = currentLanguage;
document.documentElement.lang = currentLanguage.replace('_', '-');
document.documentElement.dir = isRTLLanguage(currentLanguage) ? 'rtl' : 'ltr';
}, [currentLanguage]);
const changeLanguage = useCallback(
async (newLanguage) => {
setIsLoading(true);
try {
const translations = await loadTranslationWithFallback(newLanguage);
const newI18n = initTranslations(newLanguage, translations);
const currentTabName = localStorage.getItem('tabName');
const oldDefaultTabName = i18nInstance.current?.getMessage(currentLanguage, 'tabname');
i18nInstance.current = newI18n;
variables.language = newI18n;
variables.languagecode = newLanguage;
document.documentElement.lang = newLanguage.replace('_', '-');
document.documentElement.dir = isRTLLanguage(newLanguage) ? 'rtl' : 'ltr';
if (currentTabName === oldDefaultTabName || !currentTabName) {
const loadedTranslation = getLoadedTranslation(newLanguage);
const newTabName =
loadedTranslation?.tabname || newI18n.getMessage(newLanguage, 'tabname') || 'Mue';
localStorage.setItem('tabName', newTabName);
document.title = newTabName;
}
localStorage.setItem('language', newLanguage);
localStorage.removeItem('currentWeather');
setCurrentLanguage(newLanguage);
} catch (error) {
console.error('Failed to load language:', error);
} finally {
setIsLoading(false);
}
},
[currentLanguage],
);
const t = useCallback(
(key, optional = {}) => {
if (!i18nInstance.current) {
return key;
}
try {
return i18nInstance.current.getMessage(currentLanguage, key, optional);
} catch (error) {
// Fallback to en_GB if the current language is not loaded yet
try {
return i18nInstance.current.getMessage('en_GB', key, optional);
} catch {
return key;
}
}
},
[currentLanguage],
);
useEffect(() => {
const handleLanguageChange = (data) => {
if (data?.language) {
changeLanguage(data.language);
}
};
EventBus.on('languageChange', handleLanguageChange);
return () => {
EventBus.off('languageChange', handleLanguageChange);
};
}, [changeLanguage]);
useEffect(() => {
variables.getMessage = (key, optional = {}) => t(key, optional);
}, [t]);
const value = useMemo(
() => ({
language: currentLanguage,
languagecode: currentLanguage,
changeLanguage,
isLoading,
t,
}),
[currentLanguage, changeLanguage, isLoading, t],
);
return <TranslationContext.Provider value={value}>{children}</TranslationContext.Provider>;
}
export function useTranslation() {
const context = useContext(TranslationContext);
if (!context) {
throw new Error('useTranslation must be used within a TranslationProvider');
}
return context;
}
export function useT() {
const { t } = useTranslation();
return t;
}