【问题标题】:Using react i18next on all nested components在所有嵌套组件上使用 react i18next
【发布时间】:2019-01-08 20:59:32
【问题描述】:

我有一个关于复杂 React 应用程序的多语言支持的问题。 所有示例和文档均基于没有嵌套/子组件的“平面”应用程序。

如何处理像这样嵌套的数据:

<i18n>
    <App>
        translate('base')(
          <Base>
              <Child1 />
              <Child2 />
              {t('Hello')}
          </Base>
        )
    </App>
</i18n>

我应该用translate HOC 包装每个子组件吗?
还有其他方法可以将 translation 函数传递给子组件吗?

【问题讨论】:

    标签: javascript reactjs i18next react-i18next


    【解决方案1】:

    不久前我遇到了同样的问题。我为此找到了 4 个解决方案。

    1. t 传递给每个组件。这个很烦人,而且会导致很多错误,因为我一直忘记传递它。

    2. 使用 react-i18next 提供的 NamespacesConsumer 上下文。这也很烦人,语法有时太奇怪和重复。这也可能对性能不利,因为组件可能会经常重新渲染。

    3. 使用 react-i18next 提供的withNamespaces HOC,这是一个很好的选择,它易于阅读并且不会因翻译语法污染您的代码。它也比前两个选项更有效。

    4. 这是我最喜欢的解决方案,我最终直接使用 i18next,因为您可以随时随地访问t(),无需额外代码。

    如果你想保留 react-i18next,我建议你使用 HOC,它更容易调试、测试和开发。但老实说,我认为 i18next 做得更好。我最初使用 react-i18next 是因为我认为这是一种反应方式,但使用它只是一种痛苦,react-i18next 有很多错误,而且要编写更多代码。使用 i18next 就这么简单

    import i18next from 'i18next';
    
    i18next.t('parentKey.childKey');
    

    【讨论】:

    • 我认为直接使用 i18next 的一个问题是当语言改变时你的组件不会重新渲染。
    • 没错,但我通常会用新语言重新加载页面。这还不错,没有 react-i18next 的应用程序更快,易于测试,易于调试并且代码更干净。大多数人只会更改一次语言,因此在我自己看来,仅使用复杂的库来支持此功能有点矫枉过正。试试看,这是我能给你的最好建议。
    • 有道理。我建议你提到 react-i18next 提供的withNamespaces HOC,而不是“a HOC”。
    • 我也受到了打击:在form-redux validate(),我需要显示本地化错误。问题是validate() 无权访问Component.props (CMIIW)。所以我不得不import i18n from "i18next" 和用户i18n.t() 直接在validate() 内。 ;-)
    • 用我的子组件为我解决的问题是添加带有 t(ns:key) 键的命名空间,就像您在代码示例中一样!谢谢
    【解决方案2】:

    您也可以通过外部组件的常规道具传递它。

    就像使用 translate hoc 包装的容器组件和您只需通过 props 传递 t 函数的内部组件。

    【讨论】:

    • 嗯,我知道 :) 问题是,最好的方法是什么 ;)
    • 这是最糟糕的事情; 手动将道具传递到无尽的关卡。我不会推荐超过 2 个级别的任何应用程序,并且没有应用程序仅下降 2 个级别。尤其是翻译
    【解决方案3】:

    最好的方法是用 React.Context 包装你的主组件,并将 t 属性作为上下文传递,并让它在你的每个嵌套子组件中都可以访问。

    我也在这样的应用程序中使用本地化。

    优点:

    • 当每个组件都用 hOC 包装时,不会破坏子层次结构
    • 将来,如果您决定选择另一个库进行本地化,您只需更改该上下文的主要 Provider 组件,它将更新整个应用程序的实现。
    • 由于最初加载了翻译,因此您的上下文不会更新和重新渲染问题不会一次又一次地出现。

    【讨论】:

    • 即使 t 的值没有改变,上下文也会重新渲染里面的组件。反应真的很烦人。您需要指定 shouldComponentUpdate 或使用 PureComponent,但有时您只渲染一个无状态函数组件或您可以修改的库中的组件。我发现重新渲染很多组件只是为了翻译字符串很烦人。但这对于大多数项目来说是一个很好的解决方案,重要的是要注意性能问题或渲染错误可能是由上下文引起的。
    • 错了,除非另行更改,否则上下文不会持续更新您的树。 react-router 和 redux 从一开始就在他们的库下使用上下文。
    • 是的,没错,但我说的是 react-i18next 处理它的方式。当我使用 react-i18next 时,why-did-you-update 一直在触发,因为您从库中获得的上下文使用了未绑定的函数。为避免这种情况,您需要创建自己的上下文,这很烦人。
    • 只有当我们使用 react-i18next changeLanguage 方法时才会更新,并更改应用程序中的所有本地化。我认为这是正确的行为,因为我们希望我们所有的孩子都渲染使用本地化(我认为几乎所有组件)其余的可以是 memoPure.Component
    • 我不确定我们在这里是否相互理解。但这基本上就是我要说的。 react-i18next 处理上下文道具的方式是错误的。即使语言没有改变,这也会导致大量重新渲染。就像你说的,为了避免所有这些重新渲染,你需要使用 memoize 函数或将组件转换为 PureComponent,当你可以拥有 SFC 时,这很烦人。对我来说,为了避免重新渲染而不得不将无状态组件转换为纯组件是一个大问题。
    【解决方案4】:

    如果您在编写 React 组件时使用的是 hooks,而不是类(像我一样),那么您可以使用 useTranslation 挂钩:

    import React from 'react';
    import { useTranslation } from 'react-i18next';
    
    export function MyComponent() {
      const { t, i18n } = useTranslation();
      // or const [t, i18n] = useTranslation();
    
      return <p>{t('my translated text')}</p>
    }
    

    这就像withTranslation 包装器一样,需要在每个使用翻译的文件中导入(挂钩)。

    【讨论】:

      猜你喜欢
      • 2016-09-26
      • 2019-07-13
      • 2015-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-18
      相关资源
      最近更新 更多