我应该如何在React组件库中处理国际化?

4
我可以找到很多关于如何在React应用程序中进行国际化的示例,但是我找不到任何与组件库相关的示例。
我正在使用PhraseApp,并且想知道是否有人有建议如何以良好的方式完成此操作。
选项:
1.所有组件都作为props接收应该使用的语言
2.所有翻译都在PhraseApp中
3.这是我工作的公司的组件库,因此该库将具有需要翻译的默认标签
我考虑的选项:
- 在Apollo客户端存储中加载当前语言的键/值,并创建一个帮助程序来获取给定键的值 - 尝试使用像https://github.com/phrase/react-intl-phraseapp这样的库,但我不知道它是否能够工作,因为它不是单页应用程序

嗨 Marina,我现在正处于完全相同的情况。只想着在我们导出的每个组件上使用 react-intl,我们将调用公共实用方法来加载要使用的语言和消息... 这不是太优雅的解决方案,但可能有效。你的解决方案有进展吗? - Kuba
嗨@Kuba,感谢回复,我下周将尝试不同的解决方案,并与您分享我找到的最佳解决方案。您的解决方案是我将尝试的选项之一。 - Marina
1个回答

3

所以我们最终采用了react-intl,将每个组件包装在所需的区域设置和消息内部的IntlProvider中进行导出。IntlProvider的配置在组件的构造函数中通过state进行设置:

    this.state = {
       i18nCfg: IntlUtils.init(props.language, 'SignOutMenu')
    }

然后在组件的 render() 中设置:

    render() {
      const { i18nCfg } = this.state;
      return (
         <IntlProvider locale={i18nCfg.language} messages={i18nCfg.messages}>

...

组件的地区设置可以由父组件通过injectIntl高阶组件进行提供。

<SignOutMenu language={this.props.intl.locale}/>

如果没有定义语言,可以通过一个工具方法getUserLanguage()init()中从浏览器检测到。

您只需要注意防止应用程序中出现消息id的重复出现,因此我使用一个命名空间字符串来初始化组件,该字符串表示仅与给定组件相关的消息(在getMessages()中完成):


    import {addLocaleData} from 'react-intl';
    import en from 'react-intl/locale-data/en';
    import de from 'react-intl/locale-data/de';
    import messagesEn from '../locales/lang/i18n_en.json';
    import messagesDe from '../locales/lang/i18n_de.json';

    const defaultLanguage = 'en';
    const supportedLanguages = ['en', 'de'];

    export default class IntlUtils {

       static init = (language, namespace) => {
          // add the supported locale data
          addLocaleData([...en, ...de]);

          // get supported language
          const lang = language && supportedLanguages.indexOf(language) > -1 ? language : IntlUtils.getUserLanguage();

          // return back data for IntlProvider
          return {
             language: lang,
             messages: IntlUtils.getMessages(lang, namespace)
          }
       }

       static getMessages = (language, namespace) => {
          let langMsgs;
          switch (language) {
             case 'de': langMsgs = messagesDe; break;

             case 'en':
             default: langMsgs = messagesEn;
          }

          if (langMsgs) {
             const matchNS = namespace + ".";
             const filtered = {};
             for (var key in langMsgs) {
                if (key.startsWith(matchNS)) {
                   filtered[key] = langMsgs[key];
                }
             }
             return filtered;
          }
       }

       static getUserLanguage = () => {
          //if none available, take it from browser
          const browserLanguage = window.navigator.userLanguage || window.navigator.language;
          if (browserLanguage) {
             // get the language code and store it in local prefs for nexttime
             const m = browserLanguage.match(/^([a-z]+)/i);
             if (m) {
                return m[0];
             }
          }
          // nothing found -> return default en
          return defaultLanguage;
       }
    }


要能在IntlUtil中导入JSON文件,我必须安装babel-plugin-inline-json-import的开发依赖,并将其添加到.babelrc文件中。
   "plugins": [
      ["inline-json-import", {}]
   ]

我发现在与IntlProvider初始化的同一组件中使用带有方法formatMessage()的injectIntl HOC无法正常工作(因为HOC使用了来自上方组件的messages实例)。
请注意,我们的语言切换机制涉及页面刷新,所以它与init()一样完美。但是,在没有页面刷新的情况下使用上下文或redux进行语言切换时,我无法确定它会起多大作用。不过,我们很快就会在一个这样的应用程序中使用它,所以我可能会在这里发布更新......
希望这至少对您和其他人有所帮助。

1
感谢@Kuba分享您的解决方案。在这里,我们决定通过上下文共享ids/values翻译。基本上,我们创建了一个TranslationsContext,对于每个组件,您必须创建一个TranslationsContext.Consumer,并使用组件需要创建TranslationsContext.Provider。这不是最好的解决方案,但易于实现且速度快。 - Marina
是的,这也是做法...正如你所说,它既简单又快速,这很好。不错的方法 :o) 感谢@Marina提供的信息。 - Kuba

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接