使用react-router-dom的Route组件无法通过react-i18next国际化怎么办?
我正在开发一个应用,除了Route渲染的组件外,其他各处的国际化功能均正常运行。
i18n.js配置文件
import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import Backend from 'i18next-http-backend'; i18n .use(Backend) .use(initReactI18next) .init({ debug: true, lng: 'en', fallbackLng: 'en', whitelist: ['en', 'bg'], interpolation: { escapeValue: false, }, backend: { loadPath: '/locales/{{lng}}/{{ns}}.json', }, react: { useSuspense: false, }, }); export default i18n;
依赖版本
{ "i18next": "^19.5.0", "i18next-http-backend": "^1.4.1", "i18next-sync-fs-backend": "^1.1.1", "react-i18next": "^11.7.0" }
App.jsx中的路由代码
<Route exact path="/login" component={Login} />
index.js文件
import React, { Suspense } from 'react'; import { BrowserRouter } from "react-router-dom"; import ReactDOM from 'react-dom'; import Spinner from 'react-bootstrap/Spinner'; import fontawesome from '@fortawesome/fontawesome'; import {faPlusCircle} from '@fortawesome/free-solid-svg-icons'; import App from './App'; import * as serviceWorker from "./serviceWorker"; import { I18nextProvider } from 'react-i18next'; import i18n from './i18n' fontawesome.library.add(faPlusCircle); ReactDOM.render( <BrowserRouter> <I18nextProvider i18n={i18n}> <Suspense fallback={<Spinner animation="grow" variant="primary" />}> <App /> </Suspense> </I18nextProvider> </BrowserRouter>, document.getElementById('root') ); serviceWorker.unregister();
控制台警告信息
i18next.js:22 i18next: hasLoadedNamespace: i18next was not initialized undefined
output @ i18next.js:22
i18next.js:22 i18next::translator: key "bg" for languages "en" won't get resolved as namespace "language" was not yet loaded This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!
解决方案
1. 等待i18n初始化完成后再渲染应用
i18n.init是异步操作,当前代码直接渲染App会导致路由组件在i18n未初始化完成时就调用t函数。修改index.js,利用init返回的Promise等待初始化完成:
import React, { Suspense } from 'react'; import { BrowserRouter } from "react-router-dom"; import ReactDOM from 'react-dom'; import Spinner from 'react-bootstrap/Spinner'; import fontawesome from '@fortawesome/fontawesome'; import {faPlusCircle} from '@fortawesome/free-solid-svg-icons'; import App from './App'; import * as serviceWorker from "./serviceWorker"; import { I18nextProvider } from 'react-i18next'; import i18n from './i18n' fontawesome.library.add(faPlusCircle); // 等待i18n初始化完成 i18n.init().then(() => { ReactDOM.render( <BrowserRouter> <I18nextProvider i18n={i18n}> <Suspense fallback={<Spinner animation="grow" variant="primary" />}> <App /> </Suspense> </I18nextProvider> </BrowserRouter>, document.getElementById('root') ); }); serviceWorker.unregister();
2. 规范路由组件的国际化调用方式
确保Login组件中没有在初始化阶段(如constructor、无依赖项的useEffect)同步调用t函数:
- 函数组件使用
useTranslation钩子,自动处理命名空间加载:import { useTranslation } from 'react-i18next'; function Login() { const { t } = useTranslation('language'); // 明确指定命名空间 return <div>{t('bg')}</div>; } - 类组件使用
withTranslation高阶组件包裹:import { withTranslation } from 'react-i18next'; class Login extends React.Component { render() { const { t } = this.props; return <div>{t('bg')}</div>; } } export default withTranslation('language')(Login);
3. 确认命名空间配置
警告中提到namespace "language"未加载,需确保该命名空间被正确配置:
- 在i18n.init中添加默认命名空间:
i18n.init({ // ...其他配置 defaultNS: 'language', ns: ['language'] // 明确声明要加载的命名空间 }); - 检查
/locales/en/language.json和/locales/bg/language.json文件是否存在且JSON格式正确。
内容的提问来源于stack exchange,提问作者FireAndBlood

