【问题标题】:React-intl for non components非组件的 React-intl
【发布时间】:2018-05-26 21:18:24
【问题描述】:

目前我有以下代码将 react-intl 暴露给非组件,但它会抛出一个错误,因为 intl as undefined。

我已经创建了一个单独的组件作为“CurrentLocale”并向它注入 intl。导出函数 t 将使用来自 CurrentLocale 上下文的 intl formatMessage。

import React from 'react';
import {injectIntl} from 'react-intl';
import PropTypes from 'prop-types';
import { flow } from 'lodash';

class CurrentLocale extends React.Component {


    constructor(props,context){

        super();
        console.log(context,props);
        console.log(this.formatMessage);
        const { intl } = this.context.intl;//this.props;

        this.formatMessage = intl.formatMessage;
    }

    render() {
        return false;
    }
}
CurrentLocale.contextTypes={
    intl:PropTypes.object,
};


injectIntl(CurrentLocale);

function intl() {
    return new CurrentLocale();
}

function formatMessage(...args) {
    return intl().formatMessage(...args);
}


const t = opts => {
    const id = opts.id;
    const type = opts.type;
    const values = opts.values;
    let t;

    switch (type){

        case 'message':
        default:
            t = formatMessage(id, values);
    }

    return t;
}

export default t;

t 在另一个纯 javascript 文件中被称为,

import t from './locale/t';
t( { type: 'message', id:'button.Next'});

以下是错误消息。 提前致谢。

【问题讨论】:

    标签: reactjs react-intl


    【解决方案1】:

    我还使用另一种非常简单的方法来解决类似问题:为非组件提供对 intl 对象的访问:

    import { IntlProvider, addLocaleData } from 'react-intl';
    import localeDataDE from 'react-intl/locale-data/de';
    import localeDataEN from 'react-intl/locale-data/en';
    import { formMessages } from '../../../store/i18n'; // I defined some messages here
    import { Locale } from '../../../../utils'; //I set the locale fom here
    
    addLocaleData([...localeDataEN, ...localeDataDE]);
    const locale = Locale.setLocale(); //my own methods to retrieve locale
    const messages = Locale.setMessages(); //getting messages from the json file.
    const intlProvider = new IntlProvider({ locale, messages });
    const { intl } = intlProvider.getChildContext();
    
    export const SCHEMA = {
      salutation: {
        label: intl.formatMessage(formMessages.salutationLabel),
        errormessages: {
          required: intl.formatMessage(formMessages.salutationError),
        },
      },
      academic_title_code: {
        label: intl.formatMessage(formMessages.academicTitleLabel),
      },
    };
    

    它就像一个魅力!

    v3.x 更新

    After migration to react-intl 3.x

    import { createIntl, createIntlCache } from 'react-intl'
    import { formMessages } from '../../../store/i18n'; // I defined some messages here
    import { Locale } from '../../../../utils'; //I set the locale fom here
    
    const locale = Locale.setLocale(); //my own methods to retrieve locale
    const messages = Locale.setMessages(); //getting messages from the json file.
    // This is optional but highly recommended
    // since it prevents memory leak
    const cache = createIntlCache();
    const intl = createIntl({ locale, messages }, cache)
    
    export const SCHEMA = {
      salutation: {
        label: intl.formatMessage(formMessages.salutationLabel),
        errormessages: {
          required: intl.formatMessage(formMessages.salutationError),
        },
      },
      academic_title_code: {
        label: intl.formatMessage(formMessages.academicTitleLabel),
      },
    };
    

    【讨论】:

    • 在新版本的 react-intl 中,此解决方案会导致错误为 .getChildContext is not a function
    • 我每月更新一次我的库,下周我这样做时可能会遇到这个问题。但上次我检查(上个月)时,2.9.0 可以工作。感谢您指出问题。一旦我更新它,我会密切关注它,因为我经常使用它,它可能会破坏我的应用程序。
    【解决方案2】:

    createIntl 有一种新方法可以很容易地做到这一点,它返回一个可以在 React 组件之外使用的对象。这是来自documentation 的示例。

    import {createIntl, createIntlCache, RawIntlProvider} from 'react-intl'
    
    // This is optional but highly recommended
    // since it prevents memory leak
    const cache = createIntlCache()
    
    const intl = createIntl({
      locale: 'fr-FR',
      messages: {}
    }, cache)
    
    // Call imperatively
    intl.formatNumber(20)
    
    // Pass it to IntlProvider
    <RawIntlProvider value={intl}>{foo}</RawIntlProvider>
    

    我个人将 intl 对象存储在 Redux 存储中,因此我可以在我的应用程序的任何地方访问它。

    【讨论】:

    • 它不会影响您应用程序的包大小吗?
    • 您实际上无法在运行时通过存储或本地存储甚至按钮单击来更新它。需要将其与某物挂钩以使其具有动态性。
    【解决方案3】:

    这一行:const { intl } = this.context.intl; 应该是const { intl } = this.context;

    这是一个与您做几乎完全相同的事情的人的参考帖子:https://github.com/yahoo/react-intl/issues/983#issuecomment-342314143

    在上面,作者本质上是在创建一个导出的单例,而不是像上面那样每次都创建一个新实例。这可能也是您要考虑的事情。

    【讨论】:

      【解决方案4】:

      还有另一种方法可以解决与使用 react-intl formatMessage 处理非组件类似的问题。

      创建一个 LocaleStore.js 商店文件。

       import _formatMessage from "format-message";
      
          export default class LocaleStore {
      
            formatMessage = (id, values) => {
              if (!(id in this.messages)) {
                console.warn("Id not found in intl list: " + id);
                return id;
              }
              return _formatMessage(this.messages[id], values);
            };
          }
      

      导入 LocaleStore 您的 CombinedStores.js

      import LocaleStore from "./stores/LocaleStore";
      import en from "./translations/en";
      import de from "./translations/de";
      import Global from "./stores/global"
      const locale = new LocaleStore("en", {
        en,
        de
      });
      export default {
      global:new Global(locale) 
      }
      

      现在您可以在 GlobalStore.js

      中使用它
          class GlobalStore {
          constructor(locale) {
           this.locale = locale;
          }
      
         formatMessage=(message_is,formatLanguage="en")=> {
           return  this.locale.formatMessage(message_id, formatLanguage);
          }
        }
      

      【讨论】:

        【解决方案5】:

        如果您可以接受使用功能组件,我更喜欢使用useIntl hook

        https://reactjs.org/docs/components-and-props.html#function-and-class-components

        然后我可以得到这样的值:

        import { useIntl } from "react-intl";
        
        const intl = useIntl()
        intl.formatMessage({ id: 'myId' }),
        

        https://formatjs.io/docs/react-intl/api/#useintl-hook

        【讨论】:

        • 如果您投反对票,请说出原因!否则很难改善答案。
        • 它不能解决问题。只能在 react 组件内部使用
        • @LabLab 非常正确,我将通过澄清更新我的答案。
        猜你喜欢
        • 2016-08-20
        • 1970-01-01
        • 1970-01-01
        • 2021-09-22
        • 2017-01-05
        • 1970-01-01
        • 2016-09-12
        • 2019-12-25
        • 1970-01-01
        相关资源
        最近更新 更多