Loading...
Loading...
Compare original and translation side by side
Quick Guide: Use react-intl for internationalization with ICU Message Format.for JSX content,FormattedMessagefor string attributes and programmatic use,useIntlfor extractable message descriptors. Wrap app withdefineMessagesand configureIntlProviderfor missing translations. Always include theonErrorcategory in plurals and selects.otherVersion Note: react-intl v7.x supports React 16.6+/17/18/19. v8+ requires React 19 only (React 18 support dropped). Current latest: v10.x.
快速指南: 使用react-intl结合ICU消息格式实现国际化。在JSX内容中使用,在字符串属性和编程场景中使用FormattedMessage,使用useIntl定义可提取的消息描述符。用defineMessages包裹应用,并配置IntlProvider处理缺失的翻译。在复数和选择类型的消息中务必包含onError类别。other版本说明: react-intl v7.x支持React 16.6+/17/18/19。v8+仅支持React 19(不再支持React 18)。当前最新版本:v10.x。
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,, named constants)import type
IntlProviderothercreateIntl@formatjs/intl所有代码必须遵循CLAUDE.md中的项目约定(短横线命名法、命名导出、导入顺序、、命名常量)import type
IntlProviderother@formatjs/intlcreateIntlIntlIntlIntlProvideronErrordefaultLocaledefaultRichTextElementsexport function AppIntlProvider({ children, locale, messages }: Props) {
return (
<IntlProvider
locale={locale}
defaultLocale={DEFAULT_LOCALE}
messages={messages}
defaultRichTextElements={DEFAULT_RICH_TEXT_ELEMENTS}
onError={(err) => {
if (err.code === "MISSING_TRANSLATION") {
console.warn(`Missing translation: ${err.message}`);
return;
}
throw err;
}}
>
{children}
</IntlProvider>
);
}IntlProvideronErrordefaultLocaledefaultRichTextElementsexport function AppIntlProvider({ children, locale, messages }: Props) {
return (
<IntlProvider
locale={locale}
defaultLocale={DEFAULT_LOCALE}
messages={messages}
defaultRichTextElements={DEFAULT_RICH_TEXT_ELEMENTS}
onError={(err) => {
if (err.code === "MISSING_TRANSLATION") {
console.warn(`Missing translation: ${err.message}`);
return;
}
throw err;
}}
>
{children}
</IntlProvider>
);
}FormattedMessage<FormattedMessage
id="greeting.unread"
defaultMessage="{count, plural, =0 {No messages} one {# message} other {# messages}}"
values={{ count: unreadCount }}
/>FormattedMessage<FormattedMessage
id="greeting.unread"
defaultMessage="{count, plural, =0 {No messages} one {# message} other {# messages}}"
values={{ count: unreadCount }}
/>useIntlconst intl = useIntl();
const placeholder = intl.formatMessage({
id: "search.placeholder",
defaultMessage: "Search products...",
});
<input placeholder={placeholder} aria-label={ariaLabel} />useIntlconst intl = useIntl();
const placeholder = intl.formatMessage({
id: "search.placeholder",
defaultMessage: "Search products...",
});
<input placeholder={placeholder} aria-label={ariaLabel} />defineMessagesexport const productMessages = defineMessages({
title: {
id: "product.title",
defaultMessage: "Product Details",
description: "Page title for product detail page",
},
reviewCount: {
id: "product.reviewCount",
defaultMessage:
"{count, plural, =0 {No reviews} one {# review} other {# reviews}}",
description: "Number of product reviews with pluralization",
},
});defineMessagesexport const productMessages = defineMessages({
title: {
id: "product.title",
defaultMessage: "Product Details",
description: "Page title for product detail page",
},
reviewCount: {
id: "product.reviewCount",
defaultMessage:
"{count, plural, =0 {No reviews} one {# review} other {# reviews}}",
description: "Number of product reviews with pluralization",
},
});<FormattedMessage
id="terms.notice"
defaultMessage="By signing up, you agree to our <terms>Terms</terms> and <privacy>Privacy Policy</privacy>."
values={{
terms: (chunks) => <a href="/terms">{chunks}</a>,
privacy: (chunks) => <a href="/privacy">{chunks}</a>,
}}
/>defaultRichTextElementsIntlProvider<b><i><br><FormattedMessage
id="terms.notice"
defaultMessage="By signing up, you agree to our <terms>Terms</terms> and <privacy>Privacy Policy</privacy>."
values={{
terms: (chunks) => <a href="/terms">{chunks}</a>,
privacy: (chunks) => <a href="/privacy">{chunks}</a>,
}}
/>IntlProviderdefaultRichTextElements<b><i><br><FormattedDate value={date} year="numeric" month="long" day="numeric" />
// en-US: "January 15, 2024" | de-DE: "15. Januar 2024"
<FormattedNumber value={amount} style="currency" currency={currency} />
// en-US: "$1,234.56" | de-DE: "1.234,56 EUR"
<FormattedList type="conjunction" value={names} />
// en: "Alice, Bob, and Charlie" | es: "Alice, Bob y Charlie"intl.formatDate()intl.formatNumber()<FormattedDate value={date} year="numeric" month="long" day="numeric" />
// en-US: "January 15, 2024" | de-DE: "15. Januar 2024"
<FormattedNumber value={amount} style="currency" currency={currency} />
// en-US: "$1,234.56" | de-DE: "1.234,56 EUR"
<FormattedList type="conjunction" value={names} />
// en: "Alice, Bob, and Charlie" | es: "Alice, Bob y Charlie"intl.formatDate()intl.formatNumber()// src/types/intl.d.ts
import type messages from "../lang/en.json";
type MessageIds = keyof typeof messages;
declare global {
namespace FormatjsIntl {
interface Message {
ids: MessageIds;
}
}
}"esnext.intl"compilerOptions.lib// src/types/intl.d.ts
import type messages from "../lang/en.json";
type MessageIds = keyof typeof messages;
declare global {
namespace FormatjsIntl {
interface Message {
ids: MessageIds;
}
}
}compilerOptions.lib"esnext.intl"formatjs extract 'src/**/*.{ts,tsx}' --out-file lang/en.jsonformatjs compile lang/en.json --out-file compiled/en.json --astformatjs extract 'src/**/*.{ts,tsx}' --out-file lang/en.jsonformatjs compile lang/en.json --out-file compiled/en.json --astother{count, plural, =0 {No items} one {# item} other {# items}}
{position, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}
{gender, select, male {He} female {She} other {They}} liked your post.other{count, plural, =0 {No items} one {# item} other {# items}}
{position, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}
{gender, select, male {He} female {She} other {They}} liked your post.createIntlcreateIntlCacheRawIntlProvidercreateIntlcreateIntlCacheRawIntlProviderdefineMessagesFormattedMessagedefineMessagesFormattedMessageIntlProviderotherdefaultLocaleonError{count}{count, plural, ...}#FormattedMessageReactNodestringformatMessagestringstring | ReactNode[]chunksformatNumberstyle: "percent"formatRelativeTime'''injectIntluseIntlonWarndefaultRichTextElementsIntlProviderotherotherdefaultLocaleonError{count}{count, plural, ...}#FormattedMessageReactNodestringformatMessagestringstring | ReactNode[]chunksformatNumberstyle: "percent"formatRelativeTime'''injectIntluseIntlonWarndefaultRichTextElementsAll code must follow project conventions in CLAUDE.md
IntlProviderother所有代码必须遵循CLAUDE.md中的项目约定
IntlProviderother