-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy path0de0f2fb.9e413e56.js
1 lines (1 loc) · 44.3 KB
/
0de0f2fb.9e413e56.js
1
"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4652],{3317:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>l,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"react-intl/components","title":"Components","description":"React Intl has a set of React components that provide a declarative way to setup an i18n context and format dates, numbers, and strings for display in a web UI. The components render React elements by building on React Intl\'s imperative API.","source":"@site/docs/react-intl/components.md","sourceDirName":"react-intl","slug":"/react-intl/components","permalink":"/docs/react-intl/components","draft":false,"unlisted":false,"editUrl":"https://github.com/formatjs/formatjs/edit/main/website/docs/react-intl/components.md","tags":[],"version":"current","lastUpdatedBy":"renovate[bot]","lastUpdatedAt":1743775521000,"frontMatter":{"id":"components","title":"Components"},"sidebar":"api","previous":{"title":"Overview","permalink":"/docs/react-intl"},"next":{"title":"Imperative API","permalink":"/docs/react-intl/api"}}');var r=t(6106),a=t(8299);const i={id:"components",title:"Components"},l=void 0,o={},c=[{value:"Why Components?",id:"why-components",level:2},{value:"IntlProvider",id:"intlprovider",level:2},{value:"locale, formats, and messages",id:"locale-formats-and-messages",level:3},{value:"defaultLocale and defaultFormats",id:"defaultlocale-and-defaultformats",level:3},{value:"textComponent",id:"textcomponent",level:3},{value:"onError",id:"onerror",level:3},{value:"onWarn",id:"onwarn",level:3},{value:"wrapRichTextChunksInFragment",id:"wraprichtextchunksinfragment",level:3},{value:"defaultRichTextElements",id:"defaultrichtextelements",level:3},{value:"RawIntlProvider",id:"rawintlprovider",level:2},{value:"FormattedDate",id:"formatteddate",level:2},{value:"FormattedDateParts",id:"formatteddateparts",level:2},{value:"FormattedTime",id:"formattedtime",level:2},{value:"FormattedTimeParts",id:"formattedtimeparts",level:2},{value:"FormattedDateTimeRange",id:"formatteddatetimerange",level:2},{value:"FormattedRelativeTime",id:"formattedrelativetime",level:2},{value:"FormattedNumber",id:"formattednumber",level:2},{value:"FormattedNumberParts",id:"formattednumberparts",level:2},{value:"FormattedPlural",id:"formattedplural",level:2},{value:"FormattedList",id:"formattedlist",level:2},{value:"FormattedListParts",id:"formattedlistparts",level:2},{value:"FormattedDisplayName",id:"formatteddisplayname",level:2},{value:"FormattedMessage",id:"formattedmessage",level:2},{value:"Message Syntax",id:"message-syntax",level:3},{value:"Message Descriptor",id:"message-descriptor",level:3},{value:"Message Formatting Fallbacks",id:"message-formatting-fallbacks",level:3},{value:"Usage",id:"usage",level:3},{value:"Rich Text Formatting",id:"rich-text-formatting",level:3},{value:"Function as the child",id:"function-as-the-child",level:3}];function d(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(n.p,{children:["React Intl has a set of React components that provide a declarative way to setup an i18n context and format dates, numbers, and strings for display in a web UI. The components render React elements by building on React Intl's imperative ",(0,r.jsx)(n.a,{href:"/docs/react-intl/api",children:"API"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"why-components",children:"Why Components?"}),"\n",(0,r.jsxs)(n.p,{children:["Beyond providing an idiomatic-React way of integrating internationalization into a React app, and the ",(0,r.jsx)(n.code,{children:"<Formatted*>"})," components have benefits over always using the imperative API directly:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Render React elements that seamlessly compose with other React components."}),"\n",(0,r.jsxs)(n.li,{children:["Support rich-text string/message formatting in ",(0,r.jsx)(n.code,{children:"<FormattedMessage>"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:["Implement advanced features like ",(0,r.jsx)(n.code,{children:"<FormattedRelativeTime>"}),"'s updating over time."]}),"\n",(0,r.jsx)(n.li,{children:"Provide TypeScript type definitions."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"intlprovider",children:"IntlProvider"}),"\n",(0,r.jsxs)(n.p,{children:["React Intl uses the provider pattern to scope an i18n context to a tree of components. This allows configuration like the current locale and set of translated strings/messages to be provided at the root of a component tree and made available to the ",(0,r.jsx)(n.code,{children:"<Formatted*>"})," components. This is the same concept as what Flux frameworks like ",(0,r.jsx)(n.a,{href:"http://redux.js.org/",children:"Redux"})," use to provide access to a store within a component tree."]}),"\n",(0,r.jsx)(n.admonition,{type:"caution",children:(0,r.jsxs)(n.p,{children:["All apps using React Intl must use the ",(0,r.jsx)(n.code,{children:"<IntlProvider>"})," or ",(0,r.jsx)(n.code,{children:"<RawIntlProvider>"})," component."]})}),"\n",(0,r.jsx)(n.p,{children:"This component is used to setup the i18n context for a tree. Usually, this component will wrap an app's root component so that the entire app will be within the configured i18n context. The following are the i18n configuration props that can be set:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"interface IntlConfig {\n locale: string\n formats: CustomFormats\n messages: Record<string, string> | Record<string, MessageFormatElement[]>\n defaultLocale: string\n defaultFormats: CustomFormats\n timeZone?: string\n textComponent?: React.ComponentType | keyof React.JSX.IntrinsicElements\n wrapRichTextChunksInFragment?: boolean\n defaultRichTextElements?: Record<string, FormatXMLElementFn<React.ReactNode>>\n onError(err: string): void\n}\n"})}),"\n",(0,r.jsx)(n.h3,{id:"locale-formats-and-messages",children:"locale, formats, and messages"}),"\n",(0,r.jsxs)(n.p,{children:["The user's current locale and what the app should be rendered in. While ",(0,r.jsx)(n.code,{children:"defaultLocale"})," and ",(0,r.jsx)(n.code,{children:"defaultFormats"})," are for fallbacks or during development and represent the app's default. Notice how there is no ",(0,r.jsx)(n.code,{children:"defaultMessages"}),", that's because each ",(0,r.jsx)(n.a,{href:"#message-descriptor",children:"Message Descriptor"})," provides a ",(0,r.jsx)(n.code,{children:"defaultMessage"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"defaultlocale-and-defaultformats",children:"defaultLocale and defaultFormats"}),"\n",(0,r.jsxs)(n.p,{children:["Default locale & formats for when a message is not translated (missing from ",(0,r.jsx)(n.code,{children:"messages"}),"). ",(0,r.jsx)(n.code,{children:"defaultLocale"})," should be the locale that ",(0,r.jsx)(n.code,{children:"defaultMessage"}),"s are declared in so that a sentence is coherent in a single locale. Without ",(0,r.jsx)(n.code,{children:"defaultLocale"})," and/or if it's set incorrectly, you might run into scenario where a sentence is in English but embedded date/time is in Spanish."]}),"\n",(0,r.jsx)(n.h3,{id:"textcomponent",children:"textComponent"}),"\n",(0,r.jsxs)(n.p,{children:["Provides a way to configure the default wrapper for React Intl's ",(0,r.jsx)(n.code,{children:"<Formatted*>"})," components. If not specified, ",(0,r.jsx)(n.a,{href:"https://reactjs.org/docs/fragments.html",children:(0,r.jsx)(n.code,{children:"<React.Fragment>"})})," is used. Before V3, ",(0,r.jsx)(n.code,{children:"span"})," was used instead; check the ",(0,r.jsx)(n.a,{href:"/docs/react-intl/upgrade-guide-3x",children:"migration guide"})," for more info."]}),"\n",(0,r.jsx)(n.h3,{id:"onerror",children:"onError"}),"\n",(0,r.jsxs)(n.p,{children:["Allows the user to provide a custom error handler. By default, error messages are logged using ",(0,r.jsx)(n.code,{children:"console.error"})," if ",(0,r.jsx)(n.code,{children:"NODE_ENV"})," is not set to ",(0,r.jsx)(n.code,{children:"production"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"onwarn",children:"onWarn"}),"\n",(0,r.jsxs)(n.p,{children:["Allows the user to provide a custom warning handler. By default, warning messages are logged using ",(0,r.jsx)(n.code,{children:"console.warning"})," if ",(0,r.jsx)(n.code,{children:"NODE_ENV"})," is not set to ",(0,r.jsx)(n.code,{children:"production"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"wraprichtextchunksinfragment",children:"wrapRichTextChunksInFragment"}),"\n",(0,r.jsxs)(n.p,{children:["When formatting rich text message, the output we produced is of type ",(0,r.jsx)(n.code,{children:"Array<string | React.ReactElement>"}),", which will trigger key error. This wraps the output in a single ",(0,r.jsx)(n.code,{children:"React.Fragment"})," to suppress that."]}),"\n",(0,r.jsx)(n.h3,{id:"defaultrichtextelements",children:"defaultRichTextElements"}),"\n",(0,r.jsxs)(n.p,{children:["A map of tag to rich text formatting function. This is meant to provide a centralized way to format common tags such as ",(0,r.jsx)(n.code,{children:"<b>"}),", ",(0,r.jsx)(n.code,{children:"<p>"}),"... or enforcing certain Design System in the codebase (e.g standardized ",(0,r.jsx)(n.code,{children:"<a>"})," or ",(0,r.jsx)(n.code,{children:"<button>"}),"...). See ",(0,r.jsx)(n.a,{href:"https://github.com/formatjs/formatjs/issues/1752",children:"https://github.com/formatjs/formatjs/issues/1752"})," for more context."]}),"\n",(0,r.jsxs)(n.p,{children:["These configuration props are combined with the ",(0,r.jsx)(n.code,{children:"<IntlProvider>"}),"'s component-specific props:"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",children:"props: IntlConfig &\n {\n children: ReactNode,\n }\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Finally, child elements ",(0,r.jsx)(n.em,{children:"must"})," be supplied to ",(0,r.jsx)(n.code,{children:"<IntlProvider>"}),"."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",children:'const App = ({importantDate}) => (\n <div>\n <FormattedDate\n value={importantDate}\n year="numeric"\n month="long"\n day="numeric"\n weekday="long"\n />\n </div>\n)\n\nReactDOM.render(\n <IntlProvider locale={navigator.language}>\n <App importantDate={new Date(1459913574887)} />\n </IntlProvider>,\n document.getElementById(\'container\')\n)\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Assuming ",(0,r.jsx)(n.code,{children:"navigator.language"})," is ",(0,r.jsx)(n.code,{children:'"fr"'}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-html",children:"<div>mardi 5 avril 2016</div>\n"})}),"\n",(0,r.jsx)(n.h2,{id:"rawintlprovider",children:"RawIntlProvider"}),"\n",(0,r.jsxs)(n.p,{children:["This is the underlying ",(0,r.jsx)(n.code,{children:"React.Context.Provider"})," object that ",(0,r.jsx)(n.code,{children:"IntlProvider"})," use. It can be used in conjunction with ",(0,r.jsx)(n.code,{children:"createIntl"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",children:"import {createIntl, createIntlCache, RawIntlProvider} from 'react-intl'\n\n// This is optional but highly recommended\n// since it prevents memory leak\nconst cache = createIntlCache()\n\nconst intl = createIntl({\n locale: 'fr-FR',\n messages: {}\n}, cache)\n\n// Pass it to IntlProvider\n<RawIntlProvider value={intl}>{foo}</RawIntlProvider>\n"})}),"\n",(0,r.jsx)(n.h2,{id:"formatteddate",children:"FormattedDate"}),"\n",(0,r.jsxs)(n.p,{children:["This component uses the ",(0,r.jsx)(n.a,{href:"/docs/react-intl/api#formatdate",children:(0,r.jsx)(n.code,{children:"formatDate"})})," and ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat",children:(0,r.jsx)(n.code,{children:"Intl.DateTimeFormat"})})," APIs and has ",(0,r.jsx)(n.code,{children:"props"})," that correspond to the ",(0,r.jsx)(n.code,{children:"DateTimeFormatOptions"})," specified above."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"props: Intl.DateTimeFormatOptions &\n {\n value: any,\n format: string,\n children: (formattedDate: string) => ReactElement,\n }\n"})}),"\n",(0,r.jsxs)(n.p,{children:["By default ",(0,r.jsx)(n.code,{children:"<FormattedDate>"})," will render the formatted date into a ",(0,r.jsx)(n.code,{children:"<React.Fragment>"}),". If you need to customize rendering, you can either wrap it with another React element (recommended), or pass a function as the child."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:"<FormattedDate value={new Date(1459832991883)} />\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example with Options:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedDate\n value={new Date(1459832991883)}\n year="numeric"\n month="long"\n day="2-digit"\n/>\n'})}),"\n",(0,r.jsx)(n.h2,{id:"formatteddateparts",children:"FormattedDateParts"}),"\n",(0,r.jsx)(n.admonition,{title:"browser support",type:"caution",children:(0,r.jsxs)(n.p,{children:["This requires ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/formatToParts",children:"Intl.DateTimeFormat.prototype.formatToParts"})," which is not available in IE11. Please use our ",(0,r.jsx)(n.a,{href:"/docs/polyfills/intl-datetimeformat",children:"polyfill"})," if you plan to support IE11."]})}),"\n",(0,r.jsxs)(n.p,{children:["This component provides more customization to ",(0,r.jsx)(n.code,{children:"FormattedDate"})," by allowing children function to have access to underlying parts of the formatted date. The available parts are listed ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat/formatToParts",children:"here"})]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"props: Intl.DateTimeFormatOptions &\n {\n value: any,\n format: string,\n children: (parts: Intl.DateTimeFormatPart[]) => ReactElement,\n }\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedDateParts\n value={new Date(1459832991883)}\n year="numeric"\n month="long"\n day="2-digit"\n>\n {parts => (\n <>\n <b>{parts[0].value}</b>\n {parts[1].value}\n <small>{parts[2].value}</small>\n </>\n )}\n</FormattedDateParts>\n'})}),"\n",(0,r.jsx)(n.h2,{id:"formattedtime",children:"FormattedTime"}),"\n",(0,r.jsxs)(n.p,{children:["This component uses the ",(0,r.jsx)(n.a,{href:"/docs/react-intl/api#formattime",children:(0,r.jsx)(n.code,{children:"formatTime"})})," and ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat",children:(0,r.jsx)(n.code,{children:"Intl.DateTimeFormat"})})," APIs and has ",(0,r.jsx)(n.code,{children:"props"})," that correspond to the ",(0,r.jsx)(n.code,{children:"DateTimeFormatOptions"})," specified above, with the following defaults:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",children:"{\n hour: 'numeric',\n minute: 'numeric',\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",children:"props: DateTimeFormatOptions &\n {\n value: any,\n format: string,\n children: (formattedDate: string) => ReactElement,\n }\n"})}),"\n",(0,r.jsxs)(n.p,{children:["By default ",(0,r.jsx)(n.code,{children:"<FormattedTime>"})," will render the formatted time into a ",(0,r.jsx)(n.code,{children:"React.Fragment"}),". If you need to customize rendering, you can either wrap it with another React element (recommended), or pass a function as the child."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:"<FormattedTime value={new Date(1459832991883)} />\n"})}),"\n",(0,r.jsx)(n.h2,{id:"formattedtimeparts",children:"FormattedTimeParts"}),"\n",(0,r.jsx)(n.admonition,{title:"browser support",type:"caution",children:(0,r.jsxs)(n.p,{children:["This requires ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/formatToParts",children:"Intl.DateTimeFormat.prototype.formatToParts"})," which is not available in IE11. Please use our ",(0,r.jsx)(n.a,{href:"/docs/polyfills/intl-datetimeformat",children:"polyfill"})," if you plan to support IE11."]})}),"\n",(0,r.jsxs)(n.p,{children:["This component provides more customization to ",(0,r.jsx)(n.code,{children:"FormattedTime"})," by allowing children function to have access to underlying parts of the formatted date. The available parts are listed ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat/formatToParts",children:"here"})]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"props: Intl.DateTimeFormatOptions &\n {\n value: any,\n format: string,\n children: (parts: Intl.DateTimeFormatPart[]) => ReactElement,\n }\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:"<FormattedTimeParts value={new Date(1459832991883)}>\n {parts => (\n <>\n <b>{parts[0].value}</b>\n {parts[1].value}\n <small>{parts[2].value}</small>\n </>\n )}\n</FormattedTimeParts>\n"})}),"\n",(0,r.jsx)(n.h2,{id:"formatteddatetimerange",children:"FormattedDateTimeRange"}),"\n",(0,r.jsx)(n.admonition,{title:"browser support",type:"caution",children:(0,r.jsxs)(n.p,{children:["This requires stage-3 API ",(0,r.jsx)(n.a,{href:"https://github.com/tc39/proposal-intl-DateTimeFormat-formatRange",children:"Intl.RelativeTimeFormat.prototype.formatRange"})," which has limited browser support. Please use our ",(0,r.jsx)(n.a,{href:"/docs/polyfills/intl-datetimeformat",children:"polyfill"})," if you plan to support them."]})}),"\n",(0,r.jsxs)(n.p,{children:["This component uses the ",(0,r.jsx)(n.a,{href:"/docs/react-intl/api#formatdatetimerange",children:(0,r.jsx)(n.code,{children:"formatDateTimeRange"})})," and ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat",children:(0,r.jsx)(n.code,{children:"Intl.DateTimeFormat"})})," APIs and has ",(0,r.jsx)(n.code,{children:"props"})," that correspond to the ",(0,r.jsx)(n.code,{children:"DateTimeFormatOptions"})," specified above"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",children:"props: DateTimeFormatOptions &\n {\n from: number | Date,\n to: number | Date,\n children: (formattedDate: string) => ReactElement,\n }\n"})}),"\n",(0,r.jsxs)(n.p,{children:["By default ",(0,r.jsx)(n.code,{children:"<FormattedDateTimeRange>"})," will render the formatted time into a ",(0,r.jsx)(n.code,{children:"React.Fragment"}),". If you need to customize rendering, you can either wrap it with another React element (recommended), or pass a function as the child."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:"<FormattedDateTimeRange\n from={new Date('2020-1-1')}\n to={new Date('2020-1-15')}\n/>\n"})}),"\n",(0,r.jsx)(n.h2,{id:"formattedrelativetime",children:"FormattedRelativeTime"}),"\n",(0,r.jsx)(n.admonition,{title:"browser support",type:"caution",children:(0,r.jsxs)(n.p,{children:["This requires ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat",children:"Intl.RelativeTimeFormat"})," which has limited browser support. Please use our ",(0,r.jsx)(n.a,{href:"/docs/polyfills/intl-relativetimeformat",children:"polyfill"})," if you plan to support them."]})}),"\n",(0,r.jsxs)(n.p,{children:["This component uses the ",(0,r.jsx)(n.a,{href:"/docs/react-intl/api#formatrelativetime",children:(0,r.jsx)(n.code,{children:"formatRelativeTime"})})," API and has ",(0,r.jsx)(n.code,{children:"props"})," that correspond to the following relative formatting options:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"type RelativeTimeFormatOptions = {\n numeric?: 'always' | 'auto'\n style?: 'long' | 'short' | 'narrow'\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Prop Types:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"props: RelativeTimeFormatOptions &\n {\n value: number,\n unit: Unit,\n format: string,\n updateIntervalInSeconds: number,\n children: (formattedDate: string) => ReactElement,\n }\n"})}),"\n",(0,r.jsxs)(n.p,{children:["By default ",(0,r.jsx)(n.code,{children:"<FormattedRelativeTime>"})," will render the formatted relative time into a ",(0,r.jsx)(n.code,{children:"React.Fragment"}),". If you need to customize rendering, you can either wrap it with another React element (recommended), or pass a function as the child."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedRelativeTime value={0} numeric="auto" updateIntervalInSeconds={1} />\n'})}),"\n",(0,r.jsx)(n.admonition,{title:"maximum interval",type:"info",children:(0,r.jsxs)(n.p,{children:["You can adjust the maximum interval that the component will re-render by setting the ",(0,r.jsx)(n.code,{children:"updateIntervalInSeconds"}),". A falsy value will turn off auto-updating. The updating is smart and will schedule the next update for the next ",(0,r.jsx)(n.em,{children:"interesting moment"}),"."]})}),"\n",(0,r.jsxs)(n.p,{children:["An ",(0,r.jsx)(n.em,{children:"interesting moment"})," is defined as the next non-fractional ",(0,r.jsx)(n.code,{children:"value"})," for that ",(0,r.jsx)(n.code,{children:"unit"}),". For example:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:"<FormattedRelativeTime value={-50} updateIntervalInSeconds={1} />\n"})}),"\n",(0,r.jsxs)(n.p,{children:["This will initially renders ",(0,r.jsx)(n.code,{children:"59 seconds ago"}),", after 1 second, will render ",(0,r.jsx)(n.code,{children:"1 minute ago"}),", and will not re-render until a full minute goes by, it'll render ",(0,r.jsx)(n.code,{children:"2 minutes ago"}),". It will not try to render ",(0,r.jsx)(n.code,{children:"1.2 minutes ago"}),"."]}),"\n",(0,r.jsx)(n.admonition,{title:"limitation",type:"caution",children:(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"updateIntervalInSeconds"})," cannot be enabled for ",(0,r.jsx)(n.code,{children:"unit"})," longer than ",(0,r.jsx)(n.code,{children:"hour"})," (so not for ",(0,r.jsx)(n.code,{children:"day"}),", ",(0,r.jsx)(n.code,{children:"week"}),", ",(0,r.jsx)(n.code,{children:"quarter"}),", ",(0,r.jsx)(n.code,{children:"year"}),"). This is primarily because it doesn't make sense to schedule a timeout in ",(0,r.jsx)(n.code,{children:"day"}),"s, and the number of ",(0,r.jsx)(n.code,{children:"ms"})," in a day is larger than the max timeout that ",(0,r.jsx)(n.code,{children:"setTimeout"})," accepts."]})}),"\n",(0,r.jsx)(n.h2,{id:"formattednumber",children:"FormattedNumber"}),"\n",(0,r.jsxs)(n.p,{children:["This component uses the ",(0,r.jsx)(n.a,{href:"/docs/react-intl/api#formatnumber",children:(0,r.jsx)(n.code,{children:"formatNumber"})})," and ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat",children:(0,r.jsx)(n.code,{children:"Intl.NumberFormat"})})," APIs and has ",(0,r.jsx)(n.code,{children:"props"})," that correspond to ",(0,r.jsx)(n.code,{children:"Intl.NumberFormatOptions"}),"."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"props: NumberFormatOptions &\n {\n value: number,\n format: string,\n children: (formattedNumber: string) => ReactElement,\n }\n"})}),"\n",(0,r.jsxs)(n.p,{children:["By default ",(0,r.jsx)(n.code,{children:"<FormattedNumber>"})," will render the formatted number into a ",(0,r.jsx)(n.code,{children:"React.Fragment"}),". If you need to customize rendering, you can either wrap it with another React element (recommended), or pass a function as the child."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:"<FormattedNumber value={1000} />\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example Formatting Currency Values"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedNumber value={1000} style="currency" currency="USD" />\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:["Formatting Number using ",(0,r.jsx)(n.code,{children:"unit"})]})}),"\n",(0,r.jsxs)(n.p,{children:["Currently this is part of ES2020 ",(0,r.jsx)(n.a,{href:"https://tc39.es/ecma402/#numberformat-objects",children:"NumberFormat"}),".\nWe've provided a polyfill ",(0,r.jsx)(n.a,{href:"/docs/polyfills/intl-numberformat",children:"here"})," and ",(0,r.jsx)(n.code,{children:"react-intl"})," types allow users to pass\nin a ",(0,r.jsx)(n.a,{href:"/docs/polyfills/intl-numberformat#SupportedUnits",children:"sanctioned unit"}),". For example:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedNumber\n value={1000}\n style="unit"\n unit="kilobyte"\n unitDisplay="narrow"\n/>\n'})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedNumber\n value={1000}\n unit="fahrenheit"\n unitDisplay="long"\n style="unit"\n/>\n'})}),"\n",(0,r.jsx)(n.h2,{id:"formattednumberparts",children:"FormattedNumberParts"}),"\n",(0,r.jsx)(n.admonition,{title:"browser support",type:"caution",children:(0,r.jsxs)(n.p,{children:["This requires ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/formatToParts",children:"Intl.NumberFormat.prototype.formatToParts"})," which is not available in IE11. Please use our ",(0,r.jsx)(n.a,{href:"/docs/polyfills/intl-numberformat",children:"polyfill"})," if you plan to support IE11."]})}),"\n",(0,r.jsxs)(n.p,{children:["This component provides more customization to ",(0,r.jsx)(n.code,{children:"FormattedNumber"})," by allowing children function to have access to underlying parts of the formatted number. The available parts are listed ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat/formatToParts",children:"here"}),"."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"props: NumberFormatOptions &\n {\n value: number,\n format: string,\n children: (parts: Intl.NumberFormatPart[]) => ReactElement,\n }\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:"<FormattedNumberParts value={1000}>\n {parts => (\n <>\n <b>{parts[0].value}</b>\n {parts[1].value}\n <small>{parts[2].value}</small>\n </>\n )}\n</FormattedNumberParts>\n"})}),"\n",(0,r.jsx)(n.h2,{id:"formattedplural",children:"FormattedPlural"}),"\n",(0,r.jsxs)(n.p,{children:["This component uses the ",(0,r.jsx)(n.a,{href:"/docs/react-intl/api#formatplural",children:(0,r.jsx)(n.code,{children:"formatPlural"})})," API and ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules",children:(0,r.jsx)(n.code,{children:"Intl.PluralRules"})})," has ",(0,r.jsx)(n.code,{children:"props"})," that correspond to ",(0,r.jsx)(n.code,{children:"Intl.PluralRulesOptions"}),"."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"props: PluralFormatOptions &\n {\n value: any,\n\n other: ReactElement,\n zero: ReactElement,\n one: ReactElement,\n two: ReactElement,\n few: ReactElement,\n many: ReactElement,\n\n children: (formattedPlural: ReactElement) => ReactElement,\n }\n"})}),"\n",(0,r.jsxs)(n.p,{children:["By default ",(0,r.jsx)(n.code,{children:"<FormattedPlural>"})," will select a ",(0,r.jsx)(n.a,{href:"http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html",children:"plural category"})," (",(0,r.jsx)(n.code,{children:"zero"}),", ",(0,r.jsx)(n.code,{children:"one"}),", ",(0,r.jsx)(n.code,{children:"two"}),", ",(0,r.jsx)(n.code,{children:"few"}),", ",(0,r.jsx)(n.code,{children:"many"}),", or ",(0,r.jsx)(n.code,{children:"other"}),") and render the corresponding React element into a ",(0,r.jsx)(n.code,{children:"React.Fragment"}),". If you need to customize rendering, you can either wrap it with another React element (recommended), or pass a function as the child."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedPlural value={10} one="message" other="messages" />\n'})}),"\n",(0,r.jsx)(n.h2,{id:"formattedlist",children:"FormattedList"}),"\n",(0,r.jsx)(n.admonition,{title:"browser support",type:"caution",children:(0,r.jsxs)(n.p,{children:["This requires ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat",children:"Intl.ListFormat"})," which has limited browser support. Please use our ",(0,r.jsx)(n.a,{href:"/docs/polyfills/intl-listformat",children:"polyfill"})," if you plan to support them."]})}),"\n",(0,r.jsxs)(n.p,{children:["This component uses ",(0,r.jsx)(n.a,{href:"/docs/react-intl/api#formatlist",children:(0,r.jsx)(n.code,{children:"formatList"})})," API and ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ListFormat",children:"Intl.ListFormat"}),". Its props corresponds to ",(0,r.jsx)(n.code,{children:"Intl.ListFormatOptions"}),"."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",children:"props: ListFormatOptions &\n {\n children: (chunksOrString: string | React.ReactElement[]) => ReactElement,\n }\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsxs)(n.p,{children:["When the locale is ",(0,r.jsx)(n.code,{children:"en"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:"<FormattedList type=\"conjunction\" value={['Me', 'myself', 'I']} />\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:"<FormattedList type=\"conjunction\" value={['Me', <b>myself</b>, 'I']} />\n"})}),"\n",(0,r.jsx)(n.h2,{id:"formattedlistparts",children:"FormattedListParts"}),"\n",(0,r.jsx)(n.admonition,{title:"browser support",type:"caution",children:(0,r.jsxs)(n.p,{children:["This requires ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat",children:"Intl.ListFormat"})," which has limited browser support. Please use our ",(0,r.jsx)(n.a,{href:"/docs/polyfills/intl-listformat",children:"polyfill"})," if you plan to support them."]})}),"\n",(0,r.jsxs)(n.p,{children:["This component uses ",(0,r.jsx)(n.a,{href:"/docs/react-intl/api#formatlisttoparts",children:(0,r.jsx)(n.code,{children:"formatListToParts"})})," API and ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ListFormat",children:"Intl.ListFormat"}),". Its props corresponds to ",(0,r.jsx)(n.code,{children:"Intl.ListFormatOptions"}),"."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",children:"props: ListFormatOptions &\n {\n children: (chunks: Array<React.ReactElement | string>) => ReactElement,\n }\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsxs)(n.p,{children:["When the locale is ",(0,r.jsx)(n.code,{children:"en"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:"<FormattedListParts type=\"conjunction\" value={['Me', 'myself', 'I']}>\n {parts => (\n <>\n <b>{parts[0].value}</b>\n {parts[1].value}\n <small>{parts[2].value}</small>\n {parts[3].value}\n <small>{parts[4].value}</small>\n </>\n )}\n</FormattedListParts>\n"})}),"\n",(0,r.jsx)(n.h2,{id:"formatteddisplayname",children:"FormattedDisplayName"}),"\n",(0,r.jsx)(n.admonition,{title:"browser support",type:"caution",children:(0,r.jsxs)(n.p,{children:["This requires ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames",children:"Intl.DisplayNames"})," which has limited browser support. Please use our ",(0,r.jsx)(n.a,{href:"/docs/polyfills/intl-displaynames",children:"polyfill"})," if you plan to support them."]})}),"\n",(0,r.jsxs)(n.p,{children:["This component uses ",(0,r.jsx)(n.a,{href:"/docs/react-intl/api#formatdisplayname",children:(0,r.jsx)(n.code,{children:"formatDisplayName"})})," and ",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames",children:(0,r.jsx)(n.code,{children:"Intl.DisplayNames"})}),"\nhas ",(0,r.jsx)(n.code,{children:"props"})," that correspond to ",(0,r.jsx)(n.code,{children:"DisplayNameOptions"}),". You might need a ",(0,r.jsx)(n.a,{href:"/docs/polyfills/intl-displaynames",children:"polyfill"}),"."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"props: FormatDisplayNameOptions &\n {\n value: string | number | Record<string, unknown>,\n }\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsxs)(n.p,{children:["When the locale is ",(0,r.jsx)(n.code,{children:"en"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedDisplayName type="language" value="zh-Hans-SG" />\n'})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedDisplayName type="currency" value="JPY" />\n'})}),"\n",(0,r.jsx)(n.h2,{id:"formattedmessage",children:"FormattedMessage"}),"\n",(0,r.jsxs)(n.p,{children:["This component uses the ",(0,r.jsx)(n.a,{href:"/docs/react-intl/api#formatmessage",children:(0,r.jsx)(n.code,{children:"formatMessage"})})," API and has ",(0,r.jsx)(n.code,{children:"props"})," that correspond to a ",(0,r.jsx)(n.a,{href:"#message-descriptor",children:"Message Descriptor"}),"."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Props:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",children:"props: MessageDescriptor &\n {\n values: object,\n tagName: string,\n children: (chunks: ReactElement) => ReactElement,\n }\n"})}),"\n",(0,r.jsx)(n.h3,{id:"message-syntax",children:"Message Syntax"}),"\n",(0,r.jsxs)(n.p,{children:["String/Message formatting is a paramount feature of React Intl and it builds on ",(0,r.jsx)(n.a,{href:"https://unicode-org.github.io/icu/userguide/format_parse/messages",children:"ICU Message Formatting"})," by using the ",(0,r.jsx)(n.a,{href:"/docs/core-concepts/icu-syntax",children:"ICU Message Syntax"}),". This message syntax allows for simple to complex messages to be defined, translated, and then formatted at runtime."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Simple Message:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"Hello, {name}\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Complex Message:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"Hello, {name}, you have {itemCount, plural,\n =0 {no items}\n one {# item}\n other {# items}\n}.\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"See:"})," The ",(0,r.jsx)(n.a,{href:"/docs/core-concepts/icu-syntax",children:"Message Syntax Guide"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"message-descriptor",children:"Message Descriptor"}),"\n",(0,r.jsxs)(n.p,{children:["React Intl has a Message Descriptor concept which is used to define your app's default messages/strings. ",(0,r.jsx)(n.code,{children:"<FormattedMessage>"})," have props which correspond to a Message Descriptor. The Message Descriptors work very well for providing the data necessary for having the strings/messages translated, and they contain the following properties:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsxs)(n.strong,{children:[(0,r.jsx)(n.code,{children:"id"}),":"]})," A unique, stable identifier for the message"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsxs)(n.strong,{children:[(0,r.jsx)(n.code,{children:"description"}),":"]})," Context for the translator about how it's used in the UI"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsxs)(n.strong,{children:[(0,r.jsx)(n.code,{children:"defaultMessage"}),":"]})," The default message (probably in English)"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",children:"type MessageDescriptor = {\n id?: string\n defaultMessage?: string\n description?: string\n}\n"})}),"\n",(0,r.jsx)(n.admonition,{title:"compile message descriptors",type:"info",children:(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.a,{href:"/docs/tooling/babel-plugin",children:"babel-plugin-formatjs"})," and ",(0,r.jsx)(n.a,{href:"/docs/tooling/ts-transformer",children:"@formatjs/ts-transformer"})," packages can be used to compile Message Descriptors defined in JavaScript source files into AST for performance."]})}),"\n",(0,r.jsx)(n.h3,{id:"message-formatting-fallbacks",children:"Message Formatting Fallbacks"}),"\n",(0,r.jsx)(n.p,{children:"The message formatting APIs go the extra mile to provide fallbacks for the common situations where formatting fails; at the very least a non-empty string should always be returned. Here's the message formatting fallback algorithm:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["Lookup and format the translated message at ",(0,r.jsx)(n.code,{children:"id"}),", passed to ",(0,r.jsx)(n.a,{href:"#intlprovider",children:(0,r.jsx)(n.code,{children:"<IntlProvider>"})}),"."]}),"\n",(0,r.jsxs)(n.li,{children:["Fallback to formatting the ",(0,r.jsx)(n.code,{children:"defaultMessage"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:["Fallback to translated message at ",(0,r.jsx)(n.code,{children:"id"}),"'s source."]}),"\n",(0,r.jsxs)(n.li,{children:["Fallback to ",(0,r.jsx)(n.code,{children:"defaultMessage"})," source."]}),"\n",(0,r.jsxs)(n.li,{children:["Fallback to the literal message ",(0,r.jsx)(n.code,{children:"id"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"usage",children:"Usage"}),"\n",(0,r.jsxs)(n.p,{children:["By default ",(0,r.jsx)(n.code,{children:"<FormattedMessage>"})," will render the formatted string into a ",(0,r.jsx)(n.code,{children:"<React.Fragment>"}),". If you need to customize rendering, you can either wrap it with another React element (recommended), specify a different ",(0,r.jsx)(n.code,{children:"tagName"})," (e.g., ",(0,r.jsx)(n.code,{children:"'div'"}),"), or pass a function as the child."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedMessage\n id="app.greeting"\n description="Greeting to welcome the user to the app"\n defaultMessage="Hello, {name}!"\n values={{\n name: \'Eric\',\n }}\n/>\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Example:"})," function as the child"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedMessage id="title">{txt => <h1>{txt}</h1>}</FormattedMessage>\n'})}),"\n",(0,r.jsx)(n.admonition,{title:"simple message",type:"info",children:(0,r.jsxs)(n.p,{children:["Messages can be simple strings ",(0,r.jsx)(n.em,{children:"without"})," placeholders, and that's the most common type of message. This case is highly-optimized, but still has the benefits of the ",(0,r.jsx)(n.a,{href:"#message-formatting-fallbacks",children:"fallback procedure"}),"."]})}),"\n",(0,r.jsx)(n.h3,{id:"rich-text-formatting",children:"Rich Text Formatting"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"<FormattedMessage>"})," also supports rich-text formatting by specifying a XML tag in the message & resolving that tag in the ",(0,r.jsx)(n.code,{children:"values"})," prop. Here's an example:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedMessage\n id="app.greeting"\n description="Greeting to welcome the user to the app"\n defaultMessage="Hello, <b>Eric</b> {icon}"\n values={{\n b: chunks => <b>{chunks}</b>,\n icon: <svg />,\n }}\n/>\n'})}),"\n",(0,r.jsx)(n.p,{children:"By allowing embedding XML tag we want to make sure contextual information is not lost when you need to style part of the string. In a more complicated example like:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedMessage\n id="foo"\n defaultMessage="To buy a shoe, <a>visit our website</a> and <cta>buy a shoe</cta>"\n values={{\n a: chunks => (\n <a\n class="external_link"\n target="_blank"\n href="https://www.example.com/shoe"\n >\n {chunks}\n </a>\n ),\n cta: chunks => <strong class="important">{chunks}</strong>,\n }}\n/>\n'})}),"\n",(0,r.jsx)(n.h3,{id:"function-as-the-child",children:"Function as the child"}),"\n",(0,r.jsxs)(n.p,{children:["Since rich text formatting allows embedding ",(0,r.jsx)(n.code,{children:"ReactElement"}),", in function as the child scenario, the function will receive the formatted message chunks as a single parameter."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-tsx",metastring:"live",live:!0,children:'<FormattedMessage\n id="foo"\n defaultMessage="To buy a shoe, <a>visit our website</a> and <cta>buy a shoe</cta>"\n values={{\n a: chunks => (\n <a\n class="external_link"\n target="_blank"\n href="https://www.example.com/shoe"\n >\n {chunks}\n </a>\n ),\n cta: chunks => <strong class="important">{chunks}</strong>,\n }}\n>\n {chunks => <h2>{chunks}</h2>}\n</FormattedMessage>\n'})}),"\n",(0,r.jsxs)(n.p,{children:["All the rich text gets translated together which yields higher quality output. This brings feature-parity with other translation libs as well, such as ",(0,r.jsx)(n.a,{href:"https://projectfluent.org/",children:"fluent"})," by Mozilla (using ",(0,r.jsx)(n.code,{children:"overlays"})," concept)."]}),"\n",(0,r.jsxs)(n.p,{children:["Extending this also allows users to potentially utilizing other rich text format, like ",(0,r.jsx)(n.a,{href:"https://daringfireball.net/projects/markdown/",children:"Markdown"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8299:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>l});var s=t(7378);const r={},a=s.createContext(r);function i(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]);