非组件的 React-intl
Posted
技术标签:
【中文标题】非组件的 React-intl【英文标题】:React-intl for non components 【发布时间】: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');
以下是错误消息。 提前致谢。
【问题讨论】:
【参考方案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 非常正确,我将通过澄清更新我的答案。以上是关于非组件的 React-intl的主要内容,如果未能解决你的问题,请参考以下文章
将 react-intl 对象注入到已安装的 Enzyme 组件中进行测试
React-intl 在 Safari v8.0.8 上禁用 react-router 的 Link 组件 onClick 事件