diff --git a/src/translate/I18Next.tsx b/src/translate/I18Next.tsx new file mode 100644 index 0000000..fddb5a5 --- /dev/null +++ b/src/translate/I18Next.tsx @@ -0,0 +1,73 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import Backend from 'i18next-http-backend'; // 引入 Backend 插件 +import { useEffect, useLayoutEffect, useState } from 'react'; + +type I18NextProviderProps = { + children: React.ReactNode; + basename?: string; + noUse?: boolean; +}; + +export const initI18n = async (basename: string) => { + // 初始化 i18n + return new Promise((resolve) => { + i18n + .use(Backend) // 使用 Backend 插件 + .use(initReactI18next) + .init( + { + backend: { + loadPath: `${basename}/locales/{{lng}}/{{ns}}.json`, // 指定 JSON 文件的路径 + }, + lng: 'zh', // 默认语言 + fallbackLng: 'en', // 备用语言 + interpolation: { + escapeValue: false, // react 已经安全地处理了转义 + }, + }, + (e) => { + console.log('e', e); + resolve(true); + }, + ); + }); +}; + +/** + * 国际化组件,初始化 + * @param props + * @returns + */ +export const I18NextProvider = (props: I18NextProviderProps) => { + const { children, basename, noUse } = props; + if (noUse) { + return <>{children}; + } + const [init, setInit] = useState(false); + useLayoutEffect(() => { + initCheck(); + }, []); + const initCheck = async () => { + let _currentBasename = ''; + if (typeof basename === 'undefined') { + const local = localStorage.getItem('locale-basename'); + if (local) { + _currentBasename = local; + } else { + _currentBasename = ''; + } + } else { + _currentBasename = basename; + } + if (_currentBasename === '/') { + _currentBasename = ''; + } + initI18n(_currentBasename); + setInit(true); + }; + if (!init) { + return <>; + } + return <>{children}; +}; diff --git a/src/translate/index.tsx b/src/translate/index.tsx new file mode 100644 index 0000000..067e686 --- /dev/null +++ b/src/translate/index.tsx @@ -0,0 +1,4 @@ +import { useTranslation } from 'react-i18next'; +export * from './I18Next.tsx'; + +export { useTranslation };