2025-07-07 17:35:46 +05:00
|
|
|
'use client'
|
|
|
|
|
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
|
|
|
|
import { defaultLanguage, Language, Namespace, namespaces, supportedLanguages } from './config';
|
|
|
|
|
|
|
|
|
|
type Translation = Record<string, string>;
|
|
|
|
|
type NamespaceTranslations = Record<Namespace, Translation>;
|
|
|
|
|
type LanguageTranslations = Record<Language, NamespaceTranslations>;
|
|
|
|
|
|
|
|
|
|
const I18nContext = createContext<{
|
|
|
|
|
language: Language;
|
|
|
|
|
t: (key: string, namespace?: Namespace) => string;
|
|
|
|
|
}>({
|
|
|
|
|
language: defaultLanguage,
|
|
|
|
|
t: (key: string) => key,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
interface I18nProviderProps {
|
|
|
|
|
children: React.ReactNode;
|
|
|
|
|
initialLanguage: Language;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const I18nProvider = ({ children, initialLanguage }: I18nProviderProps) => {
|
|
|
|
|
const [language, setLanguage] = useState<Language>(initialLanguage);
|
|
|
|
|
const [translations, setTranslations] = useState<LanguageTranslations>({} as LanguageTranslations);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Загрузка переводов
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const loadTranslations = async () => {
|
|
|
|
|
const newTranslations: LanguageTranslations = { ...translations };
|
|
|
|
|
|
|
|
|
|
await Promise.all(
|
|
|
|
|
(Object.keys(supportedLanguages) as Language[]).map(async (lang) => {
|
|
|
|
|
if (!newTranslations[lang]) {
|
|
|
|
|
newTranslations[lang] = {} as NamespaceTranslations;
|
|
|
|
|
|
|
|
|
|
await Promise.all(
|
|
|
|
|
namespaces.map(async (ns) => {
|
|
|
|
|
try {
|
|
|
|
|
const data = await import(`../../../public/locales/${lang}/${ns}.json`);
|
|
|
|
|
newTranslations[lang][ns] = data.default || data;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(`Failed to load ${lang}/${ns} translations`, e);
|
|
|
|
|
newTranslations[lang][ns] = {};
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
setTranslations(newTranslations);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
loadTranslations();
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
2025-11-19 14:41:08 +05:00
|
|
|
useEffect(() => {
|
|
|
|
|
setLanguage(initialLanguage);
|
|
|
|
|
}, [initialLanguage]);
|
|
|
|
|
|
2025-07-07 17:35:46 +05:00
|
|
|
const t = useMemo(() => {
|
|
|
|
|
return (key: string, namespace: Namespace = 'common') => {
|
|
|
|
|
return translations[language]?.[namespace]?.[key] || key;
|
|
|
|
|
};
|
|
|
|
|
}, [language, translations]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const contextValue = useMemo(() => ({
|
|
|
|
|
language,
|
|
|
|
|
t,
|
|
|
|
|
}), [language, t]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<I18nContext.Provider value={contextValue}>
|
|
|
|
|
{children}
|
|
|
|
|
</I18nContext.Provider>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useI18n = () => {
|
|
|
|
|
const context = useContext(I18nContext);
|
|
|
|
|
if (!context) {
|
|
|
|
|
throw new Error('useI18n must be used within I18nProvider');
|
|
|
|
|
}
|
|
|
|
|
return context;
|
2025-11-19 14:41:08 +05:00
|
|
|
};
|