在带有装饰器和 HOC 的 class 组件中使用 react-i18next
Use react-i18next in class components with decorators and HOC
我正在尝试在我的 React 项目中实现 i18n,该项目也在 react-i18next
的帮助下使用 Redux。
在这个项目中,我们使用 class 个带有装饰器的组件。
最初,我想尝试 react-i18next
v10,但由于它依赖于钩子,而我不能在 class 组件中使用它们,所以这对我来说是不可能的。
回到旧版 v9,我按照分步指南 (https://react.i18next.com/legacy-v9/step-by-step-guide) 执行了以下步骤:
- 创建了带有翻译的
i18n.js
配置文件
- 用
i18nextProvider
包装了我的根容器
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<I18nextProvider i18n={i18n}>
<RootContainer />
</I18nextProvider>
</Router>
</Provider>,
$root,
);
- 使用
withNamespaces()
HOC 包装了一个简单的组件,它是 RootContainer
的子组件,但使用装饰器语法
@withNamespaces()
export default class SimpleComponent extends React.PureComponent {
// (... component class code ...)
}
在没有装饰器的情况下等效于以下内容:
class SimpleComponent extends React.PureComponent {
// (... component class code ...)
}
export default withNamespaces()(SimpleComponent);
我一定是遗漏了什么,因为我在 SSR 期间收到以下错误:
react-i18next:: You will need pass in an i18next instance either by props, using I18nextProvider or by using i18nextReactModule. Learn more https://react.i18next.com/components/overview#getting-the-i-18-n-function-into-the-flow
0|ssr-dev | TypeError: Cannot read property 'wait' of null
0|ssr-dev | at NamespacesConsumerComponent.render (/client/node_modules/react-i18next/dist/commonjs/NamespacesConsumer.js:220:33)
问题是,如果我删除组件 class 上的 @withNamespaces()
HOC,我将不再遇到此错误,但组件的 props 中没有 {t, i18n}
因此无法翻译任何内容。
此外,不幸的是,错误中给定的 URL 已不存在。
正如我从文档中了解到的那样,<I18nextProvider>
应该将 {t, i18n}
值传递到组件树下,这不是我的情况。
我发现自己陷入无法使用 v10(我们有很多组件,目前我不能将它们全部重构为功能组件)和无法使 v9 工作之间。
我 运行 别无选择,如果您遇到过类似问题,我可以事后回顾一下。
提前致谢。
对于任何想知道的人,我通过包装 <RootContainer>
child 而不是将 <RootContainer>
本身包装在渲染器方法中来让它工作,这给我留下了如下内容:
- 渲染器
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<RootContainer />
</Router>
</Provider>,
$root,
);
- 根容器
import i18n from "../core/translations/i18n";
import {I18nextProvider} from "react-i18next";
@connectWithStore(mapStateToProps, mapActionsToProps)
export default class RootContainer extends React.PureComponent {
// (... class code ...)
render {
return (
<I18nextProvider i18n={i18n}>
<div>
<SimpleComponent/>
</div>
</I18nextProvider>
);
}
}
- 简单元素
import {withNamespaces} from "react-i18next";
@withNamespaces()
export default class SimpleComponent extends React.PureComponent {
// (... class code ...)
componentDidMount() {
// Successfully logging the values below
console.warn("Got i18n props?", {
t: this.props.t,
i18n: this.props.i18n,
});
}
}
唯一的区别是我的渲染器是一个函数,而不是一个组件本身,而 RootContainer
是一个 fully-fledged React 组件(准确地说是 PureComponent)。也许它与渲染链有关,不确定,但它仍然按预期方式工作。
我通过这样做设法在 class 中使用了最新版本的 react-i18next :
import { withTranslation } from 'react-i18next';
class RootContainer extends React.Component {
constructor(props) {
super(props);
}
render() {
<span>{this.props.t('Home')}</span>
}
}
我正在尝试在我的 React 项目中实现 i18n,该项目也在 react-i18next
的帮助下使用 Redux。
在这个项目中,我们使用 class 个带有装饰器的组件。
最初,我想尝试 react-i18next
v10,但由于它依赖于钩子,而我不能在 class 组件中使用它们,所以这对我来说是不可能的。
回到旧版 v9,我按照分步指南 (https://react.i18next.com/legacy-v9/step-by-step-guide) 执行了以下步骤:
- 创建了带有翻译的
i18n.js
配置文件 - 用
i18nextProvider
包装了我的根容器
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<I18nextProvider i18n={i18n}>
<RootContainer />
</I18nextProvider>
</Router>
</Provider>,
$root,
);
- 使用
withNamespaces()
HOC 包装了一个简单的组件,它是RootContainer
的子组件,但使用装饰器语法
@withNamespaces()
export default class SimpleComponent extends React.PureComponent {
// (... component class code ...)
}
在没有装饰器的情况下等效于以下内容:
class SimpleComponent extends React.PureComponent {
// (... component class code ...)
}
export default withNamespaces()(SimpleComponent);
我一定是遗漏了什么,因为我在 SSR 期间收到以下错误:
react-i18next:: You will need pass in an i18next instance either by props, using I18nextProvider or by using i18nextReactModule. Learn more https://react.i18next.com/components/overview#getting-the-i-18-n-function-into-the-flow
0|ssr-dev | TypeError: Cannot read property 'wait' of null
0|ssr-dev | at NamespacesConsumerComponent.render (/client/node_modules/react-i18next/dist/commonjs/NamespacesConsumer.js:220:33)
问题是,如果我删除组件 class 上的 @withNamespaces()
HOC,我将不再遇到此错误,但组件的 props 中没有 {t, i18n}
因此无法翻译任何内容。
此外,不幸的是,错误中给定的 URL 已不存在。
正如我从文档中了解到的那样,<I18nextProvider>
应该将 {t, i18n}
值传递到组件树下,这不是我的情况。
我发现自己陷入无法使用 v10(我们有很多组件,目前我不能将它们全部重构为功能组件)和无法使 v9 工作之间。
我 运行 别无选择,如果您遇到过类似问题,我可以事后回顾一下。
提前致谢。
对于任何想知道的人,我通过包装 <RootContainer>
child 而不是将 <RootContainer>
本身包装在渲染器方法中来让它工作,这给我留下了如下内容:
- 渲染器
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<RootContainer />
</Router>
</Provider>,
$root,
);
- 根容器
import i18n from "../core/translations/i18n";
import {I18nextProvider} from "react-i18next";
@connectWithStore(mapStateToProps, mapActionsToProps)
export default class RootContainer extends React.PureComponent {
// (... class code ...)
render {
return (
<I18nextProvider i18n={i18n}>
<div>
<SimpleComponent/>
</div>
</I18nextProvider>
);
}
}
- 简单元素
import {withNamespaces} from "react-i18next";
@withNamespaces()
export default class SimpleComponent extends React.PureComponent {
// (... class code ...)
componentDidMount() {
// Successfully logging the values below
console.warn("Got i18n props?", {
t: this.props.t,
i18n: this.props.i18n,
});
}
}
唯一的区别是我的渲染器是一个函数,而不是一个组件本身,而 RootContainer
是一个 fully-fledged React 组件(准确地说是 PureComponent)。也许它与渲染链有关,不确定,但它仍然按预期方式工作。
我通过这样做设法在 class 中使用了最新版本的 react-i18next :
import { withTranslation } from 'react-i18next';
class RootContainer extends React.Component {
constructor(props) {
super(props);
}
render() {
<span>{this.props.t('Home')}</span>
}
}