我在我的应用程序中支持多种语言,并使用React-intl。 我有Redux中间件,我在那里调用服务器,如果出现错误,我想在UI上显示错误。
我知道我可以做类似的事情:
1)使用消息密钥从中间件调度操作:
{type: SHOW_ERROR, message: 'message_error_key'}
2)在我的React组件中使用:
<FormattedMessage id={this.props.message_error_key}/>
但是有没有办法从中间件发送已翻译过的消息?
{type: SHOW_ERROR, message: [translated_message_should_be_here]}
答案 0 :(得分:8)
我认为您不能直接从中间件访问formatMessage
,因为它似乎只通过injectIntl
公开了组件。您可以提交一个问题来描述您的用例,并且可能会考虑在组件外部访问Sub FindAndHide(LookingFor As String)
Dim i As Long, j As Long
Dim Rng As Range
Dim Arr As Variant
Dim RowContainsString As Boolean
Set Rng = ActiveSheet.UsedRange
Arr = Rng.Value
LookingFor = LCase(LookingFor)
For i = LBound(Arr, 1) To UBound(Arr, 1)
RowContainsString = False
For j = LBound(Arr, 2) To UBound(Arr, 2)
If InStr(LCase(Arr(i, j)), LookingFor) > 0 Then
RowContainsString = True
Exit For
End If
Next j
If Not RowContainsString Then Rng.Rows(i).Hidden = True
Next i
End Sub
Sub Test()
FindAndHide LookingFor:="A"
End Sub
的简单JavaScript API,但现在似乎无法使用。
答案 1 :(得分:6)
这可能不是最漂亮的解决方案,但是我们如何解决这个问题;
1)首先我们创建了一个&lt; IntlGlobalProvider&#39;从组件树中的IntlProvider继承上下文和道具的组件;
<ApolloProvider store={store} client={client}>
<IntlProvider>
<IntlGlobalProvider>
<Router history={history} children={routes} />
</IntlGlobalProvider>
</IntlProvider>
</ApolloProvider>
2)(在IntlGlobalProvider.js中)然后在上下文中我们获得了我们想要的intl功能并通过单例公开它。
// NPM Modules
import { intlShape } from 'react-intl'
// ======================================================
// React intl passes the messages and format functions down the component
// tree using the 'context' scope. the injectIntl HOC basically takes these out
// of the context and injects them into the props of the component. To be able to
// import this translation functionality as a module anywhere (and not just inside react components),
// this function inherits props & context from its parent and exports a singleton that'll
// expose all that shizzle.
// ======================================================
var INTL
const IntlGlobalProvider = (props, context) => {
INTL = context.intl
return props.children
}
IntlGlobalProvider.contextTypes = {
intl: intlShape.isRequired
}
// ======================================================
// Class that exposes translations
// ======================================================
var instance
class IntlTranslator {
// Singleton
constructor() {
if (!instance) {
instance = this;
}
return instance;
}
// ------------------------------------
// Formatting Functions
// ------------------------------------
formatMessage (message, values) {
return INTL.formatMessage(message, values)
}
}
export const intl = new IntlTranslator()
export default IntlGlobalProvider
3)将其作为模块导入任何地方
import { defineMessages } from 'react-intl'
import { intl } from 'modules/core/IntlGlobalProvider'
const intlStrings = defineMessages({
translation: {
id: 'myid',
defaultMessage: 'Hey there',
description: 'someStuff'
},
intl.formatMessage(intlStrings.translation)
答案 2 :(得分:2)
现在支持在React生命周期之外格式化字符串。您可以查看createIntl
官方文档here。该代码可能类似于以下内容:
intl.js
import { createIntl, createIntlCache } from 'react-intl';
let cache;
let intl;
/**
* Generate IntlShape object
* @param {Object} props
* @param {String} props.locale - User specified language
* @param {Object} props.messages - Messages
* @returns {Object}
*/
const generateIntl = props => {
if (cache) {
cache = null;
}
cache = createIntlCache();
intl = createIntl(props, cache);
return intl;
};
export { generateIntl, intl };
root-component.jsx
import React from 'react';
import { RawIntlProvider, FormattedMessage } from 'react-intl';
import { generateIntl } from './intl';
const messages = { hello: 'Hello' };
const intlValue = generateIntl({ locale: 'en', messages });
export const RootComponent = () => {
return (
<RawIntlProvider value={intlValue}>
<FormattedMessage id="hello" />
</RawIntlProvider>
);
};
intl-consumer-script.js
import { intl } from './intl';
const translation = intl.formatMessage({ id: 'hello' });
console.log(translation);
答案 3 :(得分:2)
受上述Simon Somlai的启发,这里是使用react钩子的等效版本:
len(secondList['sizes']) > len(firstList['sizes']):
然后按照上面Simon Somlai的答案的步骤1的说明设置import React from 'react';
import { useIntl } from 'react-intl';
// 'intl' service singleton reference
let intl;
export function IntlGlobalProvider({ children }) {
intl = useIntl(); // Keep the 'intl' service reference
return children;
}
// Getter function to expose the read-only 'intl' service
export function appIntl() {
return intl;
}
。现在,在任何辅助程序/实用程序类中使用IntlGlobalProvider
时,您可以执行以下操作:
intl
答案 4 :(得分:1)
在尝试将reducer的默认状态初始化为本地化消息时遇到了类似的问题。看起来在组件外部使用react-intl的任何部分似乎都没有在API中考虑过。两个想法:
将intl
注入<IntlProvider>
下方的自定义组件,通过应用程序范围的单例在componentWillReceiveProps
中提供该组件。接下来从其他地方访问该单身人士并使用intl.formatMessage
和其他人。
可以使用React-intl所属的Format.js组件来实现所需的功能。在这种情况下,可以考虑yahoo/intl-messageformat和yahoo/intl-format-cache。这当然不能很好地与react-intl整合在一起。
答案 5 :(得分:0)
我认为最简单的方法是
injectIntl
包装组件/容器intl
intl
intl.formatMessage
(intl
来自操作)答案 6 :(得分:0)
您必须使用getChildContext()
来获得intl
,它具有formatMessage()
方法。
1。在您的tsx根文件中,例如App.tsx。
import { IntlProvider, addLocaleData} from 'react-intl'
import * as locale_en from 'react-intl/locale-data/en'
import * as locale_zh from 'react-intl/locale-data/zh'
import message_en from '@/locales/en'
import message_zh from '@/locales/zh-CN'
const messages = {
'en': flattenMessages(message_en),
'zh': flattenMessages(message_zh)
}
addLocaleData([...locale_en, ...locale_zh])
const intlProvider = new IntlProvider({ locale: 'zh', messages: messages['zh']})
// export intl
export const { intl } = intlProvider.getChildContext()
import { intl } from '@/App';
function* handleSubmit() {
try {
yield someApi()
} catch(error) {
console.log(intl.formatMessage(error.message))
}
}
在幕后,IntlProvider
收到了这些道具,并使用了类方法getChildContext
。
namespace IntlProvider {
interface Props {
locale?: string;
timeZone?: string;
formats?: any;
messages?: any;
defaultLocale?: string;
defaultFormats?: any;
textComponent?: any;
initialNow?: any;
onError?: (error: string) => void;
}
}
class IntlProvider extends React.Component<IntlProvider.Props> {
getChildContext(): {
intl: InjectedIntl;
};
}
更深入InjectedIntl
界面。您可以看到为什么intl实例具有formatMessage方法。
interface InjectedIntl {
formatDate(value: DateSource, options?: FormattedDate.PropsBase): string;
formatTime(value: DateSource, options?: FormattedTime.PropsBase): string;
formatRelative(value: DateSource, options?: FormattedRelative.PropsBase & { now?: any }): string;
formatNumber(value: number, options?: FormattedNumber.PropsBase): string;
formatPlural(value: number, options?: FormattedPlural.Base): keyof FormattedPlural.PropsBase;
formatMessage(messageDescriptor: FormattedMessage.MessageDescriptor, values?: {[key: string]: MessageValue}): string;
formatHTMLMessage(messageDescriptor: FormattedMessage.MessageDescriptor, values?: {[key: string]: MessageValue}): string;
locale: string;
formats: any;
messages: { [id: string]: string };
defaultLocale: string;
defaultFormats: any;
now(): number;
onError(error: string): void;
}
答案 7 :(得分:0)
我相信您应该避免在中间件中这样做。您可以使用已翻译的消息来调度操作。
const deleteUser = (id, messages) => {
type: DELETE_USER,
payload: {id, messages}
}
然后在您的传奇(或其他中间件)中,您可以使用此已翻译的消息。
function* deleteUserWatcher({
payload: { id, messages }
}) {
try {
yield request.delete(`/user/${id}`);
yield put(deleteUserSuccess(id));
yield put(pushNotificationToStack(message.success));
} catch (error) {
yield put(pushNotificationToStack(message.error));
}
}
然后在您的组件中,您可以调度操作
const dispatch = useDispatch();
const { formatMessage } = useIntl();
const handleDeleteUser = id => {
dispatch(deleteUser(id, {
success: formatMessage({
id: "User.delete.success",
defaultMessage: "User has been deleted"
}),
error: formatMessage({
id: "User.delete.error",
defaultMessage: "Ups. Something went wrong. Sorry :("
}),
}
));
}
我知道这并不适合所有情况,但是您可以使用这种方法涵盖大多数情况