在带有装饰器和HOC的类组件中使用react-i18next

时间:2019-10-21 11:05:41

标签: javascript reactjs i18next react-i18next

我正在尝试在我的React项目中实现i18n,该项目在react-i18next的帮助下也使用Redux。

在此项目中,我们将类组件与装饰器一起使用。

最初,我想尝试react-i18next v10,但由于它依赖于钩子,而且我不能在类组件中使用钩子,所以对我来说这是不可能的。

回到旧版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,
);
  • RootContainer HOC包装了一个简单的组件,它是withNamespaces()的子组件,但具有装饰器语法
@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)

问题是,如果我删除了组件类上的@withNamespaces() HOC,我将不再遇到此错误,但是组件的props中没有{t, i18n},因此无法翻译任何内容。 而且,不幸的是,错误中的给定URL不再存在。

据我从文档中了解到,<I18nextProvider>应该将{t, i18n}值传递到组件树下,这在我看来不是。

我发现自己陷入了无法使用v10(我们有很多组件,而现在不能将它们全部重构为功能组件)和无法使v9正常工作之间的困扰。

如果您遇到类似的问题,我的选择将用光,并且可以事后考虑。

谢谢。

2 个答案:

答案 0 :(得分:0)

对于任何想知道的人,我都通过将<RootContainer>子对象包装而不是将<RootContainer>本身包装在renderer方法中来工作,这给我留下了类似以下内容:

  • 渲染器
ReactDOM.render(
    <Provider store={store}>
        <Router history={history}>
            <RootContainer />
        </Router>
    </Provider>,
    $root,
);
  • RootContainer
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>
        );
    }
}
  • SimpleElement
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是一个成熟的React组件(准确地说是PureComponent)。不确定,这可能与渲染链接有关,但是它仍然可以按预期的方式工作。

答案 1 :(得分:0)

我这样做是设法在课堂上使用了react-i18next的最新版本:

import { withTranslation } from 'react-i18next';

class RootContainer extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
   <span>{this.props.t('Home')}</span>
  }
}