feat(i18n): add i18n types, config, provider, context, and custom hook
This commit is contained in:
15
src/contexts/LangaugeContext.ts
Normal file
15
src/contexts/LangaugeContext.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { type Language } from '@/types/language';
|
||||
import { createContext } from 'react';
|
||||
|
||||
export interface LangaugeContextModel {
|
||||
language: Language;
|
||||
changeLanguage: (langauge: Language) => void;
|
||||
t: (key: string) => string;
|
||||
}
|
||||
|
||||
// The context is used by the LangaugeProvider
|
||||
export const LangaugeContext = createContext<LangaugeContextModel>({
|
||||
language: 'fa',
|
||||
changeLanguage: () => {},
|
||||
t: () => '',
|
||||
});
|
||||
9
src/hooks/useLanguage.ts
Normal file
9
src/hooks/useLanguage.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import {
|
||||
LangaugeContext,
|
||||
type LangaugeContextModel,
|
||||
} from '@/contexts/LangaugeContext';
|
||||
import { useContext } from 'react';
|
||||
|
||||
export const useLangauge = (): LangaugeContextModel => {
|
||||
return useContext(LangaugeContext);
|
||||
};
|
||||
17
src/hooks/useLocalStorage.ts
Normal file
17
src/hooks/useLocalStorage.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const useLocalStorage = <T extends string>(
|
||||
key: string,
|
||||
defaultValue: T,
|
||||
): [T, (value: T) => void] => {
|
||||
const localValueOrDefault: T = (localStorage.getItem(key) ??
|
||||
defaultValue) as T;
|
||||
|
||||
const [localValue, setLocalValue] = useState<T>(localValueOrDefault);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem(key, localValue);
|
||||
}, [localValue, key]);
|
||||
|
||||
return [localValue, setLocalValue];
|
||||
};
|
||||
18
src/i18n.ts
Normal file
18
src/i18n.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import i18n from 'i18next';
|
||||
import i18nBackend from 'i18next-http-backend';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
i18n
|
||||
.use(i18nBackend)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
lng: 'en',
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
backend: {
|
||||
loadPath: `${window.location.origin}/i18n/{{lng}}.json`,
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
@@ -2,9 +2,12 @@ import { StrictMode } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import { LanguageProvider } from './providers/LanguageProvider';
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
<LanguageProvider>
|
||||
<App />
|
||||
</LanguageProvider>
|
||||
</StrictMode>,
|
||||
);
|
||||
|
||||
47
src/providers/LanguageProvider.tsx
Normal file
47
src/providers/LanguageProvider.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { Language } from '@/types/language';
|
||||
import { changeLanguage } from 'i18next';
|
||||
import { useLayoutEffect, type JSX, type PropsWithChildren } from 'react';
|
||||
import { initReactI18next, useTranslation } from 'react-i18next';
|
||||
import { useLocalStorage } from '@/hooks/useLocalStorage';
|
||||
import { LangaugeContext } from '@/contexts/LangaugeContext';
|
||||
import i18n from 'i18next';
|
||||
import i18nBackend from 'i18next-http-backend';
|
||||
|
||||
i18n
|
||||
.use(i18nBackend)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
lng: 'en',
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
backend: {
|
||||
loadPath: `${window.location.origin}/i18n/{{lng}}.json`,
|
||||
},
|
||||
});
|
||||
|
||||
export const LanguageProvider = (props: PropsWithChildren): JSX.Element => {
|
||||
const [currentLanguage, setCurrentLangauge] = useLocalStorage<Language>(
|
||||
'language',
|
||||
'fa',
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
changeLanguage(currentLanguage);
|
||||
document.documentElement.dir = currentLanguage === 'fa' ? 'rtl' : 'ltr';
|
||||
document.documentElement.lang = currentLanguage;
|
||||
}, [currentLanguage]);
|
||||
|
||||
return (
|
||||
<LangaugeContext.Provider
|
||||
value={{
|
||||
language: currentLanguage,
|
||||
changeLanguage: setCurrentLangauge,
|
||||
t: t,
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</LangaugeContext.Provider>
|
||||
);
|
||||
};
|
||||
1
src/types/language.ts
Normal file
1
src/types/language.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type Language = 'en' | 'fa';
|
||||
Reference in New Issue
Block a user