-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathsearch-doc.json
1 lines (1 loc) · 267 KB
/
search-doc.json
1
{"searchDocs":[{"title":"Basic Internationalization Principles","type":0,"sectionRef":"#","url":"/docs/core-concepts/basic-internationalization-principles","content":"","keywords":"","version":"Next"},{"title":"What Is Internationalization and Why Does It Matter?","type":1,"pageTitle":"Basic Internationalization Principles","url":"/docs/core-concepts/basic-internationalization-principles#what-is-internationalization-and-why-does-it-matter","content":" Internationalized software supports the languages and cultural customs of people throughout the world. The Web reaches all parts of the world. Internationalized web apps provide a great user experience for people everywhere. Localized software adapts to a specific language and culture by translating text into the user's language and formatting data in accordance with the user's expectations. An app is typically localized for a small set of locales. The ECMA-402 JavaScript internationalization specification has an excellent overview. ","version":"Next","tagName":"h2"},{"title":"Locales: Language and Region","type":1,"pageTitle":"Basic Internationalization Principles","url":"/docs/core-concepts/basic-internationalization-principles#locales-language-and-region","content":" A "locale" refers to the lingual and cultural expectations for a region. It is represented using a "locale code" defined in UTS LDML. This code is comprised of several parts separated by hyphens (-). The first part is a short string representing the language. The second, optional, part is a short string representing the region. Additionally, various extensions and variants can be specified. Typically, web apps are localized to just the language or language-region combination. Examples of such locale codes are: en for Englishen-US for English as spoken in the United Statesen-GB for English as spoken in the United Kingdomes-AR for Spanish as spoken in Argentinaar-001 for Arabic as spoken throughout the worldar-AE for Arabic as spoken in United Arab Emirates Most internationalized apps only support a small list of locales. ","version":"Next","tagName":"h2"},{"title":"Translating Strings","type":1,"pageTitle":"Basic Internationalization Principles","url":"/docs/core-concepts/basic-internationalization-principles#translating-strings","content":" You likely have some text in your application that is in a natural language such as English or Japanese. In order to support other locales, you will need to translate these strings. FormatJS provides a mechanism to let you write the core "software" of your application without special code for different translations. The considerations for each locale are encapsulated in your translated strings and our libraries. const messages = { en: { GREETING: 'Hello {name}', }, fr: { GREETING: 'Bonjour {name}', }, } We use the ICU Message syntax which is also used in Java, C, PHP and various other platforms. ","version":"Next","tagName":"h2"},{"title":"Bundling Translated Strings","type":1,"pageTitle":"Basic Internationalization Principles","url":"/docs/core-concepts/basic-internationalization-principles#bundling-translated-strings","content":" It is common to organize your translations primarily by locale, because you only need the translations for the user's current locale. Our template and component library integrations are designed to work with the translations for a single locale. If your app is complex, you can further subdivide your translations, such as by page or section of the site. ","version":"Next","tagName":"h2"},{"title":"Structure of Code","type":1,"pageTitle":"Basic Internationalization Principles","url":"/docs/core-concepts/basic-internationalization-principles#structure-of-code","content":" The actual formatting and presentation of data and translated strings typically takes these steps: Determine the user's locale, as described in Runtime Environments guide.Setup one of FormatJS's integrations with the following data: the user's current localetranslated strings for that localeoptionally, any custom formats Call the template engine, passing the data that needs formatting. ","version":"Next","tagName":"h2"},{"title":"Message Syntax","type":0,"sectionRef":"#","url":"/docs/core-concepts/icu-syntax","content":"","keywords":"","version":"Next"},{"title":"Basic Principles","type":1,"pageTitle":"Message Syntax","url":"/docs/core-concepts/icu-syntax#basic-principles","content":" The simplest transform for the message is a literal string. Hello everyone All other transforms are done using replacements called "arguments". They are enclosed in curly braces ({ and }) and refer to a value in the input data. ","version":"Next","tagName":"h2"},{"title":"Simple Argument","type":1,"pageTitle":"Message Syntax","url":"/docs/core-concepts/icu-syntax#simple-argument","content":" You can use a {key} argument for placing a value into the message. The key is looked up in the input data, and the string is interpolated with its value. ICU Message Hello {who} Values as JSON Result ","version":"Next","tagName":"h2"},{"title":"Formatted Argument","type":1,"pageTitle":"Message Syntax","url":"/docs/core-concepts/icu-syntax#formatted-argument","content":" Values can also be formatted based on their type. You use a {key, type, format} argument to do that. The elements of the argument are: key is where in the input data to find the datatype is optional, and is how to interpret the value (see below)format is optional, and is a further refinement on how to display that type of data ICU Message I have {numCats, number} cats. Values as JSON Result ","version":"Next","tagName":"h2"},{"title":"number Type","type":1,"pageTitle":"Message Syntax","url":"/docs/core-concepts/icu-syntax#number-type","content":" This type is used to format numbers in a way that is sensitive to the locale. It understands the following values for the optional format element of the argument: ICU Message I have {numCats, number} cats. Values as JSON Result ICU Message Almost {pctBlack, number, ::percent} of them are black. Values as JSON Result Internally it uses the Intl.NumberFormat API. You can define custom values for the format element, which are passed to the Intl.NumberFormat constructor. Sometimes embedding how the number will be formatted provides great context to translators. We also support ICU Number Skeletons using the same syntax: ICU Message The price of this bagel is {num, number, ::sign-always compact-short currency/GBP} Values as JSON Result You can read more about this here. For fine control over decimal precision, you can use the Fraction Precision # and 0 symbols, which specify the number of decimal places to display: ICU Message The duration is {num, number, ::.##} seconds Values as JSON Result Note that the # symbol doesn't render trailing zeroes, as seen in this example: ICU Message The duration is {num, number, ::.##} seconds Values as JSON Result To render trailing zeroes, use the 0 symbol: ICU Message The very precise number is {num, number, ::.00} Values as JSON Result For more details, see Fraction Precision. ","version":"Next","tagName":"h3"},{"title":"date Type","type":1,"pageTitle":"Message Syntax","url":"/docs/core-concepts/icu-syntax#date-type","content":" This type is used to format dates in a way that is sensitive to the locale. It understands the following values for the optional format element of the argument: short is used to format dates in the shortest possible waymedium is used to format dates with short textual representation of the monthlong is used to format dates with long textual representation of the monthfull is used to format dates with the most detail ICU Message Sale begins {start, date, medium} Values as JSON Result Internally it uses the Intl.DateTimeFormat API. You can define custom values for the format element, which are passed to the Intl.DateTimeFormat constructor. ","version":"Next","tagName":"h3"},{"title":"time Type","type":1,"pageTitle":"Message Syntax","url":"/docs/core-concepts/icu-syntax#time-type","content":" This type is used to format times in a way that is sensitive to the locale. It understands the following values for the optional format element of the argument: short is used to format times with hours and minutesmedium is used to format times with hours, minutes, and secondslong is used to format times with hours, minutes, seconds, and timezonefull is the same as long ICU Message Coupon expires at {expire, time, short} Values as JSON Result Internally it uses the Intl.DateTimeFormat API. You can define custom values for the format element, which are passed to the Intl.DateTimeFormat constructor. ","version":"Next","tagName":"h3"},{"title":"Supported DateTime Skeleton","type":1,"pageTitle":"Message Syntax","url":"/docs/core-concepts/icu-syntax#supported-datetime-skeleton","content":" Similar to number type, we also support ICU DateTime skeleton. ICU provides a wide array of pattern to customize date time format. However, not all of them are available via ECMA402's Intl API. Therefore, we only support the following patterns Symbol\tMeaning\tNotesG\tEra designator y\tyear M\tmonth in year L\tstand-alone month in year d\tday in month E\tday of week e\tlocal day of week\te..eee is not supported c\tstand-alone local day of week\tc..ccc is not supported a\tAM/PM marker h\tHour [1-12] H\tHour [0-23] K\tHour [0-11] k\tHour [1-24] m\tMinute s\tSecond z\tTime Zone\t ","version":"Next","tagName":"h3"},{"title":"{select} Format","type":1,"pageTitle":"Message Syntax","url":"/docs/core-concepts/icu-syntax#select-format","content":" The {key, select, matches} is used to choose output by matching a value to one of many choices. (It is similar to the switch statement available in some programming languages.) The key is looked up in the input data. The corresponding value is matched to one of matches and the corresponding output is returned. The key argument must follow Unicode Pattern_Syntax. The matches is a space-separated list of matches. The format of a match is match {output}. (A match is similar to the case statement of the switch found in some programming languages.) The match is a literal value. If it is the same as the value for key then the corresponding output will be used. output is itself a message, so it can be a literal string or also have more arguments nested inside of it. The other match is special and is used if nothing else matches. (This is similar to the default case of the switch found in some programming languages.) danger other is required as per icu4j implementation. We will throw an error if select is used without other. ICU Message {gender, select, male {He will respond shortly.} female {She will respond shortly.} other {They will respond shortly.} } Values as JSON Result Here's an example of nested arguments. ICU Message {isTaxed, select, yes {An additional {tax, number, percent} tax will be collected.} other {No taxes apply.} } Values as JSON Result ","version":"Next","tagName":"h3"},{"title":"{plural} Format","type":1,"pageTitle":"Message Syntax","url":"/docs/core-concepts/icu-syntax#plural-format","content":" The {key, plural, matches} is used to choose output based on the pluralization rules of the current locale. It is very similar to the {select} format above except that the value is expected to be a number and is mapped to a plural category. The match is a literal value and is matched to one of these plural categories. Not all languages use all plural categories. zero: This category is used for languages that have grammar specialized specifically for zero number of items. (Examples are Arabic and Latvian.)one: This category is used for languages that have grammar specialized specifically for one (singular) item. Many languages, but not all, use this plural category. (Many popular Asian languages, such as Chinese and Japanese, do not use this category.)two: This category is used for languages that have grammar specialized specifically for two (dual) items. (Examples are Arabic and Welsh.)few: This category is used for languages that have grammar specialized specifically for a small number (paucal) of items. For some languages this is used for 2-4 items, for some 3-10 items, and other languages have even more complex rules.many: This category is used for languages that have grammar specialized specifically for a larger number of items. (Examples are Arabic, Polish, and Russian.)other: This category is used if the value doesn't match one of the other plural categories. Note that this is used for "plural" for languages (such as English) that have a simple "singular" versus "plural" dichotomy.=value: This is used to match a specific value regardless of the plural categories of the current locale. info Don't use =1 in place of one. one doesn't always mean 1 but rather means singular, which can match to more than number 1 in certain locales. Some locales considered all numbers ends with 1 (like 1, 11, 111) to be singular. danger other is required as per icu4j implementation. We will throw an error if plural is used without other. ICU Message {itemCount, plural, one {Cart: {itemCount, number} item} other {Cart: {itemCount, number} items} } Values as JSON Result ICU Message {itemCount, plural, =0 {You have no items.} one {You have {itemCount, number} item.} other {You have {itemCount, number} items.} } Values as JSON Result In the output of the match, you can use the # special token as a placeholder for the numeric value and it'll be formatted as if it were {key, number}. This is the style we prefer to use. ICU Message {itemCount, plural, =0 {You have no items.} one {You have # item.} other {You have # items.} } Values as JSON Result ","version":"Next","tagName":"h3"},{"title":"{selectordinal} Format","type":1,"pageTitle":"Message Syntax","url":"/docs/core-concepts/icu-syntax#selectordinal-format","content":" The {key, selectordinal, matches} is used to choose output based on the ordinal pluralization rules (1st, 2nd, 3rd, etc.) of the current locale. It is very similar to the {plural} format above except that the value is mapped to an ordinal plural category. The match is a literal value and is matched to one of these plural categories. Not all languages use all plural categories. zero: This category is used for languages that have grammar specialized specifically for zero number of items. (Examples are Arabic and Latvian.)one: This category is used for languages that have grammar specialized specifically for one item. Many languages, but not all, use this plural category. (Many popular Asian languages, such as Chinese and Japanese, do not use this category.)two: This category is used for languages that have grammar specialized specifically for two items. (Examples are Arabic and Welsh.)few: This category is used for languages that have grammar specialized specifically for a small number of items. For some languages this is used for 2-4 items, for some 3-10 items, and other languages have even more complex rules.many: This category is used for languages that have grammar specialized specifically for a larger number of items. (Examples are Arabic, Polish, and Russian.)other: This category is used if the value doesn't match one of the other plural categories. Note that this is used for "plural" for languages (such as English) that have a simple "singular" versus "plural" dichotomy.=value: This is used to match a specific value regardless of the plural categories of the current locale. danger other is required as per icu4j implementation. We will throw an error if selectordinal is used without other. In the output of the match, the # special token can be used as a placeholder for the numeric value and will be formatted as if it were {key, number}. ICU Message It's my cat's {year, selectordinal, one {#st} two {#nd} few {#rd} other {#th} } birthday! Values as JSON Result ","version":"Next","tagName":"h3"},{"title":"Rich Text Formatting","type":1,"pageTitle":"Message Syntax","url":"/docs/core-concepts/icu-syntax#rich-text-formatting","content":" We also support embedded rich text formatting in our message using tags. This allows developers to embed as much text as possible so sentences don't have to be broken up into chunksNOTE: This is not XML/HTML tag ICU Message Our price is <boldThis>{price, number, ::currency/USD precision-integer}</boldThis> with <link>{pct, number, ::percent} discount</link> Values as JSON Result Custom Behavior It is expected that the system using embedded rich text formatting will have methods to handle these placeholders external to this library. The tags will be part of the generated output and can either be post-processed by your own tooling or use the defaultRichTextElements configuration. ","version":"Next","tagName":"h2"},{"title":"Quoting / Escaping","type":1,"pageTitle":"Message Syntax","url":"/docs/core-concepts/icu-syntax#quoting--escaping","content":" The ASCII apostrophe ' (U+0027) can be used to escape syntax characters in the text portion of the message, which mimics the behavior of ICU's quoting/escaping. ICU Message This is not an interpolation: '{word} Values as JSON Result ICU Message These are not interpolations: '{word1} {word2}' Values as JSON Result ICU Message '<notATag> Values as JSON Result ICU Message '<notATag>hello</notATag>' Values as JSON Result Two consecutive ASCII apostrophes represents one ASCII apostrophe, similar to %% in printf represents one %. However, we recommend using curly apostrophe ’ (U+2019) for human-readable strings and only use ASCII apostrophe '(U+0027) in ICU message syntax. ICU Message This '{isn''t}' obvious. Values as JSON Result ","version":"Next","tagName":"h2"},{"title":"Application Workflow","type":0,"sectionRef":"#","url":"/docs/getting-started/application-workflow","content":"","keywords":"","version":"Next"},{"title":"Simple application workflow with a local translation tool","type":1,"pageTitle":"Application Workflow","url":"/docs/getting-started/application-workflow#simple-application-workflow-with-a-local-translation-tool","content":" projectRoot |-- src | |-- App.js |-- extracted | |-- en.json |-- lang | |-- fr.json | |-- de.json |-- package.json |-- .eslintrc.js The extracted translation files live in the extracted folder since they have a different internal structure (e.g. they contain additional information like the comments). The translation files produced during the translation process are stored in the lang folder. ","version":"Next","tagName":"h2"},{"title":"The workflow","type":1,"pageTitle":"Application Workflow","url":"/docs/getting-started/application-workflow#the-workflow","content":" The workflow looks like this: Extraction: This step aggregates all defaultMessages from your application into a single JSON file along with description, ready to be translated.Edit: Edit the translations, save when done.The changes immediately show up in your build ","version":"Next","tagName":"h3"},{"title":"Complex application workflow with a cloud based translation service","type":1,"pageTitle":"Application Workflow","url":"/docs/getting-started/application-workflow#complex-application-workflow-with-a-cloud-based-translation-service","content":" ","version":"Next","tagName":"h2"},{"title":"Project Structure","type":1,"pageTitle":"Application Workflow","url":"/docs/getting-started/application-workflow#project-structure","content":" A minimal i18n-friendly project can have the following structure: projectRoot |-- src | |-- App.js |-- lang | |-- en-US.json | |-- fr.json |-- package.json |-- .eslintrc.js where lang folder is where the aggregated strings file from your application would live. Integration with 3rd-party translation vendor can consume the en-US.json file and produce fr.json or other locale files accordingly. ","version":"Next","tagName":"h3"},{"title":"Pipeline","type":1,"pageTitle":"Application Workflow","url":"/docs/getting-started/application-workflow#pipeline","content":" A generic translation pipeline looks something like this: Extraction: This step aggregates all defaultMessages from your application into a single JSON file along with description, ready to be translated.Upload Messages: This step uploads the JSON file to your translation vendor.Download Translations: This step either polls your translation vendor or hook into your vendor to download translated messages in the set of locales that you configured.Commit: This commits back translation messages to the codebase. ","version":"Next","tagName":"h3"},{"title":"Where formatjs comes in","type":1,"pageTitle":"Application Workflow","url":"/docs/getting-started/application-workflow#where-formatjs-comes-in","content":" The goal of this project is not to provide a solution for the whole pipeline, but rather focus on Developer Experience via tooling and best practices so devs are i18n-aware. This includes: Declaring i18n-friendly messagesLinter that enforces such messagesCLI for extraction & compilationPolyfills for a stable i18n runtime environmentsBundler plugin for compiling TypeScript/JavaScript ","version":"Next","tagName":"h2"},{"title":"Message Declaration","type":0,"sectionRef":"#","url":"/docs/getting-started/message-declaration","content":"","keywords":"","version":"Next"},{"title":"Using imperative API intl.formatMessage","type":1,"pageTitle":"Message Declaration","url":"/docs/getting-started/message-declaration#using-imperative-api-intlformatmessage","content":" // Method must be exactly `intl.formatMessage` intl.formatMessage( { description: 'A message', // Description should be a string literal defaultMessage: 'My name is {name}', // Message should be a string literal }, { name: userName, } // Values should be an object literal, but not necessarily every value inside ) ","version":"Next","tagName":"h2"},{"title":"Using React API <FormattedMessage/>","type":1,"pageTitle":"Message Declaration","url":"/docs/getting-started/message-declaration#using-react-api-formattedmessage","content":" import {FormattedMessage} from 'react-intl' ;<FormattedMessage description="A message" // Description should be a string literal defaultMessage="My name is {name}" // Message should be a string literal values={ { name: userName, } // Values should be an object literal, but not necessarily every value inside } /> ","version":"Next","tagName":"h2"},{"title":"Using Vue API & template methods such as $formatMessage","type":1,"pageTitle":"Message Declaration","url":"/docs/getting-started/message-declaration#using-vue-api--template-methods-such-as-formatmessage","content":" <template> <p>{{ $formatNumber(3, {style: 'currency', currency: 'USD'}) }}</p> </template> ","version":"Next","tagName":"h2"},{"title":"Pre-declaring using defineMessage for later consumption (less recommended)","type":1,"pageTitle":"Message Declaration","url":"/docs/getting-started/message-declaration#pre-declaring-using-definemessage-for-later-consumption-less-recommended","content":" import {defineMessage} from 'react-intl' const message = defineMessage({ description: 'A message', // Description should be a string literal defaultMessage: 'My name is {name}', // Message should be a string literal }) intl.formatMessage(message, {name: 'John'}) // My name is John <FormattedMessage {...message} values={{ name: 'John', }} /> // My name is John caution We rely on AST to extract messages from the codebase, so make sure you call intl.formatMessage(), use our builtin React components, use our Vue methods or configure --additionalFunctionNames/--additionalComponentNames in our CLI properly. caution You can declare a message without immediately formatting it with defineMessage and our extractor would still be able to extract it. However, our enforce-placeholders linter rule won't be able to analyze it. ","version":"Next","tagName":"h2"},{"title":"Installation","type":0,"sectionRef":"#","url":"/docs/getting-started/installation","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Installation","url":"/docs/getting-started/installation#installation","content":" npmyarn npm i -S react react-intl ","version":"Next","tagName":"h2"},{"title":"Minimal Application","type":1,"pageTitle":"Installation","url":"/docs/getting-started/installation#minimal-application","content":" After following the step above, you should be able to get a minimal application like this running: NodeReactVue3 import * as React from 'react' import {IntlProvider, FormattedMessage, FormattedNumber} from 'react-intl' // Translated messages in French with matching IDs to what you declared const messagesInFrench = { myMessage: "Aujourd'hui, nous sommes le {ts, date, ::yyyyMMdd}", } export default function App() { return ( <IntlProvider messages={messagesInFrench} locale="fr" defaultLocale="en"> <p> <FormattedMessage id="myMessage" defaultMessage="Today is {ts, date, ::yyyyMMdd}" values={{ts: Date.now()}} /> <br /> <FormattedNumber value={19} style="currency" currency="EUR" /> </p> </IntlProvider> ) } Output <p> Aujourd'hui, nous sommes le 23/07/2020 <br /> 19,00 € </p> ","version":"Next","tagName":"h2"},{"title":"Adding our babel-plugin/TypeScript Transformer for compilation","type":1,"pageTitle":"Installation","url":"/docs/getting-started/installation#adding-our-babel-plugintypescript-transformer-for-compilation","content":" Our tooling supports babel, ts-loader, ts-jest, rollup-plugin-typescript2 & ts-patch for message compilation: ","version":"Next","tagName":"h2"},{"title":"Babel","type":1,"pageTitle":"Installation","url":"/docs/getting-started/installation#babel","content":" If you're using babel, add babel-plugin-formatjs to your dependencies: npmyarn npm i -D babel-plugin-formatjs and add it to your babel.config.js or .babelrc: { "plugins": [ [ "formatjs", { "idInterpolationPattern": "[sha512:contenthash:base64:6]", "ast": true } ] ] } ","version":"Next","tagName":"h3"},{"title":"ts-loader","type":1,"pageTitle":"Installation","url":"/docs/getting-started/installation#ts-loader","content":" npmyarn npm i -D @formatjs/ts-transformer import {transform} from '@formatjs/ts-transformer' module.exports = { ...otherConfigs, module: { rules: [ { test: /\\.tsx?$/, use: [ { loader: 'ts-loader', options: { getCustomTransformers() { return { before: [ transform({ overrideIdFn: '[sha512:contenthash:base64:6]', }), ], } }, }, }, ], }, ], }, } ","version":"Next","tagName":"h3"},{"title":"ts-jest in jest.config.js","type":1,"pageTitle":"Installation","url":"/docs/getting-started/installation#ts-jest-in-jestconfigjs","content":" npmyarn npm i -D @formatjs/ts-transformer Take a look at ts-jest guide on how to incorporate custom AST Transformers. ","version":"Next","tagName":"h3"},{"title":"ts-patch","type":1,"pageTitle":"Installation","url":"/docs/getting-started/installation#ts-patch","content":" npmyarn npm i -D @formatjs/ts-transformer { "compilerOptions": { "plugins": [ { "transform": "@formatjs/ts-transformer", "import": "transform", "type": "config", "overrideIdFn": "[sha512:contenthash:base64:6]", "ast": true } ] } } ","version":"Next","tagName":"h3"},{"title":"rollup-plugin-typescript2","type":1,"pageTitle":"Installation","url":"/docs/getting-started/installation#rollup-plugin-typescript2","content":" npmyarn npm i -D @formatjs/ts-transformer // rollup.config.js import typescript from 'rollup-plugin-typescript2' import {transform} from '@formatjs/ts-transformer' export default { input: './main.ts', plugins: [ typescript({ transformers: () => ({ before: [ transform({ overrideIdFn: '[sha512:contenthash:base64:6]', ast: true, }), ], }), }), ], } ","version":"Next","tagName":"h3"},{"title":"Advanced Usage","type":0,"sectionRef":"#","url":"/docs/guides/advanced-usage","content":"","keywords":"","version":"Next"},{"title":"Pre-compiling messages","type":1,"pageTitle":"Advanced Usage","url":"/docs/guides/advanced-usage#pre-compiling-messages","content":" You can also pre-compile all messages into AST using @formatjs/cli compile command and pass that into IntlProvider. This is especially faster since it saves us time parsing string into AST. The use cases for this support are: Server-side rendering or pre-compiling where you can cache the AST and don't have to pay compilation costs multiple time.Desktop apps using Electron or CEF where you can preload/precompile things in advanced before runtime. Caching Since this approach uses AST as the data source, changes to @formatjs/icu-messageformat-parser's AST will require cache invalidation. Asset Size AST is also slightly larger in size than regular string messages but can be efficiently compressed. ","version":"Next","tagName":"h2"},{"title":"react-intl without parser (40% smaller)","type":1,"pageTitle":"Advanced Usage","url":"/docs/guides/advanced-usage#react-intl-without-parser-40-smaller","content":" If you've made sure all your messages & defaultMessages are precompiled as above, you can resolve @formatjs/icu-messageformat-parser to @formatjs/icu-messageformat-parser/no-parser during bundling to get a much smaller bundler (~40% less). For example: ","version":"Next","tagName":"h2"},{"title":"webpack.config.js","type":1,"pageTitle":"Advanced Usage","url":"/docs/guides/advanced-usage#webpackconfigjs","content":" module.exports = { //... resolve: { alias: { '@formatjs/icu-messageformat-parser': '@formatjs/icu-messageformat-parser/no-parser', }, }, } ","version":"Next","tagName":"h3"},{"title":"rollup.config.js","type":1,"pageTitle":"Advanced Usage","url":"/docs/guides/advanced-usage#rollupconfigjs","content":" import alias from '@rollup/plugin-alias' module.exports = { //... plugins: [ alias({ entries: { '@formatjs/icu-messageformat-parser': '@formatjs/icu-messageformat-parser/no-parser', }, }), ], } In the future, we'll gear towards making this the default behavior. ","version":"Next","tagName":"h3"},{"title":"Imperative APIs","type":1,"pageTitle":"Advanced Usage","url":"/docs/guides/advanced-usage#imperative-apis","content":" Imperative APIs (e.g formatMessage...) are generally faster than Formatted component since it does not create extra ReactElement nodes. They should have the exact same capabilities as Formatted components. ","version":"Next","tagName":"h2"},{"title":"More examples","type":1,"pageTitle":"Advanced Usage","url":"/docs/guides/advanced-usage#more-examples","content":" Head over to https://github.com/formatjs/formatjs/tree/main/packages/react-intl/examples for more examples on how to use our libraries. ","version":"Next","tagName":"h2"},{"title":"Develop with formatjs","type":0,"sectionRef":"#","url":"/docs/guides/develop","content":"","keywords":"","version":"Next"},{"title":"Linter Installation","type":1,"pageTitle":"Develop with formatjs","url":"/docs/guides/develop#linter-installation","content":" npmyarn npm i -D eslint-plugin-formatjs eslint Then in your eslint config: { "plugins": ["formatjs"], "rules": { "formatjs/no-offset": "error" } } Head over to eslint-plugin-formatjs for more details on our rules. ","version":"Next","tagName":"h2"},{"title":"Error Codes","type":1,"pageTitle":"Develop with formatjs","url":"/docs/guides/develop#error-codes","content":" react-intl is designed to fail fast when there's a configuration issue but fall back to defaultLocale when there's a translation issues. Below are the list of errors that we emit out that can be caught during testing: ","version":"Next","tagName":"h2"},{"title":"FORMAT_ERROR","type":1,"pageTitle":"Develop with formatjs","url":"/docs/guides/develop#format_error","content":" Issue when we try to format a sentence but some of the placeholder values are malformed, e.g passing in a string for a Date or such. ","version":"Next","tagName":"h3"},{"title":"UNSUPPORTED_FORMATTER","type":1,"pageTitle":"Develop with formatjs","url":"/docs/guides/develop#unsupported_formatter","content":" We trigger this error when a custom format is being declared but there's no corresponding formatter with it. For example: intl.formatMessage({ defaultMessage: 'the price is {p, number, customCurrency}', }) and there's no formatter for customCurrency. ","version":"Next","tagName":"h3"},{"title":"INVALID_CONFIG","type":1,"pageTitle":"Develop with formatjs","url":"/docs/guides/develop#invalid_config","content":" When some config values are misconfigured such as missing locale. ","version":"Next","tagName":"h3"},{"title":"MISSING_DATA","type":1,"pageTitle":"Develop with formatjs","url":"/docs/guides/develop#missing_data","content":" When some native Intl APIs don't support certain locales, or missing locale-data when polyfills are setup. This typically happens when you're running on an older browsers/Node, or try to use newer APIs in browsers that have not supported them. ","version":"Next","tagName":"h3"},{"title":"MISSING_TRANSLATION","type":1,"pageTitle":"Develop with formatjs","url":"/docs/guides/develop#missing_translation","content":" This gets triggered whenever we try to look up a translated message in messages for a given id and it's not there and there is no fallback defaultMessage for the given id. verbosity This error will be triggered very often since it happens for every message that does not have a translation. Therefore if you do log it remotely there should be throttling in place. ","version":"Next","tagName":"h3"},{"title":"Message Distribution","type":0,"sectionRef":"#","url":"/docs/getting-started/message-distribution","content":"","keywords":"","version":"Next"},{"title":"Compiling Messages","type":1,"pageTitle":"Message Distribution","url":"/docs/getting-started/message-distribution#compiling-messages","content":" Let's take the example from Message Extraction, assuming we are working with the French version and the file is called lang/fr.json: { "hak27d": { "defaultMessage": "Panneau de configuration", "description": "title of control panel section" }, "haqsd": { "defaultMessage": "Supprimer l'utilisateur {name}", "description": "delete button" }, "19hjs": { "defaultMessage": "nouveau mot de passe", "description": "placeholder text" }, "explicit-id": { "defaultMessage": "Confirmez le mot de passe", "description": "placeholder text" } } We can use @formatjs/cli to compile this into a react-intl consumable JSON file: Add the following command to your package.json scripts: { "scripts": { "compile": "formatjs compile" } } and execute with npm: npmyarn npm run compile -- lang/fr.json --ast --out-file compiled-lang/fr.json Parsing messages into AST We recommending compiling your messages into AST as it allows us to skip parsing them during runtime. This makes your app more performant. ","version":"Next","tagName":"h2"},{"title":"Translation Management System (TMS) Integration","type":1,"pageTitle":"Message Distribution","url":"/docs/getting-started/message-distribution#translation-management-system-tms-integration","content":" If your TMS/vendor has a different JSON format you can specify a custom formatter with --format <formatFile> that converts that into Record<string,string> so @formatjs/cli can understand. For example: If your vendor accepts the format like { "[id]": { "string": "[message]", "comment": "[description]" } } you can run npmyarn npm run compile -- lang/fr.json --ast --out-file compiled-lang/fr.json --format formatter.js where formatter.js is: exports.compile = function (msgs) { const results = {} for (const [id, msg] of Object.entries(msgs)) { results[id] = msg.string } return results } In the future we will provide formatters that work with popular TMSes by default. ","version":"Next","tagName":"h2"},{"title":"Distribution","type":1,"pageTitle":"Message Distribution","url":"/docs/getting-started/message-distribution#distribution","content":" While every application has a separate distribution pipeline, the common theme is the ability to map a locale to its translation file. In this example we'll assume your pipeline can understand dynamic import: NodeReactVue3 import * as React from 'react' import * as ReactDOM from 'react-dom' import {IntlProvider} from 'react-intl' function loadLocaleData(locale: string) { switch (locale) { case 'fr': return import('compiled-lang/fr.json') default: return import('compiled-lang/en.json') } } function App(props) { return ( <IntlProvider locale={props.locale} defaultLocale="en" messages={props.messages} > <MainApp /> </IntlProvider> ) } async function bootstrapApplication(locale, mainDiv) { const messages = await loadLocaleData(locale) ReactDOM.render(<App locale={locale} messages={messages} />, mainDiv) } ","version":"Next","tagName":"h2"},{"title":"Bundling with formatjs","type":0,"sectionRef":"#","url":"/docs/guides/bundler-plugins","content":"","keywords":"","version":"Next"},{"title":"Using babel-plugin-formatjs","type":1,"pageTitle":"Bundling with formatjs","url":"/docs/guides/bundler-plugins#using-babel-plugin-formatjs","content":" npmyarn npm i -D babel-plugin-formatjs Let's take this simple example: import {FormattedMessage} from 'react-intl' <FormattedMessage description="A message" defaultMessage="My name is {name}" values={{ name: userName, }} /> During runtime this will throw an Error saying ID is required. In order to inject an ID in the transpiled JS, you can use our babel-plugin-formatjs similarly as below: babel.config.json { "plugins": [ [ "formatjs", { "idInterpolationPattern": "[sha512:contenthash:base64:6]", "ast": true } ] ] } This will produce the following JS const {FormattedMessage} = require('react-intl') React.createElement(FormattedMessage, { id: '179jda', defaultMessage: 'My name is {name}', values: { name: userName, }, }) description Our plugin also removes description because it's only for translator, not end-user. ","version":"Next","tagName":"h2"},{"title":"Using @formatjs/ts-transformer","type":1,"pageTitle":"Bundling with formatjs","url":"/docs/guides/bundler-plugins#using-formatjsts-transformer","content":" npmyarn npm i -D @formatjs/ts-transformer If you're using TypeScript, in order to enable custom AST transformer you should consider using ts-patch, ts-loader or similar. Let's take this simple example: import {FormattedMessage} from 'react-intl' <FormattedMessage description="A message" defaultMessage="My name is {name}" values={{ name: userName, }} /> ","version":"Next","tagName":"h2"},{"title":"ts-loader","type":1,"pageTitle":"Bundling with formatjs","url":"/docs/guides/bundler-plugins#ts-loader","content":" You can add this in your webpack config ts-loader. import {transform} from '@formatjs/ts-transformer' // webpack config module.exports = { rules: [ { test: /\\.tsx?$/, use: [ { loader: 'ts-loader', options: { getCustomTransformers() { return { before: [ transform({ overrideIdFn: '[sha512:contenthash:base64:6]', }), ], } }, }, }, ], exclude: /node_modules/, }, ], } This will produce the following JS const {FormattedMessage} = require('react-intl') React.createElement(FormattedMessage, { id: '179jda', defaultMessage: 'My name is {name}', values: { name: userName, }, }) description Our transformer also removes description because it's only for translator, not end-user. ","version":"Next","tagName":"h3"},{"title":"Runtime Requirements","type":0,"sectionRef":"#","url":"/docs/guides/runtime-requirements","content":"","keywords":"","version":"Next"},{"title":"Browser","type":1,"pageTitle":"Runtime Requirements","url":"/docs/guides/runtime-requirements#browser","content":" Browser Support We support IE11 & 2 most recent versions of Edge, Chrome, Firefox & Safari. If you need older browser support, take a look at polyfill-library that also uses formatjs but pre-bundle other polyfills that we use. React Intl relies on these Intl APIs: Intl.NumberFormat: Available on IE11+Intl.DateTimeFormat: Available on IE11+Intl.PluralRules: This can be polyfilled using this package.(Optional) Intl.RelativeTimeFormat: Required if you use formatRelativeTimeor FormattedRelativeTime. This can be polyfilled using this package.(Optional) Intl.DisplayNames: Required if you use formatDisplayNameor FormattedDisplayName. This can be polyfilled using this package. We officially support IE11 along with 2 most recent versions of Edge, Chrome & Firefox. ","version":"Next","tagName":"h2"},{"title":"Node.js","type":1,"pageTitle":"Runtime Requirements","url":"/docs/guides/runtime-requirements#nodejs","content":" ","version":"Next","tagName":"h2"},{"title":"full-icu","type":1,"pageTitle":"Runtime Requirements","url":"/docs/guides/runtime-requirements#full-icu","content":" Starting with Node.js 13.0.0 full-icu is supported by default. If using React Intl in an earlier version of Node.js, your node binary has to either: Get compiled with full-icu using these instructions OR Uses full-icu npm package If your node version is missing any of the Intl APIs above, you'd have to polyfill them accordingly. ","version":"Next","tagName":"h3"},{"title":"React Native","type":1,"pageTitle":"Runtime Requirements","url":"/docs/guides/runtime-requirements#react-native","content":" If you're using react-intl in React Native, make sure your runtime has built-in Intl support (similar to JSC International variant). See these issues for more details: https://github.com/formatjs/formatjs/issues/1356https://github.com/formatjs/formatjs/issues/992 ","version":"Next","tagName":"h2"},{"title":"React Native on iOS","type":1,"pageTitle":"Runtime Requirements","url":"/docs/guides/runtime-requirements#react-native-on-ios","content":" If you cannot use the Intl variant of JSC (e.g on iOS), follow the instructions in polyfills to polyfill the following APIs (in this order): Intl.getCanonicalLocalesIntl.LocaleIntl.PluralRulesIntl.NumberFormatIntl.DateTimeFormat ","version":"Next","tagName":"h3"},{"title":"Distributing i18n-friendly libraries","type":0,"sectionRef":"#","url":"/docs/guides/distribute-libraries","content":"","keywords":"","version":"Next"},{"title":"High level concept","type":1,"pageTitle":"Distributing i18n-friendly libraries","url":"/docs/guides/distribute-libraries#high-level-concept","content":" Translated strings are basically assets, just like CSS, static configuration or images. The high level structure typically contains several layers: Reusable Components/Libraries that have translated strings, which can be nested.Consuming higher-level applications that consumes those components/libraries. Each feature/library would be in charge of: Declaring its messages.Integrating with the translation pipeline.Declaring its translated & aggregated strings using either a manifest like package.json or a convention (always output to a specific location) or both. ","version":"Next","tagName":"h2"},{"title":"Declaring in package.json","type":1,"pageTitle":"Distributing i18n-friendly libraries","url":"/docs/guides/distribute-libraries#declaring-in-packagejson","content":" This is similar to using style attribute to declare CSS. You can declare something like { "name": "my-library", "version": "1.0.0", "lang": "my-strings", "supportedLocales": ["en", "en-GB", "ja"] } where my-strings is the folder containing your translated strings in your supportedLocales: my-strings |- en.json |- en-GB.json |- ja.json Consuming application can walk through node_modules looking for package.json files with these fields and aggregate the strings together into a single bundle (or multiple bundles) and serve those JSON however it chooses to. This provides flexibility to output translations to any location you want as long as it's declared in package.json. However, this also incurs additional processing cost at the application level and also encourages inconsistency in output location. ","version":"Next","tagName":"h2"},{"title":"Declaring with a convention","type":1,"pageTitle":"Distributing i18n-friendly libraries","url":"/docs/guides/distribute-libraries#declaring-with-a-convention","content":" This is similar to Declaring in package.json, except translation is always output to lang/{locale}.json. Upstream application can do formatjs compile "node_modules/**/lang/en.json" --ast --out-file lang/en.json to aggregate all its libraries' pre-translated strings. my-lib |- src |- lang |- en.json |- en-GB.json |- ja.json |- node_modules |- library1 |- lang |- en.json |- en-GB.json |- ja.json |- library2 |- lang |- en.json |- en-GB.json |- ja.json This provides consistency and minimize processing cost of different manifest files but also is less flexible. info We've seen convention approach working better in large engineering org due to enforcement of convention & structure while manifest approach working in a more open environment. ","version":"Next","tagName":"h2"},{"title":"Passing down intl object","type":1,"pageTitle":"Distributing i18n-friendly libraries","url":"/docs/guides/distribute-libraries#passing-down-intl-object","content":" The core of a i18n application is the intl object, which contains precompiled messages, locale settings, format settings and cache. Therefore, this should only be initialized at the top level in the application. Component libraries can declare intl: IntlShape as a prop and subsequently pass it down directly like: ReactVue3 import {IntlShape} from 'react-intl' import {MyButton, MyForm} from 'my-components' interface Props { intl: IntlShape } function MyFeature(props: Props) { return ( <div> <MyButton intl={props.intl} /> <MyForm intl={props.intl} /> </div> ) } or passing down via context using RawIntlProvider: import {IntlShape, RawIntlProvider} from 'react-intl' import {MyButton, MyForm} from 'my-components' interface Props { intl: IntlShape } function MyFeature(props: Props) { return ( <RawIntlProvider value={props.intl}> <MyButton /> <MyForm /> </RawIntlProvider> ) } ","version":"Next","tagName":"h2"},{"title":"ICU MessageFormat Parser","type":0,"sectionRef":"#","url":"/docs/icu-messageformat-parser","content":"","keywords":"","version":"Next"},{"title":"Overview","type":1,"pageTitle":"ICU MessageFormat Parser","url":"/docs/icu-messageformat-parser#overview","content":" This package implements a parser in JavaScript that parses the industry standard ICU Message strings — used for internationalization — into an AST. The produced AST can then be used by a compiler, like intl-messageformat, to produce localized formatted strings for display to users. ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"ICU MessageFormat Parser","url":"/docs/icu-messageformat-parser#usage","content":" import {parse} from '@formatjs/icu-messageformat-parser' const ast = parse(`this is {count, plural, one{# dog} other{# dogs} }`) ","version":"Next","tagName":"h2"},{"title":"Example","type":1,"pageTitle":"ICU MessageFormat Parser","url":"/docs/icu-messageformat-parser#example","content":" Live Editor <pre> {JSON.stringify( IcuMessageFormatParser.parse( `On {takenDate, date, short} <bold>{name}</bold> took {numPhotos, plural, =0 {no photos.} =1 {one photo.} other {# photos.} }` ), undefined, 2 )} </pre> Result ","version":"Next","tagName":"h3"},{"title":"Supported DateTime Skeleton","type":1,"pageTitle":"ICU MessageFormat Parser","url":"/docs/icu-messageformat-parser#supported-datetime-skeleton","content":" ICU provides a wide array of pattern to customize date time format. However, not all of them are available via ECMA402's Intl API. Therefore, our parser only support the following patterns Symbol\tMeaning\tNotesG\tEra designator y\tyear M\tmonth in year L\tstand-alone month in year d\tday in month E\tday of week e\tlocal day of week\te..eee is not supported c\tstand-alone local day of week\tc..ccc is not supported a\tAM/PM marker h\tHour [1-12] H\tHour [0-23] K\tHour [0-11] k\tHour [1-24] m\tMinute s\tSecond z\tTime Zone\t ","version":"Next","tagName":"h2"},{"title":"Benchmarks","type":1,"pageTitle":"ICU MessageFormat Parser","url":"/docs/icu-messageformat-parser#benchmarks","content":" complex_msg AST length 10861 normal_msg AST length 1665 simple_msg AST length 364 string_msg AST length 131 complex_msg x 29,940 ops/sec ±1.23% (89 runs sampled) normal_msg x 253,612 ops/sec ±1.01% (92 runs sampled) simple_msg x 1,805,642 ops/sec ±0.70% (94 runs sampled) string_msg x 2,694,133 ops/sec ±1.05% (95 runs sampled) ","version":"Next","tagName":"h2"},{"title":"Message Extraction","type":0,"sectionRef":"#","url":"/docs/getting-started/message-extraction","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Message Extraction","url":"/docs/getting-started/message-extraction#installation","content":" npmyarn npm i -D @formatjs/cli ","version":"Next","tagName":"h2"},{"title":"Extraction","type":1,"pageTitle":"Message Extraction","url":"/docs/getting-started/message-extraction#extraction","content":" Add the following command to your package.json scripts: { "scripts": { "extract": "formatjs extract" } } and execute with npm: npmyarn npm run extract -- 'src/**/*.ts*' --ignore='**/*.d.ts' --out-file lang/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' ID Interpolation Pattern Make sure this pattern matches idInterpolationPattern when you use babel-plugin-formatjs or @formatjs/ts-transformer in Bundling with formatjs or you'll get a MISSING_TRANSLATION error. Given a file that has the following messages: ReactVue3 import * as React from 'react' import {FormattedMessage, useIntl, injectIntl} from 'react-intl' class PasswordChangeWithIntl extends React.Component { render() { const {intl} = this.props return ( <li> <input placeholder={intl.formatMessage({ defaultMessage: 'New Password', description: 'placeholder text', })} /> <input placeholder={intl.formatMessage({ id: 'explicit-id', defaultMessage: 'Confirm Password', description: 'placeholder text', })} /> </li> ) } } const PasswordChange = injectIntl(PasswordChangeWithIntl) export function List(props) { const intl = useIntl() return ( <section> <header> <FormattedMessage defaultMessage="Control Panel" description="title of control panel section" /> </header> <ul> <li> <button> <FormattedMessage defaultMessage="Delete user {name}" description="Delete button" values={{ name: props.name, }} /> </button> </li> <PasswordChange /> </ul> </section> ) } running the above command will create a file called lang/en.json: { "hak27d": { "defaultMessage": "Control Panel", "description": "title of control panel section" }, "haqsd": { "defaultMessage": "Delete user {name}", "description": "delete button" }, "19hjs": { "defaultMessage": "New Password", "description": "placeholder text" }, "explicit-id": { "defaultMessage": "Confirm Password", "description": "placeholder text" } } Message ID During extraction, we'll preserve explicit declared IDs and insert a hash as an ID for messages without. We recommend against explicit IDs since it can cause collision. ","version":"Next","tagName":"h2"},{"title":"Automatic ID Generation","type":1,"pageTitle":"Message Extraction","url":"/docs/getting-started/message-extraction#automatic-id-generation","content":" Since manual IDs are discouraged, we've provided a babel plugin and a TypeScript AST transformer that will automatically insert message IDs in your transpiled code. For more details please visit Bundling with formatjs. ","version":"Next","tagName":"h2"},{"title":"Translation Management System (TMS) Integration","type":1,"pageTitle":"Message Extraction","url":"/docs/getting-started/message-extraction#translation-management-system-tms-integration","content":" The default format generated from @formatjs/cli might not work with the specific TMS/vendor you're working with. You can specify a custom formatter with --format <formatFile> that allows you to convert that format into something tailored to your TMS. For example: If your vendor accepts the format like { "[id]": { "string": "[message]", "comment": "[description]" } } you can run npmyarn npm run extract -- "src/**/*.{ts,tsx,vue}" --out-file lang/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format formatter.js where formatter.js is: exports.format = function (msgs) { const results = {} for (const [id, msg] of Object.entries(msgs)) { results[id] = { string: msg.defaultMessage, comment: msg.description, } } return results } We also provide several builtin formatters to integrate with 3rd party TMSes so feel free to create PRs to add more. TMS\t--formatBabelEdit\tsimple Crowdin Chrome JSON\tcrowdin Lingohub\tsimple Localize's Simple JSON\tsimple Localizely\tsimple locize\tsimple Lokalise Structured JSON\tlokalise Phrase Strings\tsimple POEditor Key-Value JSON\tsimple SimpleLocalize JSON\tsimple Smartling ICU JSON\tsmartling Transifex's Structured JSON\ttransifex ","version":"Next","tagName":"h2"},{"title":"Testing with formatjs","type":0,"sectionRef":"#","url":"/docs/guides/testing","content":"","keywords":"","version":"Next"},{"title":"Intl APIs requirements","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#intl-apis-requirements","content":" React Intl uses the built-in Intl APIs in JavaScript. Make sure your environment satisfy the requirements listed in Intl APIs requirements ","version":"Next","tagName":"h2"},{"title":"Mocha","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#mocha","content":" If you're using Mocha as your test runner and testing on older JavaScript runtimes, you can load the Intl Polyfill via the CLI or by adding a <script> in the browser. Command Line Run mocha and auto-polyfill the runtime if needed: $ mocha --recursive test/ Browser You can either load the polyfill in the browser from node_modules or use the polyfill-fastly.io service from the Financial Times: <script src="https://polyfill-fastly.io/v2/polyfill.min.js?features=Intl,Intl.~locale.en-US"></script> ","version":"Next","tagName":"h3"},{"title":"Shallow Rendering","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#shallow-rendering","content":" React's react-addons-test-utils package contains a shallow rendering feature which you might use to test your app's React components. If a component you're trying to test using ReactShallowRenderer uses React Intl — specifically injectIntl() — you'll need to do extra setup work because React Intl components expect to be nested inside an <IntlProvider>. ","version":"Next","tagName":"h2"},{"title":"Testing Example Components That Use React Intl","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#testing-example-components-that-use-react-intl","content":" The following examples will assume mocha, expect, and expect-jsx test framework. ShortDate (Basic) import React from 'react' import {FormattedDate} from 'react-intl' const ShortDate = props => ( <FormattedDate value={props.date} year="numeric" month="short" day="2-digit" /> ) export default ShortDate Testing the <ShortDate> example component is no different than testing any other basic component in your app using React's shallow rendering: import expect from 'expect' import expectJSX from 'expect-jsx' import React from 'react' import {createRenderer} from 'react-addons-test-utils' import {FormattedDate} from 'react-intl' import ShortDate from '../short-date' expect.extend(expectJSX) describe('<ShortDate>', function () { it('renders', function () { const renderer = createRenderer() const date = new Date() renderer.render(<ShortDate date={date} />) expect(renderer.getRenderOutput()).toEqualJSX( <FormattedDate value={date} year="numeric" month="short" day="2-digit" /> ) }) }) ","version":"Next","tagName":"h3"},{"title":"DOM Rendering","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#dom-rendering","content":" If you use the DOM in your tests, you need to supply the IntlProvider context to your components using composition: let element = ReactTestUtils.renderIntoDocument( <IntlProvider> <MyComponent /> </IntlProvider> ) However this means that the element reference is now pointing to the IntlProvider instead of your component. To retrieve a reference to your wrapped component, you can use "refs" with these changes to the code: In your component, remember to add {forwardRef: true} when calling injectIntl(): class MyComponent extends React.Component { ... myClassFn() { ... } } export default injectIntl(MyComponent, {forwardRef: true}); In your test, add a "ref" to extract the reference to your tested component: const element = React.createRef() ReactTestUtils.renderIntoDocument( <IntlProvider> <MyComponent ref={element} /> </IntlProvider> ) You can now access the wrapped component instance from element like this: element.current.myClassFn() ","version":"Next","tagName":"h2"},{"title":"Helper function","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#helper-function","content":" Since you will have to do this in all your unit tests, you should probably wrap that setup in a render function like this: function renderWithIntl(element) { let instance ReactTestUtils.renderIntoDocument( <IntlProvider> {React.cloneElement(element, { ref: instance, })} </IntlProvider> ) return instance } You can now use this in your tests like this: const element = React.createRef(); renderWithIntl(<MyElement ref={element}>); element.current.myClassFn(); ","version":"Next","tagName":"h3"},{"title":"Enzyme","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#enzyme","content":" Testing with Enzyme works in a similar fashion as written above. Your mount()ed and shallow()ed components will need access to the intl context. Below is a helper function which you can import and use to mount your components which make use of any of React-Intl's library (either <Formatted* /> components or format*() methods through injectIntl). ","version":"Next","tagName":"h2"},{"title":"Helper function","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#helper-function-1","content":" /** * Components using the react-intl module require access to the intl context. * This is not available when mounting single components in Enzyme. * These helper functions aim to address that and wrap a valid, * English-locale intl context around them. */ import React from 'react' import {IntlProvider} from 'react-intl' import {mount, shallow} from 'enzyme' // You can pass your messages to the IntlProvider. Optional: remove if unneeded. const messages = require('../locales/en') // en.json const defaultLocale = 'en' const locale = defaultLocale export function mountWithIntl(node: React.ReactElement) { return mount(node, { wrappingComponent: IntlProvider, wrappingComponentProps: { locale, defaultLocale, messages, }, }) } export function shallowWithIntl(node: React.ReactElement) { return shallow(node, { wrappingComponent: IntlProvider, wrappingComponentProps: { locale, defaultLocale, messages, }, }) } ","version":"Next","tagName":"h3"},{"title":"Usage","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#usage","content":" Create a file with the above helper in e.g. helpers/intl-enzyme-test-helper.js and import the methods you need in your tests. // intl-enzyme-test-helper.js import {mountWithIntl} from 'helpers/intl-enzyme-test-helper.js' const wrapper = mountWithIntl(<CustomComponent />) expect(wrapper.state('foo')).to.equal('bar') // OK expect(wrapper.text()).to.equal('Hello World!') // OK Based on this gist. ","version":"Next","tagName":"h3"},{"title":"Jest","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#jest","content":" Testing with Jest can be divided into two approaches: snapshot's testing and DOM testing. Snapshot's testing is a relatively new feature and works out of the box. If you'd like DOM testing you need to use Enzyme or React's TestUtils. ","version":"Next","tagName":"h2"},{"title":"Snapshot Testing","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#snapshot-testing","content":" Snapshot testing is a new feature of Jest that automatically generates text snapshots of your components and saves them on the disk so if the UI output changes, you get notified without manually writing any assertions on the component output. Use either helper function or mock as described below. Helper function import React from 'react' import renderer from 'react-test-renderer' import {IntlProvider} from 'react-intl' const createComponentWithIntl = (children, props = {locale: 'en'}) => { return renderer.create(<IntlProvider {...props}>{children}</IntlProvider>) } export default createComponentWithIntl Usage import React from 'react' import createComponentWithIntl from '../../utils/createComponentWithIntl' import AppMain from '../AppMain' test('app main should be rendered', () => { const component = createComponentWithIntl(<AppMain />) let tree = component.toJSON() expect(tree).toMatchSnapshot() tree.props.onClick() tree = component.toJSON() expect(tree).toMatchSnapshot() }) You can find runnable example here and more info about Jest here. Usage with Jest & enzyme Jest will automatically mock react-intl, so no any extra implementation is needed, tests should work as is: import React from 'react' import {shallow} from 'enzyme' import AppMain from '../AppMain' test('app main should be rendered', () => { const wrapper = shallow(<AppMain />) expect(wrapper).toMatchSnapshot() }) ","version":"Next","tagName":"h3"},{"title":"DOM Testing","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#dom-testing","content":" If you want use Jest with DOM Testing read more info above in Enzyme section or in official Jest documentation. ","version":"Next","tagName":"h3"},{"title":"Storybook","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#storybook","content":" ","version":"Next","tagName":"h2"},{"title":"Intl","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#intl","content":" If you want to use react-intl inside of Storybook you can use storybook-addon-intl which provides an easy to use wrapper for react-intl including a locale switcher so you can test your component in all provided languages. ","version":"Next","tagName":"h3"},{"title":"react-testing-library","type":1,"pageTitle":"Testing with formatjs","url":"/docs/guides/testing#react-testing-library","content":" In order to use react-intl and react-testing-library together, you should provide some helper function to the testing flow. You can check the docs. To create a generic solution, We can create a custom render function using the wrapper option as explained in thesetup page. Our custom render function can look like this: // test-utils.js import React from 'react' import {render as rtlRender} from '@testing-library/react' import {IntlProvider} from 'react-intl' function render(ui, {locale = 'pt', ...renderOptions} = {}) { function Wrapper({children}) { return <IntlProvider locale={locale}>{children}</IntlProvider> } return rtlRender(ui, {wrapper: Wrapper, ...renderOptions}) } // re-export everything export * from '@testing-library/react' // override render method export {render} import React from 'react' import '@testing-library/jest-dom/jest-globals' // We're importing from our own created test-utils and not RTL's import {render, screen} from '../test-utils.js' import {FormattedDate} from 'react-intl' const FormatDateView = () => { return ( <div data-testid="date-display"> <FormattedDate value="2019-03-11" timeZone="utc" day="2-digit" month="2-digit" year="numeric" /> </div> ) } test('it should render FormattedDate and have a formated pt date', () => { render(<FormatDateView />) expect(screen.getByTestId('date-display')).toHaveTextContent('11/03/2019') }) ","version":"Next","tagName":"h2"},{"title":"polyfill-fastly.io Integration","type":0,"sectionRef":"#","url":"/docs/polyfills","content":"One of our goals is to provide developers with access to newest ECMA-402 Intl APIs. Therefore, FormatJS suite also provide multiple high quality polyfills that are fully tested using the Official ECMAScript Conformance Test Suite. Our current list of polyfills includes: Intl.PluralRulesIntl.RelativeTimeFormatIntl.ListFormatIntl.DisplayNamesIntl.NumberFormat (ES2020)Intl.LocaleIntl.LocaleMatcherIntl.getCanonicalLocalesIntl.DateTimeFormat (ES2020)Intl.SegmenterIntl.DurationFormatIntl.supportedValuesOf polyfill-fastly.io Integration For basic use cases, we recommend using polyfill-fastly.io or polyfill-library to generate polyfill bundle since it automatically resolves the dependencies above for you.","keywords":"","version":"Next"},{"title":"Intl.DateTimeFormat (ESNext)","type":0,"sectionRef":"#","url":"/docs/polyfills/intl-datetimeformat","content":"","keywords":"","version":"Next"},{"title":"Features","type":1,"pageTitle":"Intl.DateTimeFormat (ESNext)","url":"/docs/polyfills/intl-datetimeformat#features","content":" dateStyle/timeStyleformatRange ","version":"Next","tagName":"h2"},{"title":"Installation","type":1,"pageTitle":"Intl.DateTimeFormat (ESNext)","url":"/docs/polyfills/intl-datetimeformat#installation","content":" npmyarn npm i @formatjs/intl-datetimeformat ","version":"Next","tagName":"h2"},{"title":"Requirements","type":1,"pageTitle":"Intl.DateTimeFormat (ESNext)","url":"/docs/polyfills/intl-datetimeformat#requirements","content":" This package requires the following capabilities: Intl.getCanonicalLocales or polyfillIntl.Locale or polyfill.Intl.NumberFormat or polyfill. ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Intl.DateTimeFormat (ESNext)","url":"/docs/polyfills/intl-datetimeformat#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Via polyfill-fastly.io","type":1,"pageTitle":"Intl.DateTimeFormat (ESNext)","url":"/docs/polyfills/intl-datetimeformat#via-polyfill-fastlyio","content":" You can use polyfill-fastly.io URL Builder to create a polyfill script tag for Intl.DateTimeFormat. By default the created URL does not come with any locale data. In order to add locale data, append Intl.DateTimeFormat.~locale.<locale>, as well as locale data for any required polyfills, to your list of features. For example: <!-- Polyfill Intl.DateTimeFormat, its dependencies & `en` locale data --> <script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script> ","version":"Next","tagName":"h3"},{"title":"Simple","type":1,"pageTitle":"Intl.DateTimeFormat (ESNext)","url":"/docs/polyfills/intl-datetimeformat#simple","content":" import '@formatjs/intl-datetimeformat/polyfill' import '@formatjs/intl-datetimeformat/locale-data/en' // locale-data for en import '@formatjs/intl-datetimeformat/add-all-tz' // Add ALL tz data ","version":"Next","tagName":"h3"},{"title":"Dynamic import + capability detection","type":1,"pageTitle":"Intl.DateTimeFormat (ESNext)","url":"/docs/polyfills/intl-datetimeformat#dynamic-import--capability-detection","content":" import {shouldPolyfill} from '@formatjs/intl-datetimeformat/should-polyfill' async function polyfill(locale: string) { const unsupportedLocale = shouldPolyfill(locale) // This locale is supported if (!unsupportedLocale) { return } // Load the polyfill 1st BEFORE loading data await import('@formatjs/intl-datetimeformat/polyfill-force') // Parallelize CLDR data loading const dataPolyfills = [ import('@formatjs/intl-datetimeformat/add-all-tz'), import(`@formatjs/intl-datetimeformat/locale-data/${unsupportedLocale}`), ] await Promise.all(dataPolyfills) } ","version":"Next","tagName":"h3"},{"title":"Adding IANA Timezone Database","type":1,"pageTitle":"Intl.DateTimeFormat (ESNext)","url":"/docs/polyfills/intl-datetimeformat#adding-iana-timezone-database","content":" We provide 2 pre-processed IANA Timezone: Full: contains ALL Timezone from IANA database import '@formatjs/intl-datetimeformat/polyfill' import '@formatjs/intl-datetimeformat/add-all-tz' Golden: contains popular set of timezones from IANA database import '@formatjs/intl-datetimeformat/polyfill' import '@formatjs/intl-datetimeformat/add-golden-tz' ","version":"Next","tagName":"h3"},{"title":"Default Timezone","type":1,"pageTitle":"Intl.DateTimeFormat (ESNext)","url":"/docs/polyfills/intl-datetimeformat#default-timezone","content":" Since JS Engines do not expose default timezone, there's currently no way for us to detect local timezone that a browser is in. Therefore, the default timezone in this polyfill is UTC. You can change this by either calling __setDefaultTimeZone or always explicitly pass in timeZone option for accurate date time calculation. Since __setDefaultTimeZone is not in the spec, you should make sure to check for its existence before calling it & after tz data has been loaded, e.g: import '@formatjs/intl-datetimeformat/polyfill' import '@formatjs/intl-datetimeformat/add-all-tz.js' if ('__setDefaultTimeZone' in Intl.DateTimeFormat) { Intl.DateTimeFormat.__setDefaultTimeZone('America/Los_Angeles') } ","version":"Next","tagName":"h3"},{"title":"Tests","type":1,"pageTitle":"Intl.DateTimeFormat (ESNext)","url":"/docs/polyfills/intl-datetimeformat#tests","content":" This library is fully test262-compliant. ","version":"Next","tagName":"h2"},{"title":"Intl.DurationFormat","type":0,"sectionRef":"#","url":"/docs/polyfills/intl-durationformat","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Intl.DurationFormat","url":"/docs/polyfills/intl-durationformat#installation","content":" npmyarn npm i @formatjs/intl-durationformat ","version":"Next","tagName":"h2"},{"title":"Requirements","type":1,"pageTitle":"Intl.DurationFormat","url":"/docs/polyfills/intl-durationformat#requirements","content":" Intl.ListFormat or polyfillIntl.NumberFormat or polyfill. ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Intl.DurationFormat","url":"/docs/polyfills/intl-durationformat#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Simple","type":1,"pageTitle":"Intl.DurationFormat","url":"/docs/polyfills/intl-durationformat#simple","content":" import '@formatjs/intl-durationformat/polyfill' ","version":"Next","tagName":"h3"},{"title":"Dynamic import + capability detection","type":1,"pageTitle":"Intl.DurationFormat","url":"/docs/polyfills/intl-durationformat#dynamic-import--capability-detection","content":" import {shouldPolyfill} from '@formatjs/intl-durationformat/should-polyfill' async function polyfill(locale: string) { const unsupportedLocale = shouldPolyfill(locale) // This locale is supported if (!unsupportedLocale) { return } // Load the polyfill 1st BEFORE loading data await import('@formatjs/intl-durationformat/polyfill-force') } ","version":"Next","tagName":"h3"},{"title":"Intl MessageFormat","type":0,"sectionRef":"#","url":"/docs/intl-messageformat","content":"","keywords":"","version":"Next"},{"title":"Overview","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#overview","content":" ","version":"Next","tagName":"h2"},{"title":"Goals","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#goals","content":" This package aims to provide a way for you to manage and format your JavaScript app's string messages into localized strings for people using your app. You can use this package in the browser and on the server via Node.js. This implementation is based on the Strawman proposal, but there are a few places this implementation diverges. Future Changes This IntlMessageFormat API may change to stay in sync with ECMA-402, but this package will follow semver. ","version":"Next","tagName":"h3"},{"title":"How It Works","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#how-it-works","content":" Messages are provided into the constructor as a String message, or a pre-parsed AST object. const msg = new IntlMessageFormat(message, locales, [formats], [opts]) The string message is parsed, then stored internally in a compiled form that is optimized for the format() method to produce the formatted string for displaying to the user. const output = msg.format(values) ","version":"Next","tagName":"h3"},{"title":"Common Usage Example","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#common-usage-example","content":" A very common example is formatting messages that have numbers with plural labels. With this package you can make sure that the string is properly formatted for a person's locale, e.g.: Live Editor new IntlMessageFormat( `{numPhotos, plural, =0 {You have no photos.} =1 {You have one photo.} other {You have # photos.} }`, 'en-US' ).format({numPhotos: 1000}) Result Live Editor new IntlMessageFormat( `{numPhotos, plural, =0 {Usted no tiene fotos.} =1 {Usted tiene una foto.} other {Usted tiene # fotos.} }`, 'es-ES' ).format({numPhotos: 1000}) Result ","version":"Next","tagName":"h3"},{"title":"Message Syntax","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#message-syntax","content":" The message syntax that this package uses is not proprietary, in fact it's a common standard message syntax that works across programming languages and one that professional translators are familiar with. This package uses the ICU Message syntax and works for all CLDR languages which have pluralization rules defined. ","version":"Next","tagName":"h3"},{"title":"Features","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#features","content":" Uses industry standards: ICU Message syntax and CLDR locale data. Supports plural, select, and selectordinal message arguments. Formats numbers and dates/times in messages using Intl.NumberFormat and Intl.DateTimeFormat, respectively. Optimized for repeated calls to an IntlMessageFormat instance's format() method. Supports defining custom format styles/options. Supports escape sequences for message syntax chars, e.g.: "'{foo}'" will output: "{foo}" in the formatted output instead of interpreting it as a foo argument. ","version":"Next","tagName":"h3"},{"title":"Usage","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Modern Intl Dependency","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#modern-intl-dependency","content":" This package assumes that the Intl global object exists in the runtime. Intl is present in all modern browsers (IE11+) and Node (with full ICU). The Intl methods we rely on are: Intl.NumberFormat for number formatting (can be polyfilled using @formatjs/intl-numberformat)Intl.DateTimeFormat for date time formatting (can be polyfilled using @formatjs/intl-datetimeformat)Intl.PluralRules for plural/ordinal formatting (can be polyfilled using @formatjs/intl-pluralrules) ","version":"Next","tagName":"h3"},{"title":"Loading Intl MessageFormat in a browser","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#loading-intl-messageformat-in-a-browser","content":" <script src="intl-messageformat/intl-messageformat.min.js"></script> ","version":"Next","tagName":"h3"},{"title":"Loading Intl MessageFormat in Node.js","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#loading-intl-messageformat-in-nodejs","content":" Either do: import IntlMessageFormat from 'intl-messageformat' const IntlMessageFormat = require('intl-messageformat').default NOTE: Your Node has to include full ICU ","version":"Next","tagName":"h3"},{"title":"Public API","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#public-api","content":" ","version":"Next","tagName":"h2"},{"title":"IntlMessageFormat Constructor","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#intlmessageformat-constructor","content":" To create a message to format, use the IntlMessageFormat constructor. The constructor takes three parameters: message: string | AST - String message (or pre-parsed AST) that serves as formatting pattern. locales: string | string[] - A string with a BCP 47 language tag, or an array of such strings. If you do not provide a locale, the default locale will be used. When an array of locales is provided, each item and its ancestor locales are checked and the first one with registered locale data is returned. See: Locale Resolution for more details. formats?: object - Optional object with user defined options for format styles. opts?: { formatters?: Formatters, ignoreTag?: boolean } - Optional options. formatters: Map containing memoized formatters for performance.ignoreTag: Whether to treat HTML/XML tags as string literal instead of parsing them as tag token. When this is false we only allow simple tags without any attributes const msg = new IntlMessageFormat('My name is {name}.', 'en-US') ","version":"Next","tagName":"h3"},{"title":"Locale Resolution","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#locale-resolution","content":" IntlMessageFormat uses Intl.NumberFormat.supportedLocalesOf() to determine which locale data to use based on the locales value passed to the constructor. The result of this resolution process can be determined by call the resolvedOptions() prototype method. ","version":"Next","tagName":"h3"},{"title":"resolvedOptions() Method","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#resolvedoptions-method","content":" This method returns an object with the options values that were resolved during instance creation. It currently only contains a locale property; here's an example: Live Editor new IntlMessageFormat('', 'en-us').resolvedOptions().locale Result Notice how the specified locale was the all lower-case value: "en-us", but it was resolved and normalized to: "en-US". ","version":"Next","tagName":"h3"},{"title":"format(values) Method","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#formatvalues-method","content":" Once the message is created, formatting the message is done by calling the format() method on the instance and passing a collection of values: Live Editor new IntlMessageFormat('My name is {name}.', 'en-US').format({name: 'Eric'}) Result placeholders A value must be supplied for every argument in the message pattern the instance was constructed with. Rich Text support Live Editor new IntlMessageFormat('hello <b>world</b>', 'en').format({ b: chunks => <strong>{chunks}</strong>, }) Result We support embedded XML tag in the message, e.g this is a <b>strong</b> tag. This is not meant to be a full-fledged method to embed HTML, but rather to tag specific text chunk so translation can be more contextual. Therefore, the following restrictions apply: Any attributes on the HTML tag are also ignored.Self-closing tags are treated as string literal and not supported, please use regular ICU placeholder like {placeholder}.All tags specified must have corresponding values and will throw error if it's missing, e.g: Live Editor function () { try { return new IntlMessageFormat('a <foo>strong</foo>').format() } catch (e) { return String(e) } } Result XML/HTML tags are escaped using apostrophe just like other ICU constructs. In order to escape you can do things like: Live Editor new IntlMessageFormat("I '<'3 cats").format() Result Live Editor new IntlMessageFormat("raw '<b>HTML</b>'").format() Result Live Editor new IntlMessageFormat("raw '<b>HTML</b>' with '<a>'{placeholder}'</a>'").format( {placeholder: 'some word'} ) Result Embedded valid HTML tag is a bit of a grey area right now since we're not supporting the full HTML/XHTML/XML spec. ","version":"Next","tagName":"h3"},{"title":"getAst Method","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#getast-method","content":" Return the underlying AST for the compiled message. ","version":"Next","tagName":"h3"},{"title":"Date/Time/Number Skeleton","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#datetimenumber-skeleton","content":" We support ICU Number skeleton and a subset of Date/Time Skeleton for further customization of formats. Number Skeleton Example: Live Editor new IntlMessageFormat( 'The price is: {price, number, ::currency/EUR}', 'en-GB' ).format({price: 100}) Result A full set of options and syntax can be found here Date/Time Skeleton ICU provides a wide array of pattern to customize date time format. However, not all of them are available via ECMA402's Intl API. Therefore, our parser only support the following patterns Symbol\tMeaning\tNotesG\tEra designator y\tyear M\tmonth in year L\tstand-alone month in year d\tday in month E\tday of week e\tlocal day of week\te..eee is not supported c\tstand-alone local day of week\tc..ccc is not supported a\tAM/PM marker h\tHour [1-12] H\tHour [0-23] K\tHour [0-11] k\tHour [1-24] m\tMinute s\tSecond z\tTime Zone\t Example: Live Editor new IntlMessageFormat('Today is: {now, date, ::yyyyMMdd}', 'en-GB').format({ now: new Date(), }) Result ","version":"Next","tagName":"h3"},{"title":"Advanced Usage","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#advanced-usage","content":" ","version":"Next","tagName":"h2"},{"title":"Passing in AST","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#passing-in-ast","content":" You can pass in pre-parsed AST to IntlMessageFormat like this: new IntlMessageFormat('hello').format() // prints out hello // is equivalent to import IntlMessageFormat from 'intl-messageformat' import {parse} from '@formatjs/icu-messageformat-parser' new IntlMessageFormat(parse('hello')).format() // prints out hello This helps performance for cases like SSR or preload/precompilation-supported platforms since AST can be cached. If your messages are all in ASTs, you can alias @formatjs/icu-messageformat-parser to {default: undefined} to save some bytes during bundling. ","version":"Next","tagName":"h3"},{"title":"Formatters","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#formatters","content":" For complex messages, initializing Intl.* constructors can be expensive. Therefore, we allow user to pass in formatters to provide memoized instances of these Intl objects. This opts combines with passing in AST and fast-memoize can speed things up by 30x per the benchmark down below. For example: import IntlMessageFormat from 'intl-messageformat' import {memoize} from '@formatjs/fast-memoize' const formatters = { getNumberFormat: memoize( (locale, opts) => new Intl.NumberFormat(locale, opts) ), getDateTimeFormat: memoize( (locale, opts) => new Intl.DateTimeFormat(locale, opts) ), getPluralRules: memoize((locale, opts) => new Intl.PluralRules(locale, opts)), } new IntlMessageFormat('hello {number, number}', 'en', undefined, { formatters, }).format({number: 3}) // prints out `hello, 3` ","version":"Next","tagName":"h3"},{"title":"Benchmark","type":1,"pageTitle":"Intl MessageFormat","url":"/docs/intl-messageformat#benchmark","content":" format_cached_complex_msg x 153,868 ops/sec ±1.13% (85 runs sampled) format_cached_string_msg x 21,661,621 ops/sec ±4.06% (84 runs sampled) new_complex_msg_preparsed x 719,056 ops/sec ±2.83% (78 runs sampled) new_complex_msg x 12,844 ops/sec ±1.97% (85 runs sampled) new_string_msg x 409,770 ops/sec ±2.57% (79 runs sampled) complex msg format x 12,065 ops/sec ±1.66% (81 runs sampled) complex msg w/ formatters format x 11,649 ops/sec ±2.05% (78 runs sampled) complex preparsed msg w/ formatters format x 597,153 ops/sec ±1.46% (90 runs sampled) complex preparsed msg w/ new formatters format x 684,263 ops/sec ±1.37% (89 runs sampled) ","version":"Next","tagName":"h2"},{"title":"Intl.DisplayNames","type":0,"sectionRef":"#","url":"/docs/polyfills/intl-displaynames","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Intl.DisplayNames","url":"/docs/polyfills/intl-displaynames#installation","content":" npmyarn npm i @formatjs/intl-displaynames ","version":"Next","tagName":"h2"},{"title":"Requirements","type":1,"pageTitle":"Intl.DisplayNames","url":"/docs/polyfills/intl-displaynames#requirements","content":" Intl.getCanonicalLocales or polyfillIntl.Locale or polyfill. ","version":"Next","tagName":"h2"},{"title":"Features","type":1,"pageTitle":"Intl.DisplayNames","url":"/docs/polyfills/intl-displaynames#features","content":" Everything in intl-displaynames proposal. ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Intl.DisplayNames","url":"/docs/polyfills/intl-displaynames#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Via polyfill-fastly.io","type":1,"pageTitle":"Intl.DisplayNames","url":"/docs/polyfills/intl-displaynames#via-polyfill-fastlyio","content":" You can use polyfill-fastly.io URL Builder to create a polyfill script tag for Intl.DisplayNames. By default the created URL does not come with any locale data. In order to add locale data, append Intl.DisplayNames.~locale.<locale> to your list of features. For example: <!-- Polyfill Intl.DisplayNames, its dependencies & `en` locale data --> <script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.DisplayNames,Intl.DisplayNames.~locale.en"></script> ","version":"Next","tagName":"h3"},{"title":"Simple","type":1,"pageTitle":"Intl.DisplayNames","url":"/docs/polyfills/intl-displaynames#simple","content":" import '@formatjs/intl-displaynames/polyfill' import '@formatjs/intl-displaynames/locale-data/en' // locale-data for en ","version":"Next","tagName":"h3"},{"title":"Dynamic import + capability detection","type":1,"pageTitle":"Intl.DisplayNames","url":"/docs/polyfills/intl-displaynames#dynamic-import--capability-detection","content":" import {shouldPolyfill} from '@formatjs/intl-displaynames/should-polyfill' async function polyfill(locale: string) { const unsupportedLocale = shouldPolyfill(locale) // This locale is supported if (!unsupportedLocale) { return } // Load the polyfill 1st BEFORE loading data await import('@formatjs/intl-displaynames/polyfill-force') await import(`@formatjs/intl-displaynames/locale-data/${locale}`) } ","version":"Next","tagName":"h3"},{"title":"Intl.getCanonicalLocales","type":0,"sectionRef":"#","url":"/docs/polyfills/intl-getcanonicallocales","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Intl.getCanonicalLocales","url":"/docs/polyfills/intl-getcanonicallocales#installation","content":" npmyarn npm i @formatjs/intl-getcanonicallocales ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Intl.getCanonicalLocales","url":"/docs/polyfills/intl-getcanonicallocales#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Via polyfill-fastly.io","type":1,"pageTitle":"Intl.getCanonicalLocales","url":"/docs/polyfills/intl-getcanonicallocales#via-polyfill-fastlyio","content":" You can use polyfill-fastly.io URL Builder to create a polyfill script tag for Intl.GetCanonicalLocales. For example: <!-- Polyfill Intl.GetCanonicalLocales & its dependencies --> <script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.GetCanonicalLocales"></script> ","version":"Next","tagName":"h3"},{"title":"Simple","type":1,"pageTitle":"Intl.getCanonicalLocales","url":"/docs/polyfills/intl-getcanonicallocales#simple","content":" import '@formatjs/intl-getcanonicallocales/polyfill' ","version":"Next","tagName":"h3"},{"title":"Dynamic import + capability detection","type":1,"pageTitle":"Intl.getCanonicalLocales","url":"/docs/polyfills/intl-getcanonicallocales#dynamic-import--capability-detection","content":" import {shouldPolyfill} from '@formatjs/intl-getcanonicallocales/should-polyfill' async function polyfill() { // This platform already supports Intl.getCanonicalLocales if (shouldPolyfill()) { await import('@formatjs/intl-getcanonicallocales/polyfill') } // Alternatively, force the polyfill regardless of support await import('@formatjs/intl-getcanonicallocales/polyfill-force') } ","version":"Next","tagName":"h3"},{"title":"Tests","type":1,"pageTitle":"Intl.getCanonicalLocales","url":"/docs/polyfills/intl-getcanonicallocales#tests","content":" This library is test262-compliant. ","version":"Next","tagName":"h2"},{"title":"Intl.ListFormat","type":0,"sectionRef":"#","url":"/docs/polyfills/intl-listformat","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Intl.ListFormat","url":"/docs/polyfills/intl-listformat#installation","content":" npmyarn npm i @formatjs/intl-listformat ","version":"Next","tagName":"h2"},{"title":"Requirements","type":1,"pageTitle":"Intl.ListFormat","url":"/docs/polyfills/intl-listformat#requirements","content":" Intl.getCanonicalLocales or polyfillIntl.Locale or polyfill. ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Intl.ListFormat","url":"/docs/polyfills/intl-listformat#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Via polyfill-fastly.io","type":1,"pageTitle":"Intl.ListFormat","url":"/docs/polyfills/intl-listformat#via-polyfill-fastlyio","content":" You can use polyfill-fastly.io URL Builder to create a polyfill script tag for Intl.ListFormat. By default the created URL does not come with any locale data. In order to add locale data, append Intl.ListFormat.~locale.<locale> to your list of features. For example: <!-- Polyfill Intl.ListFormat, its dependencies & `en` locale data --> <script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.ListFormat,Intl.ListFormat.~locale.en"></script> ","version":"Next","tagName":"h3"},{"title":"Simple","type":1,"pageTitle":"Intl.ListFormat","url":"/docs/polyfills/intl-listformat#simple","content":" import '@formatjs/intl-listformat/polyfill' import '@formatjs/intl-listformat/locale-data/en' // locale-data for en ","version":"Next","tagName":"h3"},{"title":"Dynamic import + capability detection","type":1,"pageTitle":"Intl.ListFormat","url":"/docs/polyfills/intl-listformat#dynamic-import--capability-detection","content":" import {shouldPolyfill} from '@formatjs/intl-listformat/should-polyfill' async function polyfill(locale: string) { const unsupportedLocale = shouldPolyfill(locale) // This locale is supported if (!unsupportedLocale) { return } // Load the polyfill 1st BEFORE loading data await import('@formatjs/intl-listformat/polyfill-force') await import(`@formatjs/intl-listformat/locale-data/${unsupportedLocale}`) } ","version":"Next","tagName":"h3"},{"title":"Tests","type":1,"pageTitle":"Intl.ListFormat","url":"/docs/polyfills/intl-listformat#tests","content":" This library is fully test262-compliant. ","version":"Next","tagName":"h2"},{"title":"Intl.LocaleMatcher","type":0,"sectionRef":"#","url":"/docs/polyfills/intl-localematcher","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Intl.LocaleMatcher","url":"/docs/polyfills/intl-localematcher#installation","content":" npmyarn npm i @formatjs/intl-localematcher ","version":"Next","tagName":"h2"},{"title":"Requirements","type":1,"pageTitle":"Intl.LocaleMatcher","url":"/docs/polyfills/intl-localematcher#requirements","content":" Intl.getCanonicalLocales or polyfillIntl.Locale or polyfill ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Intl.LocaleMatcher","url":"/docs/polyfills/intl-localematcher#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Simple","type":1,"pageTitle":"Intl.LocaleMatcher","url":"/docs/polyfills/intl-localematcher#simple","content":" import {match} from '@formatjs/intl-localematcher' match(['fr-XX', 'en'], ['fr', 'en'], 'en') // 'fr' match(['zh'], ['fr', 'en'], 'en') // 'en' ","version":"Next","tagName":"h3"},{"title":"Intl.Locale","type":0,"sectionRef":"#","url":"/docs/polyfills/intl-locale","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Intl.Locale","url":"/docs/polyfills/intl-locale#installation","content":" npmyarn npm i @formatjs/intl-locale ","version":"Next","tagName":"h2"},{"title":"Requirements","type":1,"pageTitle":"Intl.Locale","url":"/docs/polyfills/intl-locale#requirements","content":" Intl.getCanonicalLocales or polyfill ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Intl.Locale","url":"/docs/polyfills/intl-locale#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Via polyfill-fastly.io","type":1,"pageTitle":"Intl.Locale","url":"/docs/polyfills/intl-locale#via-polyfill-fastlyio","content":" You can use polyfill-fastly.io URL Builder to create a polyfill script tag for Intl.Locale. For example: <!-- Polyfill Intl.Locale & its dependencies --> <script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.Locale"></script> ","version":"Next","tagName":"h3"},{"title":"Simple","type":1,"pageTitle":"Intl.Locale","url":"/docs/polyfills/intl-locale#simple","content":" import '@formatjs/intl-locale/polyfill' ","version":"Next","tagName":"h3"},{"title":"Dynamic import + capability detection","type":1,"pageTitle":"Intl.Locale","url":"/docs/polyfills/intl-locale#dynamic-import--capability-detection","content":" import {shouldPolyfill} from '@formatjs/intl-locale/should-polyfill' async function polyfill() { // This platform already supports Intl.Locale if (shouldPolyfill()) { await import('@formatjs/intl-locale/polyfill') } // Alternatively, force the polyfill regardless of support await import('@formatjs/intl-locale/polyfill-force') } ","version":"Next","tagName":"h3"},{"title":"Tests","type":1,"pageTitle":"Intl.Locale","url":"/docs/polyfills/intl-locale#tests","content":" This library is test262-compliant. ","version":"Next","tagName":"h2"},{"title":"Intl.PluralRules","type":0,"sectionRef":"#","url":"/docs/polyfills/intl-pluralrules","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Intl.PluralRules","url":"/docs/polyfills/intl-pluralrules#installation","content":" npmyarn npm i @formatjs/intl-pluralrules ","version":"Next","tagName":"h2"},{"title":"Requirements","type":1,"pageTitle":"Intl.PluralRules","url":"/docs/polyfills/intl-pluralrules#requirements","content":" Intl.getCanonicalLocales or polyfillIntl.Locale or polyfill. ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Intl.PluralRules","url":"/docs/polyfills/intl-pluralrules#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Via polyfill-fastly.io","type":1,"pageTitle":"Intl.PluralRules","url":"/docs/polyfills/intl-pluralrules#via-polyfill-fastlyio","content":" You can use polyfill-fastly.io URL Builder to create a polyfill script tag for Intl.PluralRules. By default the created URL does not come with any locale data. In order to add locale data, append Intl.PluralRules.~locale.<locale> to your list of features. For example: <!-- Polyfill Intl.PluralRules, its dependencies & `en` locale data --> <script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.PluralRules,Intl.PluralRules.~locale.en"></script> ","version":"Next","tagName":"h3"},{"title":"Simple","type":1,"pageTitle":"Intl.PluralRules","url":"/docs/polyfills/intl-pluralrules#simple","content":" import '@formatjs/intl-pluralrules/polyfill' import '@formatjs/intl-pluralrules/locale-data/en' // locale-data for en ","version":"Next","tagName":"h3"},{"title":"React Native","type":1,"pageTitle":"Intl.PluralRules","url":"/docs/polyfills/intl-pluralrules#react-native","content":" The polyfill conditional detection code runs very slowly on Android and can slow down your app's startup time by seconds. Since React Native uses Hermes which does not support Intl.PluralRules, import /polyfill-force instead for much better performance: import '@formatjs/intl-pluralrules/polyfill-force' // instead of /polyfill import '@formatjs/intl-pluralrules/locale-data/en' ","version":"Next","tagName":"h3"},{"title":"Dynamic import + capability detection","type":1,"pageTitle":"Intl.PluralRules","url":"/docs/polyfills/intl-pluralrules#dynamic-import--capability-detection","content":" import {shouldPolyfill} from '@formatjs/intl-pluralrules/should-polyfill' async function polyfill(locale: string) { const unsupportedLocale = shouldPolyfill(locale) // This locale is supported if (!unsupportedLocale) { return } // Load the polyfill 1st BEFORE loading data await import('@formatjs/intl-pluralrules/polyfill-force') await import(`@formatjs/intl-pluralrules/locale-data/${unsupportedLocale}`) } ","version":"Next","tagName":"h3"},{"title":"Intl.RelativeTimeFormat","type":0,"sectionRef":"#","url":"/docs/polyfills/intl-relativetimeformat","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Intl.RelativeTimeFormat","url":"/docs/polyfills/intl-relativetimeformat#installation","content":" npmyarn npm i @formatjs/intl-relativetimeformat ","version":"Next","tagName":"h2"},{"title":"Requirements","type":1,"pageTitle":"Intl.RelativeTimeFormat","url":"/docs/polyfills/intl-relativetimeformat#requirements","content":" This package requires the following capabilities: Intl.getCanonicalLocales or polyfillIntl.Locale or polyfill.Intl.PluralRules or polyfill.If you need formatToParts and have to support IE11- or Node 10-, you'd need to polyfill using @formatjs/intl-numberformat. ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Intl.RelativeTimeFormat","url":"/docs/polyfills/intl-relativetimeformat#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Via polyfill-fastly.io","type":1,"pageTitle":"Intl.RelativeTimeFormat","url":"/docs/polyfills/intl-relativetimeformat#via-polyfill-fastlyio","content":" You can use polyfill-fastly.io URL Builder to create a polyfill script tag for Intl.RelativeTimeFormat. By default the created URL does not come with any locale data. In order to add locale data, append Intl.RelativeTimeFormat.~locale.<locale> to your list of features. For example: <!-- Polyfill Intl.RelativeTimeFormat, its dependencies & `en` locale data --> <script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.RelativeTimeFormat,Intl.RelativeTimeFormat.~locale.en"></script> ","version":"Next","tagName":"h3"},{"title":"Simple","type":1,"pageTitle":"Intl.RelativeTimeFormat","url":"/docs/polyfills/intl-relativetimeformat#simple","content":" import '@formatjs/intl-relativetimeformat/polyfill' import '@formatjs/intl-relativetimeformat/locale-data/en' // locale-data for en ","version":"Next","tagName":"h3"},{"title":"Dynamic import + capability detection","type":1,"pageTitle":"Intl.RelativeTimeFormat","url":"/docs/polyfills/intl-relativetimeformat#dynamic-import--capability-detection","content":" import {shouldPolyfill} from '@formatjs/intl-relativetimeformat/should-polyfill' async function polyfill(locale: string) { const unsupportedLocale = shouldPolyfill(locale) // This locale is supported if (!unsupportedLocale) { return } // Load the polyfill 1st BEFORE loading data await import('@formatjs/intl-relativetimeformat/polyfill-force') await import( `@formatjs/intl-relativetimeformat/locale-data/${unsupportedLocale}` ) } ","version":"Next","tagName":"h3"},{"title":"Tests","type":1,"pageTitle":"Intl.RelativeTimeFormat","url":"/docs/polyfills/intl-relativetimeformat#tests","content":" This library is fully test262-compliant. ","version":"Next","tagName":"h2"},{"title":"Intl.NumberFormat (ESNext)","type":0,"sectionRef":"#","url":"/docs/polyfills/intl-numberformat","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Intl.NumberFormat (ESNext)","url":"/docs/polyfills/intl-numberformat#installation","content":" npmyarn npm i @formatjs/intl-numberformat ","version":"Next","tagName":"h2"},{"title":"Requirements","type":1,"pageTitle":"Intl.NumberFormat (ESNext)","url":"/docs/polyfills/intl-numberformat#requirements","content":" This package requires the following capabilities: Intl.getCanonicalLocales or polyfillIntl.Locale or polyfill.Intl.PluralRules or polyfill. ","version":"Next","tagName":"h2"},{"title":"Features","type":1,"pageTitle":"Intl.NumberFormat (ESNext)","url":"/docs/polyfills/intl-numberformat#features","content":" Everything in the ES2020 Internationalization API spec (https://tc39.es/ecma402). ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Intl.NumberFormat (ESNext)","url":"/docs/polyfills/intl-numberformat#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Via polyfill-fastly.io","type":1,"pageTitle":"Intl.NumberFormat (ESNext)","url":"/docs/polyfills/intl-numberformat#via-polyfill-fastlyio","content":" You can use polyfill-fastly.io URL Builder to create a polyfill script tag for Intl.NumberFormat. By default the created URL does not come with any locale data. In order to add locale data, append Intl.NumberFormat.~locale.<locale>, as well as locale data for any required polyfills, to your list of features. For example: <!-- Polyfill Intl.NumberFormat, its dependencies & `en` locale data --> <script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.NumberFormat,Intl.NumberFormat.~locale.en"></script> Or if Intl.PluralRules needs to be polyfilled as well: <!-- Polyfill Intl.NumberFormat, its dependencies & `en` locale data --> <script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.NumberFormat,Intl.NumberFormat.~locale.en,Intl.PluralRules.~locale.en"></script> ","version":"Next","tagName":"h3"},{"title":"Simple","type":1,"pageTitle":"Intl.NumberFormat (ESNext)","url":"/docs/polyfills/intl-numberformat#simple","content":" import '@formatjs/intl-numberformat/polyfill' import '@formatjs/intl-numberformat/locale-data/en' // locale-data for en ","version":"Next","tagName":"h3"},{"title":"Dynamic import + capability detection","type":1,"pageTitle":"Intl.NumberFormat (ESNext)","url":"/docs/polyfills/intl-numberformat#dynamic-import--capability-detection","content":" import {shouldPolyfill} from '@formatjs/intl-numberformat/should-polyfill' async function polyfill(locale: string) { const unsupportedLocale = shouldPolyfill(locale) // This locale is supported if (!unsupportedLocale) { return } // Load the polyfill 1st BEFORE loading data await import('@formatjs/intl-numberformat/polyfill-force') await import(`@formatjs/intl-numberformat/locale-data/${unsupportedLocale}`) } ","version":"Next","tagName":"h3"},{"title":"Supported Units","type":1,"pageTitle":"Intl.NumberFormat (ESNext)","url":"/docs/polyfills/intl-numberformat#supported-units","content":" ","version":"Next","tagName":"h2"},{"title":"Simple Units","type":1,"pageTitle":"Intl.NumberFormat (ESNext)","url":"/docs/polyfills/intl-numberformat#simple-units","content":" Currently, the spec defines a list of sanctioned units as below. type Unit = | 'acre' | 'bit' | 'byte' | 'celsius' | 'centimeter' | 'day' | 'degree' | 'fahrenheit' | 'fluid-ounce' | 'foot' | 'gallon' | 'gigabit' | 'gigabyte' | 'gram' | 'hectare' | 'hour' | 'inch' | 'kilobit' | 'kilobyte' | 'kilogram' | 'kilometer' | 'liter' | 'megabit' | 'megabyte' | 'meter' | 'mile' | 'mile-scandinavian' | 'millimeter' | 'milliliter' | 'millisecond' | 'minute' | 'month' | 'ounce' | 'percent' | 'petabyte' | 'pound' | 'second' | 'stone' | 'terabit' | 'terabyte' | 'week' | 'yard' | 'year' ","version":"Next","tagName":"h3"},{"title":"Compound Units","type":1,"pageTitle":"Intl.NumberFormat (ESNext)","url":"/docs/polyfills/intl-numberformat#compound-units","content":" You can specify X-per-Y unit, where X and Y are sanctioned simple units (e.g. kilometer-per-hour). The library will choose the best-fit localized pattern to format this compound unit. ","version":"Next","tagName":"h3"},{"title":"Intl.Segmenter","type":0,"sectionRef":"#","url":"/docs/polyfills/intl-segmenter","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Intl.Segmenter","url":"/docs/polyfills/intl-segmenter#installation","content":" npmyarn npm i @formatjs/intl-segmenter ","version":"Next","tagName":"h2"},{"title":"Features","type":1,"pageTitle":"Intl.Segmenter","url":"/docs/polyfills/intl-segmenter#features","content":" Everything in intl-segmenter proposal ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Intl.Segmenter","url":"/docs/polyfills/intl-segmenter#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Via polyfill-fastly.io","type":1,"pageTitle":"Intl.Segmenter","url":"/docs/polyfills/intl-segmenter#via-polyfill-fastlyio","content":" You can use polyfill-fastly.io URL Builder to create a polyfill script tag for Intl.Segmenter. For example: <!-- Polyfill Intl.Segmenter--> <script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.Segmenter"></script> ","version":"Next","tagName":"h3"},{"title":"Simple","type":1,"pageTitle":"Intl.Segmenter","url":"/docs/polyfills/intl-segmenter#simple","content":" import '@formatjs/intl-segmenter/polyfill' ","version":"Next","tagName":"h3"},{"title":"Dynamic import + capability detection","type":1,"pageTitle":"Intl.Segmenter","url":"/docs/polyfills/intl-segmenter#dynamic-import--capability-detection","content":" import {shouldPolyfill} from '@formatjs/intl-segmenter/should-polyfill' async function polyfill(locale: string) { if (shouldPolyfill()) { await import('@formatjs/intl-segmenter/polyfill-force') } } ","version":"Next","tagName":"h3"},{"title":"Intl.supportedValuesOf","type":0,"sectionRef":"#","url":"/docs/polyfills/intl-supportedvaluesof","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Intl.supportedValuesOf","url":"/docs/polyfills/intl-supportedvaluesof#installation","content":" npmyarn npm i @formatjs/intl-enumerator ","version":"Next","tagName":"h2"},{"title":"Requirements","type":1,"pageTitle":"Intl.supportedValuesOf","url":"/docs/polyfills/intl-supportedvaluesof#requirements","content":" Intl.CollatorIntl.DateTimeFormat or polyfillIntl.NumberFormat or polyfill. ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Intl.supportedValuesOf","url":"/docs/polyfills/intl-supportedvaluesof#usage","content":" ","version":"Next","tagName":"h2"},{"title":"Simple","type":1,"pageTitle":"Intl.supportedValuesOf","url":"/docs/polyfills/intl-supportedvaluesof#simple","content":" import '@formatjs/intl-enumerator/polyfill' ","version":"Next","tagName":"h3"},{"title":"Dynamic import + capability detection","type":1,"pageTitle":"Intl.supportedValuesOf","url":"/docs/polyfills/intl-supportedvaluesof#dynamic-import--capability-detection","content":" import {shouldPolyfill} from '@formatjs/intl-enumerator/should-polyfill' async function polyfill() { // This platform already supports Intl.supportedValuesOf if (shouldPolyfill()) { await import('@formatjs/intl-enumerator/polyfill') } // Alternatively, force the polyfill regardless of support await import('@formatjs/intl-enumerator/polyfill-force') } ","version":"Next","tagName":"h3"},{"title":"Tests","type":1,"pageTitle":"Intl.supportedValuesOf","url":"/docs/polyfills/intl-supportedvaluesof#tests","content":" This library is test262-compliant. ","version":"Next","tagName":"h2"},{"title":"Core FormatJS Intl","type":0,"sectionRef":"#","url":"/docs/intl","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#installation","content":" npmyarn npm i -S @formatjs/intl ","version":"Next","tagName":"h2"},{"title":"The intl object","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#the-intl-object","content":" The core of @formatjs/intl is the intl object (of type IntlShape), which is the instance to store a cache of all Intl.* APIs, configurations, compiled messages and such. The lifecycle of the intl object is typically tied to the locale & the list of messages that it contains, which means when you switch locale, this object should be recreated. tip The intl object should be reused as much as possible for performance. ","version":"Next","tagName":"h2"},{"title":"createIntl","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#createintl","content":" This allows you to create an IntlShape object that contains all format* methods. For example: import {createIntl, createIntlCache} from '@formatjs/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) ","version":"Next","tagName":"h2"},{"title":"createIntlCache","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#createintlcache","content":" Creates a cache instance to be used globally across locales. This memoizes previously created Intl.* constructors for performance and is only an in-memory cache. ","version":"Next","tagName":"h2"},{"title":"IntlShape","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#intlshape","content":" interface IntlConfig { locale: string timeZone?: string fallbackOnEmptyString?: boolean formats: CustomFormats messages: Record<string, string> | Record<string, MessageFormatElement[]> defaultLocale: string defaultRichTextElements?: Record<string, FormatXMLElementFn<React.ReactNode>> defaultFormats: CustomFormats onError(err: string): void onWarn(warning: string): void } interface IntlFormatters { formatDate(value: number | Date | string, opts?: FormatDateOptions): string formatTime(value: number | Date | string, opts?: FormatDateOptions): string formatDateToParts( value: number | Date | string, opts?: FormatDateOptions ): Intl.DateTimeFormatPart[] formatTimeToParts( value: number | Date | string, opts?: FormatDateOptions ): Intl.DateTimeFormatPart[] formatRelativeTime( value: number, unit?: FormattableUnit, opts?: FormatRelativeTimeOptions ): string formatNumber(value: number, opts?: FormatNumberOptions): string formatNumberToParts( value: number, opts?: FormatNumberOptions ): Intl.NumberFormatPart[] formatPlural( value: number | string, opts?: FormatPluralOptions ): ReturnType<Intl.PluralRules['select']> formatMessage( descriptor: MessageDescriptor, values?: Record<string, PrimitiveType | FormatXMLElementFn<string, string>> ): string formatMessage( descriptor: MessageDescriptor, values?: Record<string, PrimitiveType | T | FormatXMLElementFn<T, R>> ): R formatList(values: Array<string>, opts?: FormatListOptions): string formatList( values: Array<string | T>, opts?: FormatListOptions ): T | string | Array<string | T> formatListToParts(values: Array<string | T>, opts?: FormatListOptions): Part[] formatDisplayName( value: string, opts?: FormatDisplayNameOptions ): string | undefined } type IntlShape = IntlConfig & IntlFormatters The definition above shows what the intl object will look like. It's made up of two parts: IntlConfig: The intl metadata passed as props into the parent <IntlProvider>.IntlFormatters: The imperative formatting API described below. ","version":"Next","tagName":"h2"},{"title":"locale, formats, and messages","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#locale-formats-and-messages","content":" The user's current locale and what the app should be rendered in. While defaultLocale and defaultFormats are for fallbacks or during development and represent the app's default. Notice how there is no defaultMessages, that's because each Message Descriptor provides a defaultMessage. ","version":"Next","tagName":"h3"},{"title":"defaultLocale and defaultFormats","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#defaultlocale-and-defaultformats","content":" Default locale & formats for when a message is not translated (missing from messages). defaultLocale should be the locale that defaultMessages are declared in so that a sentence is coherent in a single locale. Without 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. ","version":"Next","tagName":"h3"},{"title":"onError","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#onerror","content":" Allows the user to provide a custom error handler. By default, error messages are logged using console.error if NODE_ENV is not set to production. ","version":"Next","tagName":"h3"},{"title":"defaultRichTextElements","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#defaultrichtextelements","content":" A map of tag to rich text formatting function. This is meant to provide a centralized way to format common tags such as <b>, <p>... or enforcing certain Design System in the codebase (e.g standardized <a> or <button>...). See https://github.com/formatjs/formatjs/issues/1752 for more context. ","version":"Next","tagName":"h3"},{"title":"fallbackOnEmptyString","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#fallbackonemptystring","content":" Defaults to true. This boolean option can be useful if you want to intentionally provide empty values for certain locales via empty strings. When fallbackOnEmptyString is false, empty strings will be returned instead of triggering the fallback procedure. This behaviour can be leveraged to "skip" content in specific locales. See this issue for more context. ","version":"Next","tagName":"h3"},{"title":"formatDate","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#formatdate","content":" function formatDate( value: number | Date, options?: Intl.DateTimeFormatOptions & {format?: string} ): string This function will return a formatted date string. It expects a value which can be parsed as a date (i.e., isFinite(new Date(value))), and accepts options that conform to DateTimeFormatOptions. Live Editor intl.formatDate(Date.now(), { year: 'numeric', month: 'numeric', day: 'numeric', }) Result ","version":"Next","tagName":"h2"},{"title":"formatTime","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#formattime","content":" function formatTime( value: number | Date, options?: Intl.DateTimeFormatOptions & {format?: string} ): string This function will return a formatted date string, but it differs from formatDate by having the following default options: { hour: 'numeric', minute: 'numeric', } It expects a value which can be parsed as a date (i.e., isFinite(new Date(value))), and accepts options that conform to DateTimeFormatOptions. Live Editor intl.formatTime(Date.now()) // "4:03 PM" Result ","version":"Next","tagName":"h2"},{"title":"formatRelativeTime","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#formatrelativetime","content":" browser support This requires Intl.RelativeTimeFormat which has limited browser support. Please use our polyfill if you plan to support them. type Unit = | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year' type RelativeTimeFormatOptions = { numeric?: 'always' | 'auto' style?: 'long' | 'short' | 'narrow' } function formatRelativeTime( value: number, unit: Unit, options?: Intl.RelativeTimeFormatOptions & { format?: string } ): string This function will return a formatted relative time string (e.g., "1 hour ago"). It expects a value which is a number, a unit and options that conform to Intl.RelativeTimeFormatOptions. Live Editor intl.formatRelativeTime(0) Result Live Editor intl.formatRelativeTime(-24, 'hour', {style: 'narrow'}) Result ","version":"Next","tagName":"h2"},{"title":"formatNumber","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#formatnumber","content":" This function uses Intl.NumberFormat options. function formatNumber( value: number, options?: Intl.NumberFormatOptions & {format?: string} ): string This function will return a formatted number string. It expects a value which can be parsed as a number, and accepts options that conform to NumberFormatOptions. Live Editor intl.formatNumber(1000, {style: 'currency', currency: 'USD'}) Result Formatting Number using unit Currently this is part of ES2020 NumberFormat. We've provided a polyfill here and @formatjs/intl types allow users to pass in a sanctioned unit: Live Editor intl.formatNumber(1000, { style: 'unit', unit: 'kilobyte', unitDisplay: 'narrow', }) Result Live Editor intl.formatNumber(1000, { unit: 'fahrenheit', unitDisplay: 'long', style: 'unit', }) Result ","version":"Next","tagName":"h2"},{"title":"formatPlural","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#formatplural","content":" type PluralFormatOptions = { type?: 'cardinal' | 'ordinal' = 'cardinal' } function formatPlural( value: number, options?: Intl.PluralFormatOptions ): 'zero' | 'one' | 'two' | 'few' | 'many' | 'other' This function will return a plural category string: "zero", "one", "two", "few", "many", or "other". It expects a value which can be parsed as a number, and accepts options that conform to PluralFormatOptions. This is a low-level utility whose output could be provided to a switch statement to select a particular string to display. Live Editor intl.formatPlural(1) Result Live Editor intl.formatPlural(3, {style: 'ordinal'}) Result Live Editor intl.formatPlural(4, {style: 'ordinal'}) Result multiple language support This function should only be used in apps that only need to support one language. If your app supports multiple languages use formatMessage instead. ","version":"Next","tagName":"h2"},{"title":"formatList","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#formatlist","content":" browser support This requires Intl.ListFormat which has limited browser support. Please use our polyfill if you plan to support them. type ListFormatOptions = { type?: 'disjunction' | 'conjunction' | 'unit' style?: 'long' | 'short' | 'narrow' } function formatList( elements: (string | React.ReactNode)[], options?: Intl.ListFormatOptions ): string | React.ReactNode[] This function allows you to join list of things together in an i18n-safe way. For example, when the locale is en: Live Editor intl.formatList(['Me', 'myself', 'I'], {type: 'conjunction'}) Result Live Editor intl.formatList(['5 hours', '3 minutes'], {type: 'unit'}) Result ","version":"Next","tagName":"h2"},{"title":"formatDisplayName","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#formatdisplayname","content":" browser support This requires Intl.DisplayNames which has limited browser support. Please use our polyfill if you plan to support them. type FormatDisplayNameOptions = { style?: 'narrow' | 'short' | 'long' type?: 'language' | 'region' | 'script' | 'currency' fallback?: 'code' | 'none' } function formatDisplayName( value: string | number | Record<string, unknown>, options: FormatDisplayNameOptions ): string | undefined Usage examples: Live Editor intl.formatDisplayName('zh-Hans-SG', {type: 'language'}) Result Live Editor // ISO-15924 four letters script code to localized display name intl.formatDisplayName('Deva', {type: 'script'}) Result Live Editor // ISO-4217 currency code to localized display name intl.formatDisplayName('CNY', {type: 'currency'}) Result Live Editor // ISO-3166 two letters region code to localized display name intl.formatDisplayName('UN', {type: 'region'}) Result ","version":"Next","tagName":"h2"},{"title":"formatMessage","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#formatmessage","content":" ","version":"Next","tagName":"h2"},{"title":"Message Syntax","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#message-syntax","content":" String/Message formatting is a paramount feature of React Intl and it builds on ICU Message Formatting by using the ICU Message Syntax. This message syntax allows for simple to complex messages to be defined, translated, and then formatted at runtime. Simple Message: Hello, {name} Complex Message: Hello, {name}, you have {itemCount, plural, =0 {no items} one {# item} other {# items} }. See: The Message Syntax Guide. ","version":"Next","tagName":"h3"},{"title":"Message Descriptor","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#message-descriptor","content":" React Intl has a Message Descriptor concept which is used to define your app's default messages/strings and is passed into formatMessage. The Message Descriptors work very well for providing the data necessary for having the strings/messages translated, and they contain the following properties: id: A unique, stable identifier for the messagedescription: Context for the translator about how it's used in the UIdefaultMessage: The default message (probably in English) type MessageDescriptor = { id: string defaultMessage?: string description?: string | object } Extracting Message Descriptor You can extract inline-declared messages from source files using our CLI. ","version":"Next","tagName":"h3"},{"title":"Message Formatting Fallbacks","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#message-formatting-fallbacks","content":" 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: Lookup and format the translated message at id, passed to <IntlProvider>.Fallback to formatting the defaultMessage.Fallback to source of translated message at id.Fallback to source of defaultMessage.Fallback to the literal message id. Above, "source" refers to using the template as is, without any substitutions made. ","version":"Next","tagName":"h3"},{"title":"Usage","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#usage","content":" type MessageFormatPrimitiveValue = string | number | boolean | null | undefined function formatMessage( descriptor: MessageDescriptor, values?: Record<string, MessageFormatPrimitiveValue> ): string function formatMessage( descriptor: MessageDescriptor, values?: Record< string, MessageFormatPrimitiveValue | React.ReactElement | FormatXMLElementFn > ): string | React.ReactNode[] This function will return a formatted message string. It expects a MessageDescriptor with at least an id property, and accepts a shallow values object which are used to fill placeholders in the message. If a translated message with the id has been passed to the <IntlProvider> via its messages prop it will be formatted, otherwise it will fallback to formatting defaultMessage. See: Message Formatting Fallbacks for more details. Live Editor function () { const messages = defineMessages({ greeting: { id: 'app.greeting', defaultMessage: 'Hello, {name}!', description: 'Greeting to welcome the user to the app', }, }) return intl.formatMessage(messages.greeting, {name: 'Eric'}) } Result with ReactElement Live Editor function () { const messages = defineMessages({ greeting: { id: 'app.greeting', defaultMessage: 'Hello, {name}!', description: 'Greeting to welcome the user to the app', }, }) return intl.formatMessage(messages.greeting, {name: <b>Eric</b>}) } Result with rich text formatting Live Editor function () { const messages = defineMessages({ greeting: { id: 'app.greeting', defaultMessage: 'Hello, <bold>{name}</bold>!', description: 'Greeting to welcome the user to the app', }, }) return intl.formatMessage(messages.greeting, { name: 'Eric', bold: str => <b>{str}</b>, }) } Result The message we defined using defineMessages to support extraction via babel-plugin-formatjs, but it doesn't have to be if you're not using the Babel plugin. simple message Messages can be simple strings without placeholders, and that's the most common type of message. ","version":"Next","tagName":"h3"},{"title":"defineMessages/defineMessage","type":1,"pageTitle":"Core FormatJS Intl","url":"/docs/intl#definemessagesdefinemessage","content":" interface MessageDescriptor { id?: string description?: string | object defaultMessage?: string } function defineMessages( messageDescriptors: Record<string, MessageDescriptor> ): Record<string, MessageDescriptor> function defineMessage(messageDescriptor: MessageDescriptor): MessageDescriptor These functions are exported by the @formatjs/intl package and are simply a hook for our CLI & babel/TS plugin to use when compiling default messages defined in JavaScript source files. This function simply returns the Message Descriptor map object that's passed-in. import {defineMessages, defineMessage} from '@formatjs/intl' const messages = defineMessages({ greeting: { id: 'app.home.greeting', description: 'Message to greet the user.', defaultMessage: 'Hello, {name}!', }, }) const msg = defineMessage({ id: 'single', defaultMessage: 'single message', description: 'header', }) ","version":"Next","tagName":"h2"},{"title":"Overview","type":0,"sectionRef":"#","url":"/docs/react-intl","content":"","keywords":"","version":"Next"},{"title":"Runtime Requirements","type":1,"pageTitle":"Overview","url":"/docs/react-intl#runtime-requirements","content":" We support IE11 & 2 most recent versions of Edge, Chrome, Firefox & Safari. React Intl relies on these Intl APIs: Intl.NumberFormat: Available on IE11+Intl.DateTimeFormat: Available on IE11+Intl.PluralRules: This can be polyfilled using this package.Intl.RelativeTimeFormat: This can be polyfilled using this package.(Optional) Intl.DisplayNames: Required if you use formatDisplayNameor FormattedDisplayName. This can be polyfilled using this package. If you need to support older browsers, we recommend you do the following: If you're supporting browsers that do not have Intl, include this polyfill in your build. Polyfill Intl.NumberFormat with @formatjs/intl-numberformat. Polyfill Intl.DateTimeFormat with @formatjs/intl-datetimeformat If you're supporting browsers that do not have Intl.PluralRules (e.g IE11 & Safari 12-), include this polyfill in your build. If you're supporting browsers that do not have Intl.RelativeTimeFormat (e.g IE11, Edge, Safari 12-), include this polyfill in your build along with individual CLDR data for each locale you support. If you need Intl.DisplayNames, include this polyfill in your build along with individual CLDR data for each locale you support. ","version":"Next","tagName":"h2"},{"title":"Node.js","type":1,"pageTitle":"Overview","url":"/docs/react-intl#nodejs","content":" full-icu Starting with Node.js 13.0.0 full-icu is supported by default. If using React Intl in an earlier version of Node.js, your node binary has to either: Get compiled with full-icu using these instructions OR Uses full-icu npm package If your node version is missing any of the Intl APIs above, you'd have to polyfill them accordingly. ","version":"Next","tagName":"h3"},{"title":"React Native","type":1,"pageTitle":"Overview","url":"/docs/react-intl#react-native","content":" If you're using react-intl in React Native, make sure your runtime has built-in Intl support (similar to JSC International variant). See these issues for more details: https://github.com/formatjs/formatjs/issues/1356https://github.com/formatjs/formatjs/issues/992 React Native on iOS If you cannot use the Intl variant of JSC (e.g on iOS), follow the instructions in Runtime Requirements to polyfill those APIs accordingly. ","version":"Next","tagName":"h3"},{"title":"The react-intl Package","type":1,"pageTitle":"Overview","url":"/docs/react-intl#the-react-intl-package","content":" Install the react-intl npm package via npm: npmyarn npm i -S react-intl The react-intl npm package distributes the following modules (links from unpkg): CommonJS: unbundled dependencies, "main" in package.json, warnings in dev.ES6: unbundled dependencies, "module" in package.json, warnings in dev. ","version":"Next","tagName":"h2"},{"title":"Module Bundlers","type":1,"pageTitle":"Overview","url":"/docs/react-intl#module-bundlers","content":" We've made React Intl work well with module bundlers like: Browserify, Webpack, or Rollup which can be used to bundle React Intl for the browser: The "browser" field in package.json is specified so that only basic English locale data is included when bundling. This way when using the "main" module in Node all locale data is loaded, but ignored when bundled for the browser. An ES6 version of React Intl is provided as "jsnext:main" and "module" in package.json and can be used with Rollup. Development-time warnings are wrapped with process.env.NODE_ENV !== 'production', this allows you to specify NODE_ENV when bundling and minifying to have these code blocks removed. ","version":"Next","tagName":"h3"},{"title":"The React Intl Module","type":1,"pageTitle":"Overview","url":"/docs/react-intl#the-react-intl-module","content":" Whether you use the ES6, CommonJS, or UMD version of React Intl, they all provide the same named exports: injectIntldefineMessagesIntlProviderFormattedDateFormattedTimeFormattedRelativeTimeFormattedNumberFormattedPluralFormattedMessage react When using the UMD version of React Intl without a module system, it will expect react to exist on the global variable: React, and put the above named exports on the global variable: ReactIntl. ","version":"Next","tagName":"h2"},{"title":"Creating an I18n Context","type":1,"pageTitle":"Overview","url":"/docs/react-intl#creating-an-i18n-context","content":" Now with React Intl and its locale data loaded an i18n context can be created for your React app. 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 <Formatted*> components. This is the same concept as what Flux frameworks like Redux use to provide access to a store within a component tree. All apps using React Intl must use the <IntlProvider> component. The most common usage is to wrap your root React component with <IntlProvider> and configure it with the user's current locale and the corresponding translated strings/messages: ReactDOM.render( <IntlProvider locale={usersLocale} messages={translationsForUsersLocale}> <App /> </IntlProvider>, document.getElementById('container') ) See: The <IntlProvider> docs for more details. ","version":"Next","tagName":"h2"},{"title":"Formatting Data","type":1,"pageTitle":"Overview","url":"/docs/react-intl#formatting-data","content":" React Intl has two ways to format data, through React components and its API. The components provide an idiomatic-React way of integrating internationalization into a React app, and the <Formatted*> components have benefits over always using the imperative API directly. The API should be used when your React component needs to format data to a string value where a React element is not suitable; e.g., a title or aria attribute, or for side-effect in componentDidMount. React Intl's imperative API is accessed via injectIntl, a High-Order Component (HOC) factory. It will wrap the passed-in React component with another React component which provides the imperative formatting API into the wrapped component via its props. (This is similar to the connect-to-stores pattern found in many Flux implementations.) Here's an example using <IntlProvider>, <Formatted*> components, and the imperative API to setup an i18n context and format data: import React from 'react'; import ReactDOM from 'react-dom'; import {IntlProvider, FormattedRelative, useIntl} from 'react-intl'; const MS_IN_DAY = 1e3 * 3600 * 24 const PostDate = ({date}) => { const intl = useIntl() return ( <span title={intl.formatDate(date)}> <FormattedRelativeTime value={(Date.now() - date)/MS_IN_DAY} unit="day"/> </span> ) }); const App = ({post}) => ( <div> <h1>{post.title}</h1> <p> <PostDate date={post.date} /> </p> <div>{post.body}</div> </div> ); ReactDOM.render( <IntlProvider locale={navigator.language}> <App post={{ title: 'Hello, World!', date: new Date(1459913574887), body: 'Amazing content.', }} /> </IntlProvider>, document.getElementById('container') ); Assuming navigator.language is "en-us": <div> <h1>Hello, World!</h1> <p><span title="4/5/2016">yesterday</span></p> <div>Amazing content.</div> </div> See: The API docs and Component docs for more details. ESM Build react-intl and its underlying libraries (@formatjs/icu-messageformat-parser, intl-messageformat, @formatjs/intl-relativetimeformat) export ESM artifacts. This means you should configure your build toolchain to transpile those libraries. ","version":"Next","tagName":"h2"},{"title":"Jest","type":1,"pageTitle":"Overview","url":"/docs/react-intl#jest","content":" Add transformIgnorePatterns to always include those libraries, e.g: { transformIgnorePatterns: [ '/node_modules/(?!intl-messageformat|@formatjs/icu-messageformat-parser).+\\\\.js$', ], } ","version":"Next","tagName":"h3"},{"title":"webpack","type":1,"pageTitle":"Overview","url":"/docs/react-intl#webpack","content":" If you're using babel-loader, or ts-loader, you can do 1 of the following: Add those libraries in include: { include: [ path.join(__dirname, 'node_modules/react-intl'), path.join(__dirname, 'node_modules/intl-messageformat'), path.join(__dirname, 'node_modules/@formatjs/icu-messageformat-parser'), ] } OR Add those libraries in exclude: exclude: /node_modules\\/(?!react-intl|intl-messageformat|@formatjs\\/icu-messageformat-parser)/, Core Concepts Formatters (Date, Number, Message, Relative)Provider and InjectorAPI and ComponentsMessage DescriptorMessage SyntaxDefining default messages for extractionCustom, named formats Example Apps There are several runnable example apps in this Git repo. These are a great way to see React Intl's core concepts in action in simplified applications. API Reference There are a few API layers that React Intl provides and is built on. When using React Intl you'll be interacting with Intl built-ins, React Intl's API, and its React components: ECMAScript Internationalization APIReact Intl APIReact Intl Components TypeScript Usage react-intl is written in TypeScript, thus having 1st-class TS support. In order to use react-intl in TypeScript, make sure your compilerOptions's lib config include ["esnext.intl", "es2017.intl", "es2018.intl"]. ","version":"Next","tagName":"h3"},{"title":"Typing message IDs and locale","type":1,"pageTitle":"Overview","url":"/docs/react-intl#typing-message-ids-and-locale","content":" By default, the type for the id prop of <FormattedMessage> and formatMessage is string. However, you can set a more restrictive type to get autocomplete and error checking. In order to do this, override the following global namespace with the union type of all of your message IDs. You can do this by including the following somewhere in your code: declare global { namespace FormatjsIntl { interface Message { ids: keyof typeof messages } } } Where messages is the object you would normally pass to <IntlProvider>, and would look something like: const messages = { greeting: 'Hello', planet: 'World', // ... } You can also override the following global to use a custom type for locale declare global { namespace FormatjsIntl { interface IntlConfig { locale: 'en' | 'fr' } } } Advanced Usage Our Advanced Usage has further guides for production setup in environments where performance is important. Supported Tooling ","version":"Next","tagName":"h2"},{"title":"Message extraction","type":1,"pageTitle":"Overview","url":"/docs/react-intl#message-extraction","content":" We've built @formatjs/cli that helps you extract messages from a list of files. It uses babel-plugin-formatjs under the hood and should be able to extract messages if you're declaring using 1 of the mechanisms below: import {defineMessages} from 'react-intl' defineMessages({ foo: { id: 'foo', defaultMessage: 'foo', description: 'bar', }, }) import {FormattedMessage} from 'react-intl' ;<FormattedMessage id="foo" defaultMessage="foo" description="bar" /> function Comp(props) { const {intl} = props return intl.formatMessage({ // The whole `intl.formatMessage` is required so we can extract id: 'foo', defaultMessage: 'foo', description: 'bar', }) } ","version":"Next","tagName":"h2"},{"title":"ESLint Plugin","type":1,"pageTitle":"Overview","url":"/docs/react-intl#eslint-plugin","content":" We've also built eslint-plugin-formatjs that helps enforcing specific rules on your messages if your translation vendor has restrictions. ","version":"Next","tagName":"h2"},{"title":"Upgrade Guide (v1 -> v2)","type":0,"sectionRef":"#","url":"/docs/react-intl/upgrade-guide-2x","content":"","keywords":"","version":"Next"},{"title":"Use React 0.14 or 15","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#use-react-014-or-15","content":" React Intl v2 has a peer dependency on react@^0.14.0 || ^15.0.0-0 and now takes advantage of features and changes in React 0.14 and also works with React 15. ","version":"Next","tagName":"h2"},{"title":"Update How Locale Data is Added","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#update-how-locale-data-is-added","content":" The locale data modules in React Intl v2 have been refactored to provide data, instead of mutating React Intl's internal locale data registry. The react-intl/locale-data/* files are also decoupled from the ReactIntl global and instead provide UMD modules with a new ReactIntlLocaleData global. These changes, mean apps need update how they are registering the locale data they need in the browser. ","version":"Next","tagName":"h2"},{"title":"Add Call to addLocaleData() in Browser","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#add-call-to-addlocaledata-in-browser","content":" There is now an addLocaleData() function that needs to be called with the locale data that has been loaded. You can do the following in your main client JavaScript entry point: This assumes a locale data <script> is added based on the request; e.g., for French speaking users: <script src="react-intl/locale-data/fr.js"></script> Using <script src="react-intl/dist/react-intl.js> if ('ReactIntl' in window && 'ReactIntlLocaleData' in window) { Object.keys(ReactIntlLocaleData).forEach(lang => { ReactIntl.addLocaleData(ReactIntlLocaleData[lang]) }) } Using Browserify/Webpack to Load React Intl import {addLocaleData} from 'react-intl' if ('ReactIntlLocaleData' in window) { Object.keys(ReactIntlLocaleData).forEach(lang => { addLocaleData(ReactIntlLocaleData[lang]) }) } info This decoupling of the library from the locale data, allows for the files to be loaded via <script async>. When using async scripts, your client bootstrapping code will need to wait for the load event, including the code above. ","version":"Next","tagName":"h3"},{"title":"Remove Intl Mixin","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#remove-intl-mixin","content":" The IntlMixin has been removed from React Intl v2. The mixin did two things: it automatically propagated locales, formats, and messages throughout an app's hierarchy, and it provided an imperative API via format*() functions. These jobs are now handled by <IntlProvider> and injectIntl(), respectively: ","version":"Next","tagName":"h2"},{"title":"Update to IntlProvider","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#update-to-intlprovider","content":" In React Intl v1, you would add the IntlMixin to your root component; e.g., <App>. Remove the IntlMixin and instead wrap your root component with <IntlProvider>: import ReactDOM from 'react-dom' import {IntlProvider} from 'react-intl' ReactDOM.render( <IntlProvider locale="en"> <App /> </IntlProvider>, document.getElementById('container') ) info The locale prop is singular, required, and only accepts a string value. This is a simplification of the plural locales prop used by the IntlMixin. ","version":"Next","tagName":"h3"},{"title":"Update to injectIntl()","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#update-to-injectintl","content":" The IntlMixin also provided the imperative API for custom components to use the format*() methods; e.g., formatDate() to get formatted strings for using in places like title and aria attribute. Remove the IntlMixin and instead use the injectIntl() Hight Order Component (HOC) factory function to inject the imperative API via props. Here's an example of a custom <RelativeTime> stateless component which uses injectIntl() and the imperative formatDate() API: import React from 'react' import {injectIntl, FormattedRelative} from 'react-intl' const to2Digits = num => `${num < 10 ? `0${num}` : num}` const RelativeTime = ({date, intl}) => { date = new Date(date) let year = date.getFullYear() let month = date.getMonth() + 1 let day = date.getDate() let formattedDate = intl.formatDate(date, { year: 'long', month: 'numeric', day: 'numeric', }) return ( <time dateTime={`${year}-${to2Digits(month)}-${to2Digits(day)}`} title={formattedDate} > <FormattedRelative value={date} /> </time> ) } export default injectIntl(RelativeTime) injectIntl() is similar to a connect() HOC factory function you might find in a Flux framework to connect a component to a store. ","version":"Next","tagName":"h3"},{"title":"Change How Messages are Formatted","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#change-how-messages-are-formatted","content":" The way string messages are formatted in React Intl v2 has changed significantly! This is the most disruptive set of change when upgrading from v1 to v2; but it enables many great new features. React Intl v2 introduces a new Message Descriptor concept which can be used to define an app's default string messages. A Message Descriptor is an object with the following properties, id is the only required prop: id: A unique, stable identifier for the messagedescription: Context for the translator about how it's used in the UIdefaultMessage: The default message (probably in English) info This upgrade guide will focus on using Message Descriptors that only contain an id property. ","version":"Next","tagName":"h2"},{"title":"Flatten messages Object","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#flatten-messages-object","content":" React Intl v2 no longer supports nested messages objects, instead the collection of translated string messages passed to <IntlProvider> must be flat. This is an explicit design choice which simplifies while increasing flexibility. React Intl v2 does not apply any special semantics to strings with dots; e.g., "namespaced.string_id". Apps using a nested messages object structure could use the following function to flatten their object according to React Intl v1's semantics: function flattenMessages(nestedMessages, prefix = '') { return Object.keys(nestedMessages).reduce((messages, key) => { let value = nestedMessages[key] let prefixedKey = prefix ? `${prefix}.${key}` : key if (typeof value === 'string') { messages[prefixedKey] = value } else { Object.assign(messages, flattenMessages(value, prefixedKey)) } return messages }, {}) } let messages = flattenMessages(nestedMessages) info Message ids can still contain "."s, so the ids themselves remain the same, it's only the messages object structure that needs to change. ","version":"Next","tagName":"h3"},{"title":"Replace getIntlMessage() Calls with Message Descriptors","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#replace-getintlmessage-calls-with-message-descriptors","content":" The getIntlMessage() method that was provided by the IntlMixin has been removed in React Intl v2. It was simply a helper that interpreted a message id string with "."s by looking up the translated message in a nested messages object. With the removal of IntlMixin and the change to a flat messages object, this method has been removed. All calls to getIntlMessage() need to be replaced with a Message Descriptor. Replace: this.getIntlMessage('some.message.id') With: { id: 'some.message.id' } ","version":"Next","tagName":"h3"},{"title":"Update formatMessage() Calls","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#update-formatmessage-calls","content":" A typical pattern when calling formatMessage() is to nest a call to getIntlMessage(). These can be easily updated: 1.0: let message = this.formatMessage(this.getIntlMessage('some.message.id'), values) 2.0: let message = this.props.intl.formatMessage({id: 'some.message.id'}, values) info In React Intl v2, the formatMessage() function is injected via injectIntl(). ","version":"Next","tagName":"h3"},{"title":"Update FormattedMessage and FormattedHTMLMessage Instances","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#update-formattedmessage-and-formattedhtmlmessage-instances","content":" The props for these two components have completely changed in React Intl v2. Instead of taking a message prop and treating all other props as values to fill in placeholders in a message, <FormattedMessage> and <FormattedHTMLMessage> now the same props as a Message Descriptor plus a new values prop. The new values prop groups all of the message's placeholder values together into an object. The following example shows up to update a <FormattedMessage> instance to use the new props and remove the call to getIntlMessage(): 1.0: <FormattedMessage message={this.getIntlMessage('greeting')} name="Eric" /> 2.0: <FormattedMessage id="greeting" values={{name: 'Eric'}} /> ","version":"Next","tagName":"h3"},{"title":"Update How Relative Times are Formatted","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#update-how-relative-times-are-formatted","content":" Minor changes have been made to how the "now" reference time is specified when formatting relative times in React Intl v2. It's uncommon to specify this value outside of test code, so it might not exist in your app. ","version":"Next","tagName":"h2"},{"title":"Rename FormattedRelative's now Prop to initialNow","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#rename-formattedrelatives-now-prop-to-initialnow","content":" A new feature has been added to <FormattedRelative> instances in React Intl v2, they now "tick" and stay up to date. Since time moves forward, it was confusing to have a prop named now, so it has been renamed to initialNow. Any <FormattedRelative> instances that use now should update to prop name to initialNow: 1.0: <FormattedRelative value={date} now={otherDate} /> 2.0: <FormattedRelative value={date} initialNow={otherDate} /> info The <IntlProvider> component also has a initialNow prop which can be assigned a value to stabilize the "now" reference time for all <FormattedRelative> instances. This is useful for universal/isomorphic apps to proper React checksums between the server and client initial render. ","version":"Next","tagName":"h3"},{"title":"Merge formatRelative()'s Second and Third Arguments","type":1,"pageTitle":"Upgrade Guide (v1 -> v2)","url":"/docs/react-intl/upgrade-guide-2x#merge-formatrelatives-second-and-third-arguments","content":" The signature of the formatRelative() function has been aligned with the other format*() functions and in React Intl v2, it only accepts two arguments: value and options. To specify a "now" reference time, add it to the options argument, and remove the third formatOptions argument: 1.0: let relative = this.formatRelative(date, {units: 'hour'}, {now: otherDate}) 2.0: let relative = this.props.intl.formatRelative(date, { units: 'hour', now: otherDate, }) info In React Intl v2, the formatRelative() function is injected via injectIntl(). ","version":"Next","tagName":"h3"},{"title":"Imperative API","type":0,"sectionRef":"#","url":"/docs/react-intl/api","content":"","keywords":"","version":"Next"},{"title":"Why Imperative API?","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#why-imperative-api","content":" While our components provide a seamless integration with React, the imperative API are recommended (sometimes required) in several use cases: Setting text attributes such as title, aria-label and the like where a React component cannot be used (e.g <img title/>)Formatting text/datetime... in non-React environment such as Node, Server API, Redux store, testing...High performance scenarios where the number of React components rendered becomes the bottleneck (e.g Finance stock portfolio rendering, virtual tables with a lot of cells...) ","version":"Next","tagName":"h2"},{"title":"The intl object","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#the-intl-object","content":" The core of react-intl is the intl object (of type IntlShape), which is the instance to store a cache of all Intl.* APIs, configurations, compiled messages and such. The lifecycle of the intl object is typically tied to the locale & the list of messages that it contains, which means when you switch locale, this object should be recreated. tip The intl object should be reused as much as possible for performance. There are a few ways to get access to the intl object: useIntl hook: Once you've declared your IntlProvider, you can get access to the intl object via calling this hook in your functional React componentinjectIntl HOC: In class-based React components, you can wrap them with the injectIntl HOC and intl should be available as a prop.createIntl: In a non-React environment (Node, vue, angular, testing... you name it), you can directly create a intl object by calling this function with the same configuration as the IntlProvider. ","version":"Next","tagName":"h2"},{"title":"useIntl hook","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#useintl-hook","content":" If a component can be expressed in a form of function component, using useIntl hook can be handy. This useIntl hook does not expect any option as its argument when being called. Typically, here is how you would like to use: import React from 'react' import {useIntl, FormattedDate} from 'react-intl' const FunctionComponent: React.FC<{date: number | Date}> = ({date}) => { const intl = useIntl() return ( <span title={intl.formatDate(date)}> <FormattedDate value={date} /> </span> ) } export default FunctionComponent To keep the API surface clean and simple, we only provide useIntl hook in the package. If preferable, user can wrap this built-in hook to make customized hook like useFormatMessage easily. Please visit React's official website for more general introduction on React hooks. ","version":"Next","tagName":"h2"},{"title":"injectIntl HOC","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#injectintl-hoc","content":" type WrappedComponentProps<IntlPropName extends string = 'intl'> = { [k in IntlPropName]: IntlShape } type WithIntlProps<P> = Omit<P, keyof WrappedComponentProps> & { forwardedRef?: React.Ref<any> } function injectIntl< IntlPropName extends string = 'intl', P extends WrappedComponentProps<IntlPropName> = WrappedComponentProps<any>, >( WrappedComponent: React.ComponentType<P>, options?: Opts<IntlPropName> ): React.ComponentType<WithIntlProps<P>> & { WrappedComponent: typeof WrappedComponent } This function is exported by the react-intl package and is a High-Order Component (HOC) factory. It will wrap the passed-in React component with another React component which provides the imperative formatting API into the wrapped component via its props. (This is similar to the connect-to-stores pattern found in many Flux implementations.) By default, the formatting API will be provided to the wrapped component via props.intl, but this can be overridden when specifying options.intlPropName. The value of the prop will be of type IntlShape, defined in the next section. import React from 'react' import {injectIntl, FormattedDate} from 'react-intl' interface Props { date: Date | number } const FunctionalComponent: React.FC<Props> = props => { const { date, intl, // Injected by `injectIntl` } = props return ( <span title={intl.formatDate(date)}> <FormattedDate value={date} /> </span> ) } export default injectIntl(FunctionalComponent) ","version":"Next","tagName":"h2"},{"title":"createIntl","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#createintl","content":" This allows you to create an IntlShape object without using Provider. This allows you to format things outside of React lifecycle while reusing the same intl object. For example: 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> ","version":"Next","tagName":"h2"},{"title":"createIntlCache","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#createintlcache","content":" Creates a cache instance to be used globally across locales. This memoizes previously created Intl.* constructors for performance and is only an in-memory cache. ","version":"Next","tagName":"h2"},{"title":"IntlShape","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#intlshape","content":" interface IntlConfig { locale: string timeZone?: string formats: CustomFormats textComponent?: React.ComponentType | keyof React.JSX.IntrinsicElements messages: Record<string, string> | Record<string, MessageFormatElement[]> defaultLocale: string defaultFormats: CustomFormats onError(err: string): void onWarn(warning: string): void } interface IntlFormatters { formatDate(value: number | Date | string, opts?: FormatDateOptions): string formatTime(value: number | Date | string, opts?: FormatDateOptions): string formatDateToParts( value: number | Date | string, opts?: FormatDateOptions ): Intl.DateTimeFormatPart[] formatTimeToParts( value: number | Date | string, opts?: FormatDateOptions ): Intl.DateTimeFormatPart[] formatRelativeTime( value: number, unit?: FormattableUnit, opts?: FormatRelativeTimeOptions ): string formatNumber(value: number, opts?: FormatNumberOptions): string formatNumberToParts( value: number, opts?: FormatNumberOptions ): Intl.NumberFormatPart[] formatPlural( value: number | string, opts?: FormatPluralOptions ): ReturnType<Intl.PluralRules['select']> formatMessage( descriptor: MessageDescriptor, values?: Record<string, PrimitiveType | FormatXMLElementFn<string, string>> ): string formatMessage( descriptor: MessageDescriptor, values?: Record<string, PrimitiveType | T | FormatXMLElementFn<T, R>> ): R formatList(values: Array<string>, opts?: FormatListOptions): string formatList( values: Array<string | T>, opts?: FormatListOptions ): T | string | Array<string | T> formatListToParts(values: Array<string | T>, opts?: FormatListOptions): Part[] formatDisplayName( value: string, opts?: FormatDisplayNameOptions ): string | undefined } type IntlShape = IntlConfig & IntlFormatters This interface is exported by the react-intl package that can be used in conjunction with the injectIntl HOC factory function. The definition above shows what the props.intl object will look like that's injected to your component via injectIntl. It's made up of two parts: IntlConfig: The intl metadata passed as props into the parent <IntlProvider>.IntlFormatters: The imperative formatting API described below. ","version":"Next","tagName":"h2"},{"title":"locale, formats, and messages","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#locale-formats-and-messages","content":" The user's current locale and what the app should be rendered in. While defaultLocale and defaultFormats are for fallbacks or during development and represent the app's default. Notice how there is no defaultMessages, that's because each Message Descriptor provides a defaultMessage. ","version":"Next","tagName":"h3"},{"title":"defaultLocale and defaultFormats","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#defaultlocale-and-defaultformats","content":" Default locale & formats for when a message is not translated (missing from messages). defaultLocale should be the locale that defaultMessages are declared in so that a sentence is coherent in a single locale. Without 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. ","version":"Next","tagName":"h3"},{"title":"textComponent","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#textcomponent","content":" Provides a way to configure the default wrapper for React Intl's <Formatted*> components. If not specified, <React.Fragment> is used. Before V3, span was used instead; check the migration guide for more info. ","version":"Next","tagName":"h3"},{"title":"onError","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#onerror","content":" Allows the user to provide a custom error handler. By default, error messages are logged using console.error if NODE_ENV is not set to production. ","version":"Next","tagName":"h3"},{"title":"wrapRichTextChunksInFragment","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#wraprichtextchunksinfragment","content":" When formatting rich text message, the output we produced is of type Array<string | React.ReactElement>, which will trigger key error. This wraps the output in a single React.Fragment to suppress that. ","version":"Next","tagName":"h3"},{"title":"defaultRichTextElements","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#defaultrichtextelements","content":" A map of tag to rich text formatting function. This is meant to provide a centralized way to format common tags such as <b>, <p>... or enforcing certain Design System in the codebase (e.g standardized <a> or <button>...). See https://github.com/formatjs/formatjs/issues/1752 for more context. ","version":"Next","tagName":"h3"},{"title":"formatDate","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#formatdate","content":" function formatDate( value: number | Date | string, options?: Intl.DateTimeFormatOptions & {format?: string} ): string This function will return a formatted date string. It expects a value which can be parsed as a date (i.e., isFinite(new Date(value))), and accepts options that conform to DateTimeFormatOptions. Live Editor intl.formatDate(Date.now(), { year: 'numeric', month: 'numeric', day: 'numeric', }) Result ","version":"Next","tagName":"h2"},{"title":"formatTime","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#formattime","content":" function formatTime( value: number | Date | string, options?: Intl.DateTimeFormatOptions & {format?: string} ): string This function will return a formatted date string, but it differs from formatDate by having the following default options: { hour: 'numeric', minute: 'numeric', } It expects a value which can be parsed as a date (i.e., isFinite(new Date(value))), and accepts options that conform to DateTimeFormatOptions. Live Editor intl.formatTime(Date.now()) /* "4:03 PM" */ Result ","version":"Next","tagName":"h2"},{"title":"formatDateTimeRange","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#formatdatetimerange","content":" browser support This requires Intl.DateTimeFormat.prototype.formatRange which has limited browser support. Please use our polyfill if you plan to support them. function formatDateTimeRange( from: number | Date | string, to: number | Date | string, options?: Intl.DateTimeFormatOptions & {format?: string} ): string This function will return a formatted date/time range string. Both from & to must be values which can be parsed as a date (i.e., isFinite(new Date(value))). It expects 2 values (a from Date & a to Date) and accepts options that conform to DateTimeFormatOptions. Live Editor intl.formatDateTimeRange(new Date('2020-1-1'), new Date('2020-1-15')) Result ","version":"Next","tagName":"h2"},{"title":"formatRelativeTime","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#formatrelativetime","content":" browser support This requires Intl.RelativeTimeFormat which has limited browser support. Please use our polyfill if you plan to support them. type Unit = | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year' type RelativeTimeFormatOptions = { numeric?: 'always' | 'auto' style?: 'long' | 'short' | 'narrow' } function formatRelativeTime( value: number, unit: Unit, options?: Intl.RelativeTimeFormatOptions & { format?: string } ): string This function will return a formatted relative time string (e.g., "1 hour ago"). It expects a value which is a number, a unit and options that conform to Intl.RelativeTimeFormatOptions. Live Editor intl.formatRelativeTime(0) Result Live Editor intl.formatRelativeTime(-24, 'hour', {style: 'narrow'}) Result ","version":"Next","tagName":"h2"},{"title":"formatNumber","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#formatnumber","content":" This function uses Intl.NumberFormat options. function formatNumber( value: number, options?: Intl.NumberFormatOptions & {format?: string} ): string This function will return a formatted number string. It expects a value which can be parsed as a number, and accepts options that conform to NumberFormatOptions. Live Editor intl.formatNumber(1000, {style: 'currency', currency: 'USD'}) Result Formatting Number using unit Currently this is part of ES2020 NumberFormat. We've provided a polyfill here and react-intl types allow users to pass in a sanctioned unit: Live Editor intl.formatNumber(1000, { style: 'unit', unit: 'kilobyte', unitDisplay: 'narrow', }) Result Live Editor intl.formatNumber(1000, { unit: 'fahrenheit', unitDisplay: 'long', style: 'unit', }) Result ","version":"Next","tagName":"h2"},{"title":"formatPlural","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#formatplural","content":" type PluralFormatOptions = { type?: 'cardinal' | 'ordinal' = 'cardinal' } function formatPlural( value: number, options?: Intl.PluralFormatOptions ): 'zero' | 'one' | 'two' | 'few' | 'many' | 'other' This function will return a plural category string: "zero", "one", "two", "few", "many", or "other". It expects a value which can be parsed as a number, and accepts options that conform to PluralFormatOptions. This is a low-level utility whose output could be provided to a switch statement to select a particular string to display. Live Editor intl.formatPlural(1) Result Live Editor intl.formatPlural(3, {style: 'ordinal'}) Result Live Editor intl.formatPlural(4, {style: 'ordinal'}) Result multiple language support This function should only be used in apps that only need to support one language. If your app supports multiple languages use formatMessage instead. ","version":"Next","tagName":"h2"},{"title":"formatList","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#formatlist","content":" browser support This requires Intl.ListFormat which has limited browser support. Please use our polyfill if you plan to support them. type ListFormatOptions = { type?: 'disjunction' | 'conjunction' | 'unit' style?: 'long' | 'short' | 'narrow' } function formatList( elements: (string | React.ReactNode)[], options?: Intl.ListFormatOptions ): string | React.ReactNode[] This function allows you to join list of things together in an i18n-safe way. For example, when the locale is en: Live Editor intl.formatList(['Me', 'myself', 'I'], {type: 'conjunction'}) Result Live Editor intl.formatList(['5 hours', '3 minutes'], {type: 'unit'}) Result ","version":"Next","tagName":"h2"},{"title":"formatDisplayName","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#formatdisplayname","content":" browser support This requires Intl.DisplayNames which has limited browser support. Please use our polyfill if you plan to support them. type FormatDisplayNameOptions = { style?: 'narrow' | 'short' | 'long' type?: 'language' | 'region' | 'script' | 'currency' fallback?: 'code' | 'none' } function formatDisplayName( value: string | number | Record<string, unknown>, options?: FormatDisplayNameOptions ): string | undefined Usage examples: Live Editor intl.formatDisplayName('zh-Hans-SG', {type: 'language'}) Result Live Editor // ISO-15924 four letters script code to localized display name intl.formatDisplayName('Deva', {type: 'script'}) Result Live Editor // ISO-4217 currency code to localized display name intl.formatDisplayName('CNY', {type: 'currency'}) Result Live Editor // ISO-3166 two letters region code to localized display name intl.formatDisplayName('UN', {type: 'region'}) Result ","version":"Next","tagName":"h2"},{"title":"formatMessage","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#formatmessage","content":" ","version":"Next","tagName":"h2"},{"title":"Message Syntax","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#message-syntax","content":" String/Message formatting is a paramount feature of React Intl and it builds on ICU Message Formatting by using the ICU Message Syntax. This message syntax allows for simple to complex messages to be defined, translated, and then formatted at runtime. Simple Message: Hello, {name} Complex Message: Hello, {name}, you have {itemCount, plural, =0 {no items} one {# item} other {# items} }. See: The Message Syntax Guide. ","version":"Next","tagName":"h3"},{"title":"Message Descriptor","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#message-descriptor","content":" React Intl has a Message Descriptor concept which is used to define your app's default messages/strings and is passed into formatMessage. The Message Descriptors work very well for providing the data necessary for having the strings/messages translated, and they contain the following properties: id: A unique, stable identifier for the messagedescription: Context for the translator about how it's used in the UIdefaultMessage: The default message (probably in English) type MessageDescriptor = { id: string defaultMessage?: string description?: string | object } Extracting Message Descriptor You can extract inline-declared messages from source files using our CLI. ","version":"Next","tagName":"h3"},{"title":"Message Formatting Fallbacks","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#message-formatting-fallbacks","content":" 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: Lookup and format the translated message at id, passed to <IntlProvider>.Fallback to formatting the defaultMessage.Fallback to source of translated message at id.Fallback to source of defaultMessage.Fallback to the literal message id. Above, "source" refers to using the template as is, without any substitutions made. ","version":"Next","tagName":"h3"},{"title":"Usage","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#usage","content":" type MessageFormatPrimitiveValue = string | number | boolean | null | undefined function formatMessage( descriptor: MessageDescriptor, values?: Record<string, MessageFormatPrimitiveValue> ): string function formatMessage( descriptor: MessageDescriptor, values?: Record< string, MessageFormatPrimitiveValue | React.ReactElement | FormatXMLElementFn > ): string | React.ReactNode[] This function will return a formatted message string. It expects a MessageDescriptor with at least an id property, and accepts a shallow values object which are used to fill placeholders in the message. If a translated message with the id has been passed to the <IntlProvider> via its messages prop it will be formatted, otherwise it will fallback to formatting defaultMessage. See: Message Formatting Fallbacks for more details. Live Editor function () { const messages = defineMessages({ greeting: { id: 'app.greeting', defaultMessage: 'Hello, {name}!', description: 'Greeting to welcome the user to the app', }, }) return intl.formatMessage(messages.greeting, {name: 'Eric'}) } Result with ReactElement Live Editor function () { const messages = defineMessages({ greeting: { id: 'app.greeting', defaultMessage: 'Hello, {name}!', description: 'Greeting to welcome the user to the app', }, }) return intl.formatMessage(messages.greeting, {name: <b>Eric</b>}) } Result with rich text formatting Live Editor function () { const messages = defineMessages({ greeting: { id: 'app.greeting', defaultMessage: 'Hello, <bold>{name}</bold>!', description: 'Greeting to welcome the user to the app', }, }) return intl.formatMessage(messages.greeting, { name: 'Eric', bold: str => <b>{str}</b>, }) } Result The message we defined using defineMessages to support extraction via babel-plugin-formatjs, but it doesn't have to be if you're not using the Babel plugin. simple message Messages can be simple strings without placeholders, and that's the most common type of message. ","version":"Next","tagName":"h3"},{"title":"defineMessages/defineMessage","type":1,"pageTitle":"Imperative API","url":"/docs/react-intl/api#definemessagesdefinemessage","content":" interface MessageDescriptor { id?: string description?: string | object defaultMessage?: string } function defineMessages( messageDescriptors: Record<string, MessageDescriptor> ): Record<string, MessageDescriptor> function defineMessage(messageDescriptor: MessageDescriptor): MessageDescriptor These functions are exported by the react-intl package and are simply a hook for our CLI & babel/TS plugin to use when compiling default messages defined in JavaScript source files. This function simply returns the Message Descriptor map object that's passed-in. import {defineMessages, defineMessage} from 'react-intl' const messages = defineMessages({ greeting: { id: 'app.home.greeting', description: 'Message to greet the user.', defaultMessage: 'Hello, {name}!', }, }) const msg = defineMessage({ id: 'single', defaultMessage: 'single message', description: 'header', }) ","version":"Next","tagName":"h2"},{"title":"Upgrade Guide (v3 -> v4)","type":0,"sectionRef":"#","url":"/docs/react-intl/upgrade-guide-4x","content":"","keywords":"","version":"Next"},{"title":"Breaking API Changes","type":1,"pageTitle":"Upgrade Guide (v3 -> v4)","url":"/docs/react-intl/upgrade-guide-4x#breaking-api-changes","content":" All tags specified must have corresponding values and will throw error if it's missing, e.g: new IntlMessageFormat('a<b>strong</b>').format({ b: (...chunks) => <strong>{chunks}</strong>, }) We don't allow formatting self-closing tags because we already use ICU {placeholder} syntax for that.XML/HTML tags are escaped using apostrophe just like other ICU constructs.Remove dependency on DOMParser and restrictions on void element like <link>. This effectively means you don't need to polyfill DOMParser in Node anymore.FormattedHTMLMessage & intl.formatHTMLMessage have been removed since FormattedMessage now fully supports embedded HTML tag. ","version":"Next","tagName":"h2"},{"title":"Why are we doing those changes?","type":1,"pageTitle":"Upgrade Guide (v3 -> v4)","url":"/docs/react-intl/upgrade-guide-4x#why-are-we-doing-those-changes","content":" FormattedHTMLMessage & intl.formatHTMLMessage were originally created when React was fairly new. These components helped ease migration over from raw HTML to JSX. Given that current popularity of React right now and the fact that FormattedMessage allow rendering embedded HTML tag, this is no longer needed.Initially during the 1st iteration of embedded HTML support, we allow any tag that doesn’t have a corresponding formatter to be rendered as raw HTML. We’ve received feedbacks internally that allowing embedded HTML tag to be rendered as-is without sanitization is a XSS security risk. Therefore, in order to allow raw HTML tag you have to opt-in by escaping them using apostrophe. We will update our linter to check for this as well. ","version":"Next","tagName":"h2"},{"title":"Migrating off embedded HTML in messages","type":1,"pageTitle":"Upgrade Guide (v3 -> v4)","url":"/docs/react-intl/upgrade-guide-4x#migrating-off-embedded-html-in-messages","content":" In order to restore the old behavior of FormattedHTMLMessage & intl.formatHTMLMessage, we suggest you use the rich text format feature as below: Old way: intl.formatHTMLMessage('This is a <a href="foo">link</a>') New way: intl.formatMessage('This is a <a>link</a>', { a: (...chunks) => sanitizeHTML(`<a href="foo">${chunks.join('')}</a>`), }) This forces developers to always sanitize their rendered HTML & chunks, thus minimizing XSS. ","version":"Next","tagName":"h2"},{"title":"babel-plugin-formatjs","type":0,"sectionRef":"#","url":"/docs/tooling/babel-plugin","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"babel-plugin-formatjs","url":"/docs/tooling/babel-plugin#installation","content":" npmyarn npm i babel-plugin-formatjs ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"babel-plugin-formatjs","url":"/docs/tooling/babel-plugin#usage","content":" This Babel plugin only visits ES6 modules which import React Intl. The default message descriptors for the app's default language will be processed from: defineMessages(), defineMessage(), intl.formatMessage and <FormattedMessage>; all of which are named exports of the React Intl package. ","version":"Next","tagName":"h2"},{"title":"Via babel.config.json (Recommended)","type":1,"pageTitle":"babel-plugin-formatjs","url":"/docs/tooling/babel-plugin#via-babelconfigjson-recommended","content":" babel.config.json { "plugins": [ [ "formatjs", { "idInterpolationPattern": "[sha512:contenthash:base64:6]", "ast": true } ] ] } ","version":"Next","tagName":"h3"},{"title":"Via Node API","type":1,"pageTitle":"babel-plugin-formatjs","url":"/docs/tooling/babel-plugin#via-node-api","content":" The extract message descriptors are available via the metadata property on the object returned from Babel's transform() API: require('@babel/core').transform('code', { plugins: ['formatjs'], }) // => { code, map, ast, metadata['formatjs'].messages, metadata['formatjs'].meta }; ","version":"Next","tagName":"h3"},{"title":"Options","type":1,"pageTitle":"babel-plugin-formatjs","url":"/docs/tooling/babel-plugin#options","content":" ","version":"Next","tagName":"h2"},{"title":"overrideIdFn","type":1,"pageTitle":"babel-plugin-formatjs","url":"/docs/tooling/babel-plugin#overrideidfn","content":" A function with the signature (id: string, defaultMessage: string, description: string|object) => string which allows you to override the ID both in the extracted javascript and messages. ","version":"Next","tagName":"h3"},{"title":"idInterpolationPattern","type":1,"pageTitle":"babel-plugin-formatjs","url":"/docs/tooling/babel-plugin#idinterpolationpattern","content":" If certain message descriptors don't have id, this pattern will be used to automaticallygenerate IDs for them. Default to [sha512:contenthash:base64:6]. See nodejs crypto createHash for hash algorithms & nodejs buffer docs for digest encodings. ","version":"Next","tagName":"h3"},{"title":"removeDefaultMessage","type":1,"pageTitle":"babel-plugin-formatjs","url":"/docs/tooling/babel-plugin#removedefaultmessage","content":" Remove defaultMessage field in generated js after extraction. ","version":"Next","tagName":"h3"},{"title":"additionalComponentNames","type":1,"pageTitle":"babel-plugin-formatjs","url":"/docs/tooling/babel-plugin#additionalcomponentnames","content":" Additional component names to extract messages from, e.g: ['FormattedFooBarMessage']. NOTE: By default we check for the fact that FormattedMessage are imported from moduleSourceName to make sure variable alias works. This option does not do that so it's less safe. ","version":"Next","tagName":"h3"},{"title":"additionalFunctionNames","type":1,"pageTitle":"babel-plugin-formatjs","url":"/docs/tooling/babel-plugin#additionalfunctionnames","content":" Additional function names to extract messages from, e.g: ['$formatMessage']. Use this if you prefer to alias formatMessage to something shorter like $t. ","version":"Next","tagName":"h3"},{"title":"pragma","type":1,"pageTitle":"babel-plugin-formatjs","url":"/docs/tooling/babel-plugin#pragma","content":" parse specific additional custom pragma. This allows you to tag certain file with metadata such as project. For example with this file: // @intl-meta project:my-custom-project import {FormattedMessage} from 'react-intl' ;<FormattedMessage defaultMessage="foo" id="bar" /> and with option {pragma: "@intl-meta"}, we'll parse out // @intl-meta project:my-custom-project into {project: 'my-custom-project'} in the result file. ","version":"Next","tagName":"h3"},{"title":"ast","type":1,"pageTitle":"babel-plugin-formatjs","url":"/docs/tooling/babel-plugin#ast","content":" Pre-parse defaultMessage into AST for faster runtime perf. This flag doesn't do anything when removeDefaultMessage is true. ","version":"Next","tagName":"h3"},{"title":"Components","type":0,"sectionRef":"#","url":"/docs/react-intl/components","content":"","keywords":"","version":"Next"},{"title":"Why Components?","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#why-components","content":" Beyond providing an idiomatic-React way of integrating internationalization into a React app, and the <Formatted*> components have benefits over always using the imperative API directly: Render React elements that seamlessly compose with other React components.Support rich-text string/message formatting in <FormattedMessage>.Implement advanced features like <FormattedRelativeTime>'s updating over time.Provide TypeScript type definitions. ","version":"Next","tagName":"h2"},{"title":"IntlProvider","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#intlprovider","content":" 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 <Formatted*> components. This is the same concept as what Flux frameworks like Redux use to provide access to a store within a component tree. caution All apps using React Intl must use the <IntlProvider> or <RawIntlProvider> component. 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: interface IntlConfig { locale: string formats: CustomFormats messages: Record<string, string> | Record<string, MessageFormatElement[]> defaultLocale: string defaultFormats: CustomFormats timeZone?: string textComponent?: React.ComponentType | keyof React.JSX.IntrinsicElements wrapRichTextChunksInFragment?: boolean defaultRichTextElements?: Record<string, FormatXMLElementFn<React.ReactNode>> onError(err: string): void } ","version":"Next","tagName":"h2"},{"title":"locale, formats, and messages","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#locale-formats-and-messages","content":" The user's current locale and what the app should be rendered in. While defaultLocale and defaultFormats are for fallbacks or during development and represent the app's default. Notice how there is no defaultMessages, that's because each Message Descriptor provides a defaultMessage. ","version":"Next","tagName":"h3"},{"title":"defaultLocale and defaultFormats","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#defaultlocale-and-defaultformats","content":" Default locale & formats for when a message is not translated (missing from messages). defaultLocale should be the locale that defaultMessages are declared in so that a sentence is coherent in a single locale. Without 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. ","version":"Next","tagName":"h3"},{"title":"textComponent","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#textcomponent","content":" Provides a way to configure the default wrapper for React Intl's <Formatted*> components. If not specified, <React.Fragment> is used. Before V3, span was used instead; check the migration guide for more info. ","version":"Next","tagName":"h3"},{"title":"onError","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#onerror","content":" Allows the user to provide a custom error handler. By default, error messages are logged using console.error if NODE_ENV is not set to production. ","version":"Next","tagName":"h3"},{"title":"onWarn","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#onwarn","content":" Allows the user to provide a custom warning handler. By default, warning messages are logged using console.warning if NODE_ENV is not set to production. ","version":"Next","tagName":"h3"},{"title":"wrapRichTextChunksInFragment","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#wraprichtextchunksinfragment","content":" When formatting rich text message, the output we produced is of type Array<string | React.ReactElement>, which will trigger key error. This wraps the output in a single React.Fragment to suppress that. ","version":"Next","tagName":"h3"},{"title":"defaultRichTextElements","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#defaultrichtextelements","content":" A map of tag to rich text formatting function. This is meant to provide a centralized way to format common tags such as <b>, <p>... or enforcing certain Design System in the codebase (e.g standardized <a> or <button>...). See https://github.com/formatjs/formatjs/issues/1752 for more context. These configuration props are combined with the <IntlProvider>'s component-specific props: Props: props: IntlConfig & { children: ReactNode, } Finally, child elements must be supplied to <IntlProvider>. Example: const App = ({importantDate}) => ( <div> <FormattedDate value={importantDate} year="numeric" month="long" day="numeric" weekday="long" /> </div> ) ReactDOM.render( <IntlProvider locale={navigator.language}> <App importantDate={new Date(1459913574887)} /> </IntlProvider>, document.getElementById('container') ) Assuming navigator.language is "fr": <div>mardi 5 avril 2016</div> ","version":"Next","tagName":"h3"},{"title":"RawIntlProvider","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#rawintlprovider","content":" This is the underlying React.Context.Provider object that IntlProvider use. It can be used in conjunction with createIntl: 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) // Pass it to IntlProvider <RawIntlProvider value={intl}>{foo}</RawIntlProvider> ","version":"Next","tagName":"h2"},{"title":"FormattedDate","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formatteddate","content":" This component uses the formatDate and Intl.DateTimeFormat APIs and has props that correspond to the DateTimeFormatOptions specified above. Props: props: Intl.DateTimeFormatOptions & { value: any, format: string, children: (formattedDate: string) => ReactElement, } By default <FormattedDate> will render the formatted date into a <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. Example: Live Editor <FormattedDate value={new Date(1459832991883)} /> Result Example with Options: Live Editor <FormattedDate value={new Date(1459832991883)} year="numeric" month="long" day="2-digit" /> Result ","version":"Next","tagName":"h2"},{"title":"FormattedDateParts","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formatteddateparts","content":" browser support This requires Intl.DateTimeFormat.prototype.formatToParts which is not available in IE11. Please use our polyfill if you plan to support IE11. This component provides more customization to FormattedDate by allowing children function to have access to underlying parts of the formatted date. The available parts are listed here Props: props: Intl.DateTimeFormatOptions & { value: any, format: string, children: (parts: Intl.DateTimeFormatPart[]) => ReactElement, } Live Editor <FormattedDateParts value={new Date(1459832991883)} year="numeric" month="long" day="2-digit" > {parts => ( <> <b>{parts[0].value}</b> {parts[1].value} <small>{parts[2].value}</small> </> )} </FormattedDateParts> Result ","version":"Next","tagName":"h2"},{"title":"FormattedTime","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formattedtime","content":" This component uses the formatTime and Intl.DateTimeFormat APIs and has props that correspond to the DateTimeFormatOptions specified above, with the following defaults: { hour: 'numeric', minute: 'numeric', } Props: props: DateTimeFormatOptions & { value: any, format: string, children: (formattedDate: string) => ReactElement, } By default <FormattedTime> will render the formatted time into a 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. Example: Live Editor <FormattedTime value={new Date(1459832991883)} /> Result ","version":"Next","tagName":"h2"},{"title":"FormattedTimeParts","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formattedtimeparts","content":" browser support This requires Intl.DateTimeFormat.prototype.formatToParts which is not available in IE11. Please use our polyfill if you plan to support IE11. This component provides more customization to FormattedTime by allowing children function to have access to underlying parts of the formatted date. The available parts are listed here Props: props: Intl.DateTimeFormatOptions & { value: any, format: string, children: (parts: Intl.DateTimeFormatPart[]) => ReactElement, } Live Editor <FormattedTimeParts value={new Date(1459832991883)}> {parts => ( <> <b>{parts[0].value}</b> {parts[1].value} <small>{parts[2].value}</small> </> )} </FormattedTimeParts> Result ","version":"Next","tagName":"h2"},{"title":"FormattedDateTimeRange","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formatteddatetimerange","content":" browser support This requires stage-3 API Intl.RelativeTimeFormat.prototype.formatRange which has limited browser support. Please use our polyfill if you plan to support them. This component uses the formatDateTimeRange and Intl.DateTimeFormat APIs and has props that correspond to the DateTimeFormatOptions specified above Props: props: DateTimeFormatOptions & { from: number | Date, to: number | Date, children: (formattedDate: string) => ReactElement, } By default <FormattedDateTimeRange> will render the formatted time into a 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. Example: Live Editor <FormattedDateTimeRange from={new Date('2020-1-1')} to={new Date('2020-1-15')} /> Result ","version":"Next","tagName":"h2"},{"title":"FormattedRelativeTime","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formattedrelativetime","content":" browser support This requires Intl.RelativeTimeFormat which has limited browser support. Please use our polyfill if you plan to support them. This component uses the formatRelativeTime API and has props that correspond to the following relative formatting options: type RelativeTimeFormatOptions = { numeric?: 'always' | 'auto' style?: 'long' | 'short' | 'narrow' } Prop Types: props: RelativeTimeFormatOptions & { value: number, unit: Unit, format: string, updateIntervalInSeconds: number, children: (formattedDate: string) => ReactElement, } By default <FormattedRelativeTime> will render the formatted relative time into a 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. Example: Live Editor <FormattedRelativeTime value={0} numeric="auto" updateIntervalInSeconds={1} /> Result maximum interval You can adjust the maximum interval that the component will re-render by setting the updateIntervalInSeconds. A falsy value will turn off auto-updating. The updating is smart and will schedule the next update for the next interesting moment. An interesting moment is defined as the next non-fractional value for that unit. For example: Live Editor <FormattedRelativeTime value={-50} updateIntervalInSeconds={1} /> Result This will initially renders 59 seconds ago, after 1 second, will render 1 minute ago, and will not re-render until a full minute goes by, it'll render 2 minutes ago. It will not try to render 1.2 minutes ago. limitation updateIntervalInSeconds cannot be enabled for unit longer than hour (so not for day, week, quarter, year). This is primarily because it doesn't make sense to schedule a timeout in days, and the number of ms in a day is larger than the max timeout that setTimeout accepts. ","version":"Next","tagName":"h2"},{"title":"FormattedNumber","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formattednumber","content":" This component uses the formatNumber and Intl.NumberFormat APIs and has props that correspond to Intl.NumberFormatOptions. Props: props: NumberFormatOptions & { value: number, format: string, children: (formattedNumber: string) => ReactElement, } By default <FormattedNumber> will render the formatted number into a 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. Example: Live Editor <FormattedNumber value={1000} /> Result Example Formatting Currency Values Live Editor <FormattedNumber value={1000} style="currency" currency="USD" /> Result Formatting Number using unit Currently this is part of ES2020 NumberFormat. We've provided a polyfill here and react-intl types allow users to pass in a sanctioned unit. For example: Live Editor <FormattedNumber value={1000} style="unit" unit="kilobyte" unitDisplay="narrow" /> Result Live Editor <FormattedNumber value={1000} unit="fahrenheit" unitDisplay="long" style="unit" /> Result ","version":"Next","tagName":"h2"},{"title":"FormattedNumberParts","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formattednumberparts","content":" browser support This requires Intl.NumberFormat.prototype.formatToParts which is not available in IE11. Please use our polyfill if you plan to support IE11. This component provides more customization to FormattedNumber by allowing children function to have access to underlying parts of the formatted number. The available parts are listed here. Props: props: NumberFormatOptions & { value: number, format: string, children: (parts: Intl.NumberFormatPart[]) => ReactElement, } Example: Live Editor <FormattedNumberParts value={1000}> {parts => ( <> <b>{parts[0].value}</b> {parts[1].value} <small>{parts[2].value}</small> </> )} </FormattedNumberParts> Result ","version":"Next","tagName":"h2"},{"title":"FormattedPlural","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formattedplural","content":" This component uses the formatPlural API and Intl.PluralRules has props that correspond to Intl.PluralRulesOptions. Props: props: PluralFormatOptions & { value: any, other: ReactElement, zero: ReactElement, one: ReactElement, two: ReactElement, few: ReactElement, many: ReactElement, children: (formattedPlural: ReactElement) => ReactElement, } By default <FormattedPlural> will select a plural category (zero, one, two, few, many, or other) and render the corresponding React element into a 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. Example: Live Editor <FormattedPlural value={10} one="message" other="messages" /> Result ","version":"Next","tagName":"h2"},{"title":"FormattedList","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formattedlist","content":" browser support This requires Intl.ListFormat which has limited browser support. Please use our polyfill if you plan to support them. This component uses formatList API and Intl.ListFormat. Its props corresponds to Intl.ListFormatOptions. Props: props: ListFormatOptions & { children: (chunksOrString: string | React.ReactElement[]) => ReactElement, } Example: When the locale is en: Live Editor <FormattedList type="conjunction" value={['Me', 'myself', 'I']} /> Result Live Editor <FormattedList type="conjunction" value={['Me', <b>myself</b>, 'I']} /> Result ","version":"Next","tagName":"h2"},{"title":"FormattedListParts","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formattedlistparts","content":" browser support This requires Intl.ListFormat which has limited browser support. Please use our polyfill if you plan to support them. This component uses formatListToParts API and Intl.ListFormat. Its props corresponds to Intl.ListFormatOptions. Props: props: ListFormatOptions & { children: (chunks: Array<React.ReactElement | string>) => ReactElement, } Example: When the locale is en: Live Editor <FormattedListParts type="conjunction" value={['Me', 'myself', 'I']}> {parts => ( <> <b>{parts[0].value}</b> {parts[1].value} <small>{parts[2].value}</small> {parts[3].value} <small>{parts[4].value}</small> </> )} </FormattedListParts> Result ","version":"Next","tagName":"h2"},{"title":"FormattedDisplayName","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formatteddisplayname","content":" browser support This requires Intl.DisplayNames which has limited browser support. Please use our polyfill if you plan to support them. This component uses formatDisplayName and Intl.DisplayNameshas props that correspond to DisplayNameOptions. You might need a polyfill. Props: props: FormatDisplayNameOptions & { value: string | number | Record<string, unknown>, } Example: When the locale is en: Live Editor <FormattedDisplayName type="language" value="zh-Hans-SG" /> Result Live Editor <FormattedDisplayName type="currency" value="JPY" /> Result ","version":"Next","tagName":"h2"},{"title":"FormattedMessage","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#formattedmessage","content":" This component uses the formatMessage API and has props that correspond to a Message Descriptor. Props: props: MessageDescriptor & { values: object, tagName: string, children: (chunks: ReactElement) => ReactElement, } ","version":"Next","tagName":"h2"},{"title":"Message Syntax","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#message-syntax","content":" String/Message formatting is a paramount feature of React Intl and it builds on ICU Message Formatting by using the ICU Message Syntax. This message syntax allows for simple to complex messages to be defined, translated, and then formatted at runtime. Simple Message: Hello, {name} Complex Message: Hello, {name}, you have {itemCount, plural, =0 {no items} one {# item} other {# items} }. See: The Message Syntax Guide. ","version":"Next","tagName":"h3"},{"title":"Message Descriptor","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#message-descriptor","content":" React Intl has a Message Descriptor concept which is used to define your app's default messages/strings. <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: id: A unique, stable identifier for the messagedescription: Context for the translator about how it's used in the UIdefaultMessage: The default message (probably in English) type MessageDescriptor = { id?: string defaultMessage?: string description?: string } compile message descriptors The babel-plugin-formatjs and @formatjs/ts-transformer packages can be used to compile Message Descriptors defined in JavaScript source files into AST for performance. ","version":"Next","tagName":"h3"},{"title":"Message Formatting Fallbacks","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#message-formatting-fallbacks","content":" 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: Lookup and format the translated message at id, passed to <IntlProvider>.Fallback to formatting the defaultMessage.Fallback to translated message at id's source.Fallback to defaultMessage source.Fallback to the literal message id. ","version":"Next","tagName":"h3"},{"title":"Usage","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#usage","content":" By default <FormattedMessage> will render the formatted string into a <React.Fragment>. If you need to customize rendering, you can either wrap it with another React element (recommended), specify a different tagName (e.g., 'div'), or pass a function as the child. Example: Live Editor <FormattedMessage id="app.greeting" description="Greeting to welcome the user to the app" defaultMessage="Hello, {name}!" values={{ name: 'Eric', }} /> Result Example: function as the child Live Editor <FormattedMessage id="title">{txt => <h1>{txt}</h1>}</FormattedMessage> Result simple message Messages can be simple strings without placeholders, and that's the most common type of message. This case is highly-optimized, but still has the benefits of the fallback procedure. ","version":"Next","tagName":"h3"},{"title":"Rich Text Formatting","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#rich-text-formatting","content":" <FormattedMessage> also supports rich-text formatting by specifying a XML tag in the message & resolving that tag in the values prop. Here's an example: Live Editor <FormattedMessage id="app.greeting" description="Greeting to welcome the user to the app" defaultMessage="Hello, <b>Eric</b> {icon}" values={{ b: chunks => <b>{chunks}</b>, icon: <svg />, }} /> Result 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: Live Editor <FormattedMessage id="foo" defaultMessage="To buy a shoe, <a>visit our website</a> and <cta>buy a shoe</cta>" values={{ a: chunks => ( <a class="external_link" target="_blank" href="https://www.example.com/shoe" > {chunks} </a> ), cta: chunks => <strong class="important">{chunks}</strong>, }} /> Result ","version":"Next","tagName":"h3"},{"title":"Function as the child","type":1,"pageTitle":"Components","url":"/docs/react-intl/components#function-as-the-child","content":" Since rich text formatting allows embedding ReactElement, in function as the child scenario, the function will receive the formatted message chunks as a single parameter. Live Editor <FormattedMessage id="foo" defaultMessage="To buy a shoe, <a>visit our website</a> and <cta>buy a shoe</cta>" values={{ a: chunks => ( <a class="external_link" target="_blank" href="https://www.example.com/shoe" > {chunks} </a> ), cta: chunks => <strong class="important">{chunks}</strong>, }} > {chunks => <h2>{chunks}</h2>} </FormattedMessage> Result All the rich text gets translated together which yields higher quality output. This brings feature-parity with other translation libs as well, such as fluent by Mozilla (using overlays concept). Extending this also allows users to potentially utilizing other rich text format, like Markdown. ","version":"Next","tagName":"h3"},{"title":"Upgrade Guide (v4 -> v5)","type":0,"sectionRef":"#","url":"/docs/react-intl/upgrade-guide-5x","content":"","keywords":"","version":"Next"},{"title":"Breaking API Changes","type":1,"pageTitle":"Upgrade Guide (v4 -> v5)","url":"/docs/react-intl/upgrade-guide-5x#breaking-api-changes","content":" Rich text formatting callback function is no longer variadic. Before: new IntlMessageFormat('a<b>strong</b>').format({ b: (...chunks) => <strong>{chunks}</strong>, }) After: new IntlMessageFormat('a<b>strong</b>').format({ b: chunks => <strong>{chunks}</strong>, }) FormattedMessage render prop is no longer variadic. Before: <FormattedMessage defaultMessage="a<b>strong</b>"> {(...chunks) => <b>{chunks}</b>} </FormattedMessage> After: <FormattedMessage defaultMessage="a<b>strong</b>"> {chunks => <b>{chunks}</b>} </FormattedMessage> Using FormattedMessage without a intl context will fail fast. ","version":"Next","tagName":"h2"},{"title":"Why are we doing those changes?","type":1,"pageTitle":"Upgrade Guide (v4 -> v5)","url":"/docs/react-intl/upgrade-guide-5x#why-are-we-doing-those-changes","content":" ","version":"Next","tagName":"h2"},{"title":"Rich text formatting callback function is no longer variadic","type":1,"pageTitle":"Upgrade Guide (v4 -> v5)","url":"/docs/react-intl/upgrade-guide-5x#rich-text-formatting-callback-function-is-no-longer-variadic","content":" We received feedback from the community that variadic callback function isn't really ergonomic.There's also an issue where React chunks do not come with keys, thus causing warning in React during development.The chunks by themselves are not enough to render duplicate tags, such as <a>link</a> and another <a>link</a> where you want to render 2 different hrefs for the <a> tag. In this case a: chunks => <a>{chunks}</a> isn't enough especially when the contents are the same. In the future we can set another argument that might contain metadata to distinguish between the 2 elements. ","version":"Next","tagName":"h3"},{"title":"FormattedMessage render prop is no longer variadic","type":1,"pageTitle":"Upgrade Guide (v4 -> v5)","url":"/docs/react-intl/upgrade-guide-5x#formattedmessage-render-prop-is-no-longer-variadic","content":" Same reasons as above. ","version":"Next","tagName":"h3"},{"title":"Using FormattedMessage without a intl context will fail fast","type":1,"pageTitle":"Upgrade Guide (v4 -> v5)","url":"/docs/react-intl/upgrade-guide-5x#using-formattedmessage-without-a-intl-context-will-fail-fast","content":" This also comes from Dropbox internal developer feedback. FormattedMessage has a default English renderer that masks Provider setup issues which causes them to not be handled during testing phase. ","version":"Next","tagName":"h3"},{"title":"swc-plugin","type":0,"sectionRef":"#","url":"/docs/tooling/swc-plugin","content":"swc-plugin This has been migrated over to the swc repo itself. You can find the plugin here.","keywords":"","version":"Next"},{"title":"ts-transformer","type":0,"sectionRef":"#","url":"/docs/tooling/ts-transformer","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#installation","content":" npmyarn npm i @formatjs/ts-transformer ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#usage","content":" The default message descriptors for the app's default language will be processed from: defineMessages(), defineMessage(), intl.formatMessage and <FormattedMessage>; all of which are named exports of the React Intl package. ","version":"Next","tagName":"h2"},{"title":"Via ts-loader","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#via-ts-loader","content":" import {transform} from '@formatjs/ts-transformer' module.exports = { ...otherConfigs, module: { rules: [ { test: /\\.tsx?$/, use: [ { loader: 'ts-loader', options: { getCustomTransformers() { return { before: [ transform({ overrideIdFn: '[sha512:contenthash:base64:6]', }), ], } }, }, }, ], }, ], }, } ","version":"Next","tagName":"h3"},{"title":"Via ts-jest in jest.config.js","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#via-ts-jest-in-jestconfigjs","content":" caution This requires [email protected] or later // jest.config.js module.exports = { // [...] globals: { 'ts-jest': { astTransformers: { before: [ { path: '@formatjs/ts-transformer/ts-jest-integration', options: { // options overrideIdFn: '[sha512:contenthash:base64:6]', ast: true, }, }, ], }, }, }, } ","version":"Next","tagName":"h3"},{"title":"Via ts-patch","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#via-ts-patch","content":" { "compilerOptions": { "plugins": [ { "transform": "@formatjs/ts-transformer", "import": "transform", "type": "config", "overrideIdFn": "[sha512:contenthash:base64:6]", "ast": true } ] } } ","version":"Next","tagName":"h3"},{"title":"Via rollup-plugin-typescript2","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#via-rollup-plugin-typescript2","content":" // rollup.config.js import typescript from 'rollup-plugin-typescript2' import {transform} from '@formatjs/ts-transformer' export default { input: './main.ts', plugins: [ typescript({ transformers: () => ({ before: [ transform({ overrideIdFn: '[sha512:contenthash:base64:6]', ast: true, }), ], }), }), ], } ","version":"Next","tagName":"h3"},{"title":"Options","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#options","content":" ","version":"Next","tagName":"h2"},{"title":"overrideIdFn","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#overrideidfn","content":" A function with the signature (id: string, defaultMessage: string, description: string|object) => string which allows you to override the ID both in the extracted javascript and messages. Alternatively, overrideIdFn can be a template string, which is used only if the message ID is empty. ","version":"Next","tagName":"h3"},{"title":"removeDefaultMessage","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#removedefaultmessage","content":" Remove defaultMessage field in generated js after extraction. ","version":"Next","tagName":"h3"},{"title":"extractSourceLocation","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#extractsourcelocation","content":" Whether the metadata about the location of the message in the source file should be extracted. If true, then file, start, and end fields will exist for each extracted message descriptors. Defaults to false. ","version":"Next","tagName":"h3"},{"title":"additionalComponentNames","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#additionalcomponentnames","content":" Additional component names to extract messages from, e.g: ['FormattedFooBarMessage']. NOTE: By default we check for the fact that FormattedMessage are imported from moduleSourceName to make sure variable alias works. This option does not do that so it's less safe. ","version":"Next","tagName":"h3"},{"title":"additionalFunctionNames","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#additionalfunctionnames","content":" Additional function names to extract messages from, e.g: ['$formatMessage']. Use this if you prefer to alias formatMessage to something shorter like $t. ","version":"Next","tagName":"h3"},{"title":"pragma","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#pragma","content":" parse specific additional custom pragma. This allows you to tag certain file with metadata such as project. For example with this file: // @intl-meta project:my-custom-project import {FormattedMessage} from 'react-intl' ;<FormattedMessage defaultMessage="foo" id="bar" /> and with option {pragma: "@intl-meta"}, we'll parse out // @intl-meta project:my-custom-project into {project: 'my-custom-project'} in the result file. ","version":"Next","tagName":"h3"},{"title":"ast","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#ast","content":" Pre-parse defaultMessage into AST for faster runtime perf. This flag doesn't do anything when removeDefaultMessage is true. ","version":"Next","tagName":"h3"},{"title":"onMsgExtracted(filePath: string, msgs: MessageDescriptor[])","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#onmsgextractedfilepath-string-msgs-messagedescriptor","content":" Callback that gets triggered whenever a message is encountered. ","version":"Next","tagName":"h3"},{"title":"onMetaExtracted(filePath: string, meta: Record<string, string>)","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#onmetaextractedfilepath-string-meta-recordstring-string","content":" Callback that gets triggered whenever a pragme meta is encountered. ","version":"Next","tagName":"h3"},{"title":"preserveWhitespace","type":1,"pageTitle":"ts-transformer","url":"/docs/tooling/ts-transformer#preservewhitespace","content":" Whether to preserve whitespace and newlines. Take a look at compile.ts for example in integration. ","version":"Next","tagName":"h3"},{"title":"Vue Plugin for formatjs","type":0,"sectionRef":"#","url":"/docs/vue-intl","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"Vue Plugin for formatjs","url":"/docs/vue-intl#installation","content":" npmyarn npm i -S vue-intl ","version":"Next","tagName":"h2"},{"title":"Usage","type":1,"pageTitle":"Vue Plugin for formatjs","url":"/docs/vue-intl#usage","content":" Initialize VueIntl plugin with the same IntlConfig documented in @formatjs/intl. import {createIntl} from 'vue-intl' const app = createApp(App) app.use( createIntl({ locale: 'en', defaultLocale: 'en', messages: { foo: 'bar', }, }) ) From there you can use our APIs in 2 ways: ","version":"Next","tagName":"h2"},{"title":"inject","type":1,"pageTitle":"Vue Plugin for formatjs","url":"/docs/vue-intl#inject","content":" By specifying inject: {intl: intlKey}, you can use the full IntlFormatters API documented in @formatjs/intl. Note: intlKey needs to be imported from vue-intl. ","version":"Next","tagName":"h3"},{"title":"Composition API","type":1,"pageTitle":"Vue Plugin for formatjs","url":"/docs/vue-intl#composition-api","content":" We also support Vue's Composition API with provideIntl & useIntl. import {createIntl} from '@formatjs/intl' import {provideIntl, useIntl} from 'vue-intl' const Ancestor = { setup() { provideIntl( createIntl({ locale: 'en', defaultLocale: 'en', messages: { foo: 'Composed', }, }) ) }, render() { return h(Descendant) }, } const Descendant = { setup() { const intl = useIntl() return () => h( 'p', {}, intl.formatMessage({ id: 'foo', defaultMessage: 'Hello', }) ) }, } ","version":"Next","tagName":"h3"},{"title":"Methods","type":1,"pageTitle":"Vue Plugin for formatjs","url":"/docs/vue-intl#methods","content":" You can also use our formatters in Vue template by prepending $ like below: <template> <p>{{ $formatNumber(3, {style: 'currency', currency: 'USD'}) }}</p> </template> We currently support: $formatMessage$formatDate$formatTime$formatRelativeTime$formatTimeRange$formatDisplayName$formatList See @formatjs/intl for the full list of API signatures. ","version":"Next","tagName":"h3"},{"title":"Tooling","type":1,"pageTitle":"Vue Plugin for formatjs","url":"/docs/vue-intl#tooling","content":" formatjs toolchain fully supports vue: eslint-plugin-formatjs: This fully supports .vue and JS/TS.@formatjs/cli: We now support extracting messages from .vue SFC files.babel-plugin-formatjs: Compile messages during bundling for babel.@formatjs/ts-transformer: Compile messages during bundling for TypeScript. ","version":"Next","tagName":"h2"},{"title":"Caveats","type":1,"pageTitle":"Vue Plugin for formatjs","url":"/docs/vue-intl#caveats","content":" ","version":"Next","tagName":"h2"},{"title":"Using ICU in Vue SFC","type":1,"pageTitle":"Vue Plugin for formatjs","url":"/docs/vue-intl#using-icu-in-vue-sfc","content":" Since }} & {{ are special tokens in .vue <template>, this can cause potential conflict with ICU MessageFormat syntax, e.g: <template> <p> {{ $formatMessage({ defaultMessage: '{count, selectordinal, offset:1 one {#} other {# more}}', }) }} </p> </template> Notice the {# more}} where it ends with }}. This will cause parsing issue in your vue template. In order to work around this issue, we recommend using space to turn }} into } }. <template> <p> {{ $formatMessage({ defaultMessage: '{count, selectordinal, offset:1 one {#} other {# more} }', }) }} </p> </template> ","version":"Next","tagName":"h3"},{"title":"CLI","type":0,"sectionRef":"#","url":"/docs/tooling/cli","content":"","keywords":"","version":"Next"},{"title":"Installation","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#installation","content":" npmyarn npm i -D @formatjs/cli Add the following command to your package.json scripts: { "scripts": { "extract": "formatjs extract", "compile": "formatjs compile" } } We've built this CLI that helps you extract messages from a list of files. It uses @formatjs/ts-transformer under the hood and should be able to extract messages if you're declaring using 1 of the mechanisms below: import {defineMessages, defineMessage} from 'react-intl' defineMessages({ foo: { id: 'foo', defaultMessage: 'foo', description: 'bar', }, }) defineMessage({ id: 'single', defaultMessage: 'single message', description: 'header', }) import {FormattedMessage} from 'react-intl' ;<FormattedMessage id="foo" defaultMessage="foo" description="bar" /> function Comp(props) { const {intl} = props return intl.formatMessage({ // The whole `intl.formatMessage` is required so we can extract id: 'foo', defaultMessage: 'foo', description: 'bar', }) } ","version":"Next","tagName":"h2"},{"title":"Extraction","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#extraction","content":" npmyarn npm run extract -- --help # Usage: formatjs extract [options] [files...] # Extract string messages from React components that use react-intl. # The input language is expected to be TypeScript or ES2017 with JSX. For example: npm run extract -- "src/**/*.{ts,tsx,vue}" --out-file lang.json caution You should always quote (" or ') your glob pattern (like "src/**/*") to avoid auto shell expansion of those glob, which varies depending on your shell (zsh vs fish vs bash). ","version":"Next","tagName":"h2"},{"title":"--format [path]","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--format-path","content":" Path to a formatter file that controls the shape of JSON file from --out-file. The formatter file must export a function called format with the signature. type FormatFn = <T = Record<string, MessageDescriptor>>( msgs: Record<string, MessageDescriptor> ) => T This is especially useful to convert from our extracted format to a TMS-specific format. See our builtin formatters for examples. ","version":"Next","tagName":"h3"},{"title":"--out-file [path]","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--out-file-path","content":" The target file path where the plugin will output an aggregated .json file of allthe translations from the files supplied. This flag will ignore --messages-dir ","version":"Next","tagName":"h3"},{"title":"--id-interpolation-pattern [pattern]","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--id-interpolation-pattern-pattern","content":" If certain message descriptors don't have id, this pattern will be used to automatically generate IDs for them. Default to [sha512:contenthash:base64:6]. See nodejs crypto createHash for hash algorithms & nodejs buffer docs for digest encodings. ","version":"Next","tagName":"h3"},{"title":"--extract-source-location","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--extract-source-location","content":" Whether the metadata about the location of the message in the source file should be extracted. If true, then file, start, and end fields will exist for each extracted message descriptors. (default: false) ","version":"Next","tagName":"h3"},{"title":"--additional-component-names [comma-separated-names]","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--additional-component-names-comma-separated-names","content":" Additional component names to extract messages from, e.g: ['FormattedFooBarMessage']. NOTE: By default we check for the fact that FormattedMessage is imported from moduleSourceName to make sure variable alias works. This option does not do that so it's less safe. ","version":"Next","tagName":"h3"},{"title":"--additional-function-names [comma-separated-names]","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--additional-function-names-comma-separated-names","content":" Additional function names to extract messages from, e.g: ['$t']. ","version":"Next","tagName":"h3"},{"title":"--ignore [files]","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--ignore-files","content":" List of glob paths to not extract translations from. ","version":"Next","tagName":"h3"},{"title":"--throws","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--throws","content":" Whether to throw an exception when we fail to process any file in the batch. ","version":"Next","tagName":"h3"},{"title":"--pragma [pragma]","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--pragma-pragma","content":" Parse specific additional custom pragma. This allows you to tag certain file with metadata such as project. For example with this file: // @intl-meta project:my-custom-project import {FormattedMessage} from 'react-intl' ;<FormattedMessage defaultMessage="foo" id="bar" /> and with option {pragma: "intl-meta"}, we'll parse out // @intl-meta project:my-custom-project into {project: 'my-custom-project'} in the result file. ","version":"Next","tagName":"h3"},{"title":"--flatten","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--flatten","content":" Whether to hoist selectors & flatten sentences as much as possible. E.g: I have {count, plural, one{a dog} other{many dogs}} becomes {count, plural, one{I have a dog} other{I have many dogs}} The goal is to provide as many full sentences as possible since fragmented sentences are not translator-friendly. ","version":"Next","tagName":"h3"},{"title":"Verification","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#verification","content":" Verify translation files to make sure keys are translated and messages are structurally compatible with source locale. npmyarn npm run formatjs verify [options] <translationFiles> ","version":"Next","tagName":"h2"},{"title":"--source-locale <sourceLocale>","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--source-locale-sourcelocale","content":" The source locale of the translation files. There must be a file named <sourceLocale>.json in the list of translation files. This is used as source to verify other translations against. ","version":"Next","tagName":"h3"},{"title":"--missing-keys","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--missing-keys","content":" Whether to check for missing keys in target locale compared to source locale. This basically guarantees that no messages are untranslated. ","version":"Next","tagName":"h3"},{"title":"--structural-equality","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--structural-equality","content":" Whether to check for structural equality of messages between source and target locale. This makes sure translations are formattable and are not missing any tokens. ","version":"Next","tagName":"h3"},{"title":"Compilation","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#compilation","content":" Compile extracted files from formatjs extract to a react-intl consumable JSON file. This also does ICU message verification. See Message Distribution for more details. npmyarn npm run compile -- --help ","version":"Next","tagName":"h2"},{"title":"--format [path]","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--format-path-1","content":" Path to a formatter file that converts <translation_file> to Record<string, string> so we can compile. The file must export a function named compile with the signature: type CompileFn = <T = Record<string, MessageDescriptor>>( msgs: T ) => Record<string, string> This is especially useful to convert from a TMS-specific format back to react-intl format. See our builtin formatters for examples. ","version":"Next","tagName":"h3"},{"title":"--out-file <output>","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--out-file-output","content":" The target file that contains compiled messages. ","version":"Next","tagName":"h3"},{"title":"--preserve-whitespace","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--preserve-whitespace","content":" Whether to preserve whitespace and newlines in output. We typically remove consecutive whitespaces and newlines since those often gets abused for styling purposes. ","version":"Next","tagName":"h3"},{"title":"--ast","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--ast","content":" Whether to compile message into AST instead of just string. See Advanced Usage ","version":"Next","tagName":"h3"},{"title":"--pseudo-locale <pseudoLocale>","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--pseudo-locale-pseudolocale","content":" Whether we should compile messages into pseudo locales instead. Available pseudo-locales: Given the English message my name is {name} Locale\tMessagexx-LS\tmy name is {name}SSSSSSSSSSSSSSSSSSSSSSSSS xx-AC\tMY NAME IS {name} xx-HA\t[javascript]my name is {name} en-XA\t[ḿẏ ƞȧȧḿḗḗ īş {name}] en-XB\tɯʎ uɐɯǝ ıs {name} caution Requires --ast ","version":"Next","tagName":"h3"},{"title":"Extraction and compilation with a single script","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#extraction-and-compilation-with-a-single-script","content":" In some environments you may want to simply extract your messages to a file ready for use with react-intl without using an intermediary extracted message file format. This could be useful for quickly and easily creating the file for the original language that uses the default messages. This could also be useful if you use a Translation Management System (TMS) that is best suited to working with the compiled files. Keep in mind that the compiled file does not contain message descriptions so it is harder to work with for translators. Ideally you want to find or write a custom formatter you can use to extract messages into a file format that works with your TMS. In order to achieve extraction and compilation in a single script, you can simply set up a script for that in package.json like in this example: "scripts": { "extract": "formatjs extract", "compile": "formatjs compile", "extract-compile": "formatjs extract 'src/**/*.ts*' --out-file temp.json --flatten --id-interpolation-pattern '[sha512:contenthash:base64:6]' && formatjs compile 'temp.json' --out-file lang/en.json && rm temp.json" } ","version":"Next","tagName":"h2"},{"title":"Breakdown of the script","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#breakdown-of-the-script","content":" The extract-compile example script consists of three operations performed one after the other. formatjs extract 'src/**/*.ts*' --out-file temp.json --flatten --id-interpolation-pattern '[sha512:contenthash:base64:6]' The first script extracts messages from all typescript files that are located in subfolders of src. You may need to ignore certain files that could trigger errors or warnings in the script, such as --ignore myFolder/myFile.ts formatjs compile 'temp.json' --out-file lang/en.json The second script compiles the messages from temp.json into the file lang/en.json. This file is ready to be consumed by react-intl. rm temp.json The last script deletes the temp.json extracted file. Feel free remove this from the script if you wish to keep this file around. ","version":"Next","tagName":"h3"},{"title":"The resulting files","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#the-resulting-files","content":" Here you can see the difference between the extracted (using the default formatter) and the compiled file formats. In the script above, temp.json is the extracted file and en.json is the compiled file. Extracted messagesCompiled messages { "hak27d": { "defaultMessage": "Control Panel", "description": "title of control panel section" }, "haqsd": { "defaultMessage": "Delete user {name}", "description": "delete button" }, "19hjs": { "defaultMessage": "New Password", "description": "placeholder text" }, "explicit-id": { "defaultMessage": "Confirm Password", "description": "placeholder text" } } ","version":"Next","tagName":"h3"},{"title":"Folder Compilation","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#folder-compilation","content":" Batch compile a folder with extracted files from formatjs extract to a folder containing react-intl consumable JSON files. This also does ICU message verification. See Message Distribution for more details. npmyarn npm run formatjs compile-folder [options] <folder> <outFolder> Folder structure should be in the form of <folder>/<locale>.json and the output would be <outFolder>/<locale>.json. ","version":"Next","tagName":"h2"},{"title":"--format [path]","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--format-path-2","content":" Path to a formatter file that converts <translation_file> to Record<string, string> so we can compile. The file must export a function named compile with the signature: type CompileFn = <T = Record<string, MessageDescriptor>>( msgs: T ) => Record<string, string> This is especially useful to convert from a TMS-specific format back to react-intl format ","version":"Next","tagName":"h3"},{"title":"--ast","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--ast-1","content":" Whether to compile message into AST instead of just string. See Advanced Usage ","version":"Next","tagName":"h3"},{"title":"--skip-errors","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#--skip-errors","content":" Whether to continue compiling messages after encountering an error parsing one of them. Any keys with errors will not be included in the output file. ","version":"Next","tagName":"h3"},{"title":"Builtin Formatters","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#builtin-formatters","content":" We provide the following built-in formatters to integrate with 3rd party TMSes: TMS\t--formatBabelEdit\tsimple Crowdin Chrome JSON\tcrowdin Lingohub\tsimple Localize's Simple JSON\tsimple Localizely\tsimple locize\tsimple Lokalise Structured JSON\tlokalise Phrase\tsimple POEditor Key-Value JSON\tsimple SimpleLocalize\tsimple Smartling ICU JSON\tsmartling Transifex's Structured JSON\ttransifex caution The formats of extract & compile have to be the same, which means if you extract --format smartling, you have to compile --format smartling as well & vice versa. ","version":"Next","tagName":"h2"},{"title":"Custom Formatters","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#custom-formatters","content":" You can provide your own formatter by using our interfaces: import {FormatFn, CompileFn, Comparator} from '@formatjs/cli' interface VendorJson {} // [Optional] Format @formatjs/cli structure to vendor's structure export const format: FormatFn<VendorJson> = () => {} // [Optional] Format vendor's structure to @formatjs/cli structure export const compile: CompileFn<VendorJson> = () => {} // [Optional] Sort the messages in a specific order during serialization export const compareMessages: Comparator = () => {} Take a look at our builtin formatter code for some examples. ","version":"Next","tagName":"h2"},{"title":"Node API","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#node-api","content":" Install @formatjs/cli-lib instead to use programmatically npmyarn npm i -D @formatjs/cli-lib ","version":"Next","tagName":"h2"},{"title":"Extraction","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#extraction-1","content":" import {extract} from '@formatjs/cli-lib' const resultAsString: Promise<string> = extract(files, { idInterpolationPattern: '[sha512:contenthash:base64:6]', }) ","version":"Next","tagName":"h3"},{"title":"Compilation","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#compilation-1","content":" import {compile} from '@formatjs/cli-lib' const resultAsString: Promise<string> = compile(files, { ast: true, }) ","version":"Next","tagName":"h3"},{"title":"Custom Formatter","type":1,"pageTitle":"CLI","url":"/docs/tooling/cli#custom-formatter","content":" import {FormatFn, CompileFn, Comparator} from '@formatjs/cli-lib' export const format: FormatFn = msgs => msgs // Sort key reverse alphabetically export const compareMessages = (el1, el2) => { return el1.key < el2.key ? 1 : -1 } export const compile: CompileFn = msgs => { const results: Record<string, string> = {} for (const k in msgs) { results[k] = msgs[k].defaultMessage! } return results } ","version":"Next","tagName":"h3"},{"title":"Upgrade Guide (v2 -> v3)","type":0,"sectionRef":"#","url":"/docs/react-intl/upgrade-guide-3x","content":"","keywords":"","version":"Next"},{"title":"Breaking API Changes","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#breaking-api-changes","content":" addLocaleData has been removed. See Migrate to using native Intl APIs for more details.ReactIntlLocaleData has been removed. See Migrate to using native Intl APIs for more details.intlShape has been removed. See TypeScript Support for more details.Change default textComponent in IntlProvider to React.Fragment. In order to keep the old behavior, you can explicitly set textComponent to span. <IntlProvider textComponent="span" /> FormattedRelative has been renamed to FormattedRelativeTime and its API has changed significantly. See FormattedRelativeTime for more details.formatRelative has been renamed to formatRelativeTime and its API has changed significantly. See FormattedRelativeTime for more details.Message Format syntax changes. See Message Format Syntax Changes for more details.IntlProvider no longer inherits from upstream IntlProvider. ","version":"Next","tagName":"h2"},{"title":"Use React 16.3 and upwards","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#use-react-163-and-upwards","content":" React Intl v3 supports the new context API, fixing all kinds of tree update problems 🎉In addition it makes use of the new lifecycle hooks (and gets rid of the deprecated ones). It also supports the new React.forwardRef() enabling users to directly access refs using the standard ref prop (see beneath for further information). ","version":"Next","tagName":"h2"},{"title":"Migrate withRef to forwardRef","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#migrate-withref-to-forwardref","content":" With the update to React >= 16.3 we got the option to use the new React.forwardRef() feature and because of this deprecated the use of the withRef option for the injectIntl HOC in favour of forwardRef. When forwardRef is set to true, you can now simply pretend the HOC wasn't there at all. Intl v2: import React from 'react' import {injectIntl} from 'react-intl' class MyComponent extends React.Component { doSomething = () => console.log(this.state || null) render() { return <div>Hello World</div> } } export default injectIntl(MyComponent, {withRef: true}) // somewhere else class Parent extends React.Component { componentDidMount() { this.myComponentRef.getWrappedInstance().doSomething() } render() { return ( <MyComponent ref={ref => { this.myComponentRef = ref }} /> ) } } Intl v3: import React from 'react' import {injectIntl} from 'react-intl' class MyComponent extends React.Component { doSomething = () => console.log(this.state || null) render() { return <div>Hello World</div> } } export default injectIntl(MyComponent, {forwardRef: true}) // somewhere else class Parent extends React.Component { myComponentRef = React.createRef() componentDidMount() { this.myComponentRef.doSomething() // no need to call getWrappedInstance() } render() { return <MyComponent ref={this.myComponentRef} /> } } ","version":"Next","tagName":"h2"},{"title":"New useIntl hook as an alternative of injectIntl HOC","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#new-useintl-hook-as-an-alternative-of-injectintl-hoc","content":" This v3 release also supports the latest React hook API for user with React >= 16.8. You can now take useIntl hook as an alternative to injectIntl HOC on function components. Both methods allow you to access the intl instance, here is a quick comparison: // injectIntl import {injectIntl} from 'react-intl' const MyComponentWithHOC = injectIntl(({intl, ...props}) => { // do something }) // useIntl import {useIntl} from 'react-intl' const MyComponentWithHook = props => { const intl = useIntl() // do something } To keep the API surface clean and simple, we only provide useIntl hook in the package. If preferable, user can wrap this built-in hook to make customized hook like useFormatMessage easily. Please visit React's official website for more general introduction on React hooks. ","version":"Next","tagName":"h2"},{"title":"Migrate to using native Intl APIs","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#migrate-to-using-native-intl-apis","content":" React Intl v3 no longer comes with CLDR data and rely on native Intl API instead. Specifically the new APIs we're relying on are: Intl.PluralRules: This can be polyfilled using this package.Intl.RelativeTimeFormat: This can be polyfilled using this package. This shift is meant to future-proof React Intl as these APIs are all stable and being implemented in modern browsers. This also means we no longer package and consume CLDRs in this package. If you previously were using addLocaleData to support older browsers, we recommend you do the following: If you're supporting browsers that do not have Intl.PluralRules (e.g IE11 & Safari 12-), include this polyfill in your build.If you're supporting browsers that do not have Intl.RelativeTimeFormat (e.g IE11, Edge, Safari 13-), include this polyfill in your build along with individual CLDR data for each locale you support. require('@formatjs/intl-pluralrules/polyfill') require('@formatjs/intl-pluralrules/locale-data/de') // Add locale data for de require('@formatjs/intl-relativetimeformat/polyfill') require('@formatjs/intl-relativetimeformat/locale-data/de') // Add locale data for de When using React Intl in Node.js, your node binary has to either: Get compiled with full-icu using these instructions OR Uses full-icu npm package ","version":"Next","tagName":"h2"},{"title":"TypeScript Support","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#typescript-support","content":" react-intl has been rewritten in TypeScript and thus has native TypeScript support. Therefore, we've also removed prop-types dependency and expose IntlShape as an interface instead. All types should be available from top level index file without importing from specific subfiles. For example: import {IntlShape} from 'react-intl' // Correct import {IntlShape} from 'react-intl/lib/types' // Incorrect If we're missing any interface top level support, please let us know and/or submitting a PR is greatly appreciated :) info You might need to make a few changes to your code if you were relying on the now deprecated @types/react-intl package. The most common example is InjectedIntlProps which must be replaced with WrappedComponentProps. ","version":"Next","tagName":"h2"},{"title":"FormattedRelativeTime","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#formattedrelativetime","content":" When we introduced FormattedRelative, the spec for Intl.RelativeTimeFormat was still unstable. It has now reached stage 3 and multiple browsers have implemented it. However, its API is different from FormattedRelative so we've adjusted its API to match the spec which means it's not backwards compatible. All units (such as day-short) becomes a combination of unit & style: <FormattedRelative units="second-short"/> // will be <FormattedRelativeTime unit="second" style="short"/> style becomes numeric (which is the default): <FormattedRelative style="numeric"/> // will be <FormattedRelativeTime /> <FormattedRelative style="best fit"/> // will be <FormattedRelativeTime numeric="auto"/> Type of value is no longer Date, but rather delta in the specified unit: <FormattedRelative value={Date.now() - 1000} units="second-narrow"/> // will be <FormattedRelativeTime value={-1} unit="second" style="narrow" /> <FormattedRelative value={Date.now() + 2000} units="second-narrow"/> // will be <FormattedRelativeTime value={2} unit="second" style="narrow" /> updateInterval becomes updateIntervalInSeconds and will only take the time delta in seconds. Update behavior remains the same, e.g: <FormattedRelativeTime value={2} numeric="auto" unit="second" style="narrow" updateIntervalInSeconds={1} /> // Initially prints: `in 2s` // 1 second later: `in 1s` // 1 second later: `now` // 1 second later: `1s ago` // 60 seconds later: `1m ago` initialNow has been removed. Similarly, the functional counterpart of this component which is formatRelative has been renamed to formatRelativeTime and its parameters have been changed to reflect this component's props accordingly. Implementing FormattedRelative behavior You can use @formatjs/intl-utils to get close to the previous behavior like this: import {selectUnit} from '@formatjs/intl-utils' const {value, unit} = selectUnit(Date.now() - 48 * 3600 * 1000) // render ;<FormattedRelativeTime value={value} unit={unit} /> ","version":"Next","tagName":"h2"},{"title":"Enhanced FormattedMessage & formatMessage rich text formatting","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#enhanced-formattedmessage--formatmessage-rich-text-formatting","content":" In v2, in order to do rich text formatting (embedding a ReactElement), you had to do this: <FormattedMessage defaultMessage="To buy a shoe, { link } and { cta }" values={{ link: ( <a class="external_link" target="_blank" href="https://www.shoe.com/"> visit our website </a> ), cta: <strong class="important">eat a shoe</strong>, }} /> Now you can do: <FormattedMessage defaultMessage="To buy a shoe, <a>visit our website</a> and <cta>eat a shoe</cta>" values={{ a: msg => ( <a class="external_link" target="_blank" href="https://www.shoe.com/"> {msg} </a> ), cta: msg => <strong class="important">{msg}</strong>, }} /> The change solves several issues: Contextual information was lost when you need to style part of the string: In this example above, link effectively is a blackbox placeholder to a translator. It can be a person, an animal, or a timestamp. Conveying contextual information via description & placeholder variable is often not enough since the variable can get sufficiently complicated.This brings feature-parity with other translation libs, such as fluent by Mozilla (using Overlays). If previously in cases where you pass in a ReactElement to a placeholder we highly recommend that you rethink the structure so that as much text is declared as possible: Before <FormattedMessage defaultMessage="Hello, {name} is {awesome} and {fun}" values={{ name: <b>John</b>, awesome: <span style="font-weight: bold;">awesome</span> fun: <span>fun and <FormattedTime value={Date.now()}/></span> }} /> After <FormattedMessage defaultMessage="Hello, <b>John</b> is <custom>awesome</custom> and <more>fun and {ts, time}</more>" values={{ b: name => <b>{name}</b>, custom: str => <span style="font-weight: bold;">{str}</span>, more: chunks => <span>{chunks}</span>, }} /> ","version":"Next","tagName":"h2"},{"title":"ESM Build","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#esm-build","content":" react-intl and its underlying libraries (intl-messageformat-parser, intl-messageformat, @formatjs/intl-relativetimeformat, intl-format-cache, intl-utils) export ESM artifacts. This means you should configure your build toolchain to transpile those libraries. ","version":"Next","tagName":"h2"},{"title":"Jest","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#jest","content":" Add transformIgnorePatterns to always include those libraries, e.g: { transformIgnorePatterns: [ '/node_modules/(?!intl-messageformat|intl-messageformat-parser).+\\\\.js$', ], } ","version":"Next","tagName":"h3"},{"title":"webpack","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#webpack","content":" If you're using babel-loader, add those libraries in include, e.g: include: [ path.join(__dirname, "node_modules/react-intl"), path.join(__dirname, "node_modules/intl-messageformat"), path.join(__dirname, "node_modules/intl-messageformat-parser"), ], ","version":"Next","tagName":"h3"},{"title":"Creating intl without using Provider","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#creating-intl-without-using-provider","content":" We've added a new API called createIntl that allows you to create an IntlShape object without using Provider. This allows you to format things outside of React lifecycle while reusing the same intl object. For example: 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> This is especially beneficial in SSR where you can reuse the same intl object across requests. ","version":"Next","tagName":"h2"},{"title":"Message Format Syntax Changes","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#message-format-syntax-changes","content":" We've rewritten our parser to be more faithful to ICU Message Format, in order to potentially support skeleton. So far the backwards-incompatible changes are: ","version":"Next","tagName":"h2"},{"title":"Escape character has been changed to apostrophe (').","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#escape-character-has-been-changed-to-apostrophe-","content":" Previously while we were using ICU message format syntax, our escape char was backslash (\\). This however creates issues with strict ICU translation vendors that support other implementations like ICU4J/ICU4C. Thanks to @pyrocat101 we've changed this behavior to be spec-compliant. This means: // Before <FormattedMessage defaultMessage="\\\\{foo\\\\}" /> //prints out "{foo}" // After <FormattedMessage defaultMessage="'{foo}'" /> //prints out "{foo}" We highly recommend reading the spec to learn more about how quote/escaping works here under Quoting/Escaping section. ","version":"Next","tagName":"h3"},{"title":"Placeholder argument syntax change","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#placeholder-argument-syntax-change","content":" Placeholder argument can no longer have - (e.g: this is a {placeholder-var} is invalid but this is a {placeholder_var} is). ","version":"Next","tagName":"h3"},{"title":"Testing","type":1,"pageTitle":"Upgrade Guide (v2 -> v3)","url":"/docs/react-intl/upgrade-guide-3x#testing","content":" We've removed IntlProvider.getChildContext for testing and now you can use createIntl to create a standalone intl object outside of React and use that for testing purposes. See Testing with React Intl for more details. ","version":"Next","tagName":"h2"},{"title":"eslint-plugin-formatjs","type":0,"sectionRef":"#","url":"/docs/tooling/linter","content":"","keywords":"","version":"Next"},{"title":"Usage","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#usage","content":" npmyarn npm i -D eslint-plugin-formatjs Then in your eslint config: import formatjs from 'eslint-plugin-formatjs' export default [ // other configs... { plugins: { formatjs, }, rules: { 'formatjs/no-offset': 'error', }, }, ] ","version":"Next","tagName":"h2"},{"title":"React","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#react","content":" Currently this uses intl.formatMessage, defineMessage, defineMessages, <FormattedMessage> from react-intl as hooks to verify the message. Therefore, in your code use 1 of the following mechanisms: import {defineMessages, defineMessage} from 'react-intl' const messages = defineMessages({ foo: { defaultMessage: 'foo', description: 'bar', }, }) defineMessage({ defaultMessage: 'single message', }) import {FormattedMessage} from 'react-intl' ;<FormattedMessage defaultMessage="foo" description="bar" /> function foo() { intl.formatMessage({ defaultMessage: 'foo', }) } ","version":"Next","tagName":"h3"},{"title":"Vue","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#vue","content":" This will check against intl.formatMessage, $formatMessage function calls in both your JS/TS & your SFC .vue files. For example: <template> <p> {{ $formatMessage({ defaultMessage: 'today is {now, date}', }) }} </p> </template> ","version":"Next","tagName":"h3"},{"title":"Shared Settings","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#shared-settings","content":" These settings are applied globally to all formatjs rules once specified. See Shared Settings for more details on how to set them. ","version":"Next","tagName":"h2"},{"title":"formatjs.additionalFunctionNames","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#formatjsadditionalfunctionnames","content":" Similar to babel-plugin-formatjs & @formatjs/ts-transformer, this allows you to specify additional function names to check besides formatMessage & $formatMessage. ","version":"Next","tagName":"h3"},{"title":"formatjs.additionalComponentNames","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#formatjsadditionalcomponentnames","content":" Similar to babel-plugin-formatjs & @formatjs/ts-transformer, this allows you to specify additional component names to check besides FormattedMessage. ","version":"Next","tagName":"h3"},{"title":"Shareable Configs","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#shareable-configs","content":" The plugin provides the following two shareable configs: recommendedstrict By using these, you can simplify your configuration while still using a set of rules that aligns with your quality standards. ","version":"Next","tagName":"h2"},{"title":"Example","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#example","content":" import formatjs from 'eslint-plugin-formatjs' export default [ formatjs.configs.recommended, // Other configs... ] ","version":"Next","tagName":"h3"},{"title":"Available Rules","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#available-rules","content":" ","version":"Next","tagName":"h2"},{"title":"blocklist-elements","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#blocklist-elements","content":" This blocklists usage of specific elements in ICU message. Why Certain translation vendors cannot handle things like selectordinal Available elements enum Element { // literal text, like `defaultMessage: 'some text'` literal = 'literal', // placeholder, like `defaultMessage: '{placeholder} var'` argument = 'argument', // number, like `defaultMessage: '{placeholder, number} var'` number = 'number', // date, like `defaultMessage: '{placeholder, date} var'` date = 'date', // time, like `defaultMessage: '{placeholder, time} var'` time = 'time', // select, like `defaultMessage: '{var, select, foo{one} bar{two}} var'` select = 'select', // selectordinal, like `defaultMessage: '{var, selectordinal, one{one} other{two}} var'` selectordinal = 'selectordinal', // plural, like `defaultMessage: '{var, plural, one{one} other{two}} var'` plural = 'plural', } Example import formatjs from 'eslint-plugin-formatjs' export default [ { plugins: { formatjs, }, rules: { 'formatjs/blocklist-elements': [2, ['selectordinal']], }, }, ] ","version":"Next","tagName":"h3"},{"title":"enforce-description","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#enforce-description","content":" This enforces description in the message descriptor. Why Description provides helpful context for translators import {defineMessages} from 'react-intl' const messages = defineMessages({ // WORKS foo: { defaultMessage: 'foo', description: 'bar', }, // FAILS bar: { defaultMessage: 'bar', }, }) Options import formatjs from 'eslint-plugin-formatjs' export default [ { plugins: { formatjs, }, rules: { 'formatjs/enforce-description': ['error', 'literal'], }, }, ] Setting literal forces description to always be a string literal instead of function calls or variables. This is helpful for extraction tools that expects description to always be a literal ","version":"Next","tagName":"h3"},{"title":"enforce-default-message","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#enforce-default-message","content":" This enforces defaultMessage in the message descriptor. Why Can be useful in case we want to extract messages for translations from source code. This way can make sure people won't forget about defaultMessage import {defineMessages} from 'react-intl' const messages = defineMessages({ // WORKS foo: { defaultMessage: 'This is default message', description: 'bar', }, // FAILS bar: { description: 'bar', }, }) Options import formatjs from 'eslint-plugin-formatjs' export default [ { plugins: { formatjs, }, rules: { 'formatjs/enforce-default-message': ['error', 'literal'], }, }, ] Setting literal forces defaultMessage to always be a string literal instead of function calls or variables. This is helpful for extraction tools that expects defaultMessage to always be a literal ","version":"Next","tagName":"h3"},{"title":"enforce-placeholders","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#enforce-placeholders","content":" Makes sure all values are passed in if message has placeholders (number/date/time/plural/select/selectordinal). This requires values to be passed in as literal object (not a variable). // WORKS, no error <FormattedMessage defaultMessage="this is a {placeholder}" values={{placeholder: 'dog'}} /> // WORKS, no error intl.formatMessage({ defaultMessage: 'this is a {placeholder}' }, {placeholder: 'dog'}) // WORKS, error bc no values were provided <FormattedMessage defaultMessage="this is a {placeholder}" /> // WORKS, error bc no values were provided intl.formatMessage({ defaultMessage: 'this is a {placeholder}' }) // WORKS, error bc `placeholder` is not passed in <FormattedMessage defaultMessage="this is a {placeholder}" values={{foo: 1}} /> // WORKS, error bc `placeholder` is not passed in intl.formatMessage({ defaultMessage: 'this is a {placeholder}' }, {foo: 1}) // DOESN'T WORK <FormattedMessage defaultMessage="this is a {placeholder}" values={someVar} /> // DOESN'T WORK intl.formatMessage({ defaultMessage: 'this is a {placeholder}' }, values) Options import formatjs from 'eslint-plugin-formatjs' export default [ { plugins: { formatjs, }, rules: { 'formatjs/enforce-placeholders': [ 'error', { ignoreList: ['foo'], }, ], }, }, ] ignoreList: List of placeholder names to ignore. This works with defaultRichTextElements in react-intl so we don't provide false positive for ambient global tag formatting ","version":"Next","tagName":"h3"},{"title":"enforce-plural-rules","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#enforce-plural-rules","content":" Enforce certain plural rules to always be specified/forbidden in a message. Why It is recommended to always specify other as fallback in the message.Some translation vendors only accept certain rules. Available rules enum LDML { zero = 'zero', one = 'one', two = 'two', few = 'few', many = 'many', other = 'other', } Example import formatjs from 'eslint-plugin-formatjs' export default [ { plugins: { formatjs, }, rules: { 'formatjs/enforce-plural-rules': [ 2, { one: true, other: true, zero: false, }, ], }, }, ] ","version":"Next","tagName":"h3"},{"title":"no-camel-case","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#no-camel-case","content":" This make sure placeholders are not camel-case. Why This is to prevent case-sensitivity issue in certain translation vendors. import {defineMessages} from 'react-intl' const messages = defineMessages({ // WORKS foo: { defaultMessage: 'foo {snake_case} {nothing}', }, // FAILS bar: { defaultMessage: 'foo {camelCase}', }, }) ","version":"Next","tagName":"h3"},{"title":"no-missing-icu-plural-one-placeholders","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#no-missing-icu-plural-one-placeholders","content":" Messages that look like {thing, plural, one {1 thing} other {# things}} will need to be changed to {thing, plural, one {# thing} other {# things}} Why one is a category for any number that behaves like 1. So in some languages, for example Ukrainian, Russian and Polish, one → numbers that end in 1 (like 1, 21, 151) but that don’t end in 11 (like 11, 111, 10311). More info ","version":"Next","tagName":"h3"},{"title":"no-emoji","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#no-emoji","content":" This prevents usage of emojis (or above a certain Unicode version) in message import formatjs from 'eslint-plugin-formatjs' export default [ { plugins: { formatjs, }, rules: { 'formatjs/no-emoji': ['error'], }, }, // OR { plugins: { formatjs, }, rules: { 'formatjs/no-emoji': ['error', {versionAbove: '12.0'}], }, }, ] Why Certain translation vendors cannot handle emojis.Cross-platform encoding for emojis are faulty. import {defineMessages} from 'react-intl' const messages = defineMessages({ // WORKS foo: { defaultMessage: 'Smileys & People', }, // WORKS with option {versionAbove: '12.0'} foo_bar: { defaultMessage: '😃 Smileys & People', }, // FAILS bar: { defaultMessage: '😃 Smileys & People', }, // FAILS with option {versionAbove: '12.0'} bar_foo: { defaultMessage: '🥹 Smileys & People', }, }) ","version":"Next","tagName":"h3"},{"title":"no-literal-string-in-jsx","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#no-literal-string-in-jsx","content":" This prevents untranslated strings in JSX. Why It is easy to forget wrapping JSX text in translation functions or components.It is easy to forget wrapping certain accessibility attributes (e.g. aria-label) in translation functions. // WORKS <Button> <FormattedMessage defaultMessage="Submit" /> </Button> // WORKS <Button> {customTranslateFn("Submit")} </Button> // WORKS <input aria-label={intl.formatMessage({defaultMessage: "Label"})} /> // WORKS <img src="/example.png" alt={intl.formatMessage({defaultMessage: "Image description"})} /> // FAILS <Button>Submit</Button> // FAILS <Button>{'Submit'}</Button> // FAILS <Button>{`Te` + 's' + t}</Button> // FAILS <input aria-label="Untranslated label" /> // FAILS <img src="/example.png" alt="Image description" /> // FAILS <input aria-label={`Untranslated label`} /> This linter reports text literals or string expressions, including string concatenation expressions in the JSX children. It also checks certain JSX attributes that you can customize. Example import formatjs from 'eslint-plugin-formatjs' export default [ { plugins: { formatjs, }, rules: { 'formatjs/no-literal-string-in-jsx': [ 2, { // Include or exclude additional prop checks (merged with the default checks) props: { include: [ // picomatch style glob pattern for tag name and prop name. // check `name` prop of `UI.Button` tag. ['UI.Button', 'name'], // check `message` of any component. ['*', 'message'], ], // Exclude will always override include. exclude: [ // do not check `message` of the `Foo` tag. ['Foo', 'message'], // do not check aria-label and aria-description of `Bar` tag. ['Bar', 'aria-{label,description}'], ], }, }, ], }, }, ] The default prop checks are: { include: [ // check aria attributes that the screen reader announces. ['*', 'aria-{label,description,details,errormessage}'], // check placeholder and title attribute of all native DOM elements. ['[a-z]*([a-z0-9])', '(placeholder|title)'], // check alt attribute of the img tag. ['img', 'alt'], ], exclude: [] } ","version":"Next","tagName":"h3"},{"title":"no-multiple-whitespaces","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#no-multiple-whitespaces","content":" This prevents usage of multiple consecutive whitespaces in message. Why Consecutive whitespaces are handled differently in different locales.Prevents \\ linebreaks in JS string which results in awkward whitespaces. import {defineMessages} from 'react-intl' const messages = defineMessages({ // WORKS foo: { defaultMessage: 'Smileys & People', }, // FAILS bar: { defaultMessage: 'Smileys & People', }, // FAILS baz: { defaultMessage: 'this message is too long \\ so I wanna line break it.', }, }) ","version":"Next","tagName":"h3"},{"title":"no-multiple-plurals","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#no-multiple-plurals","content":" This prevents specifying multiple plurals in your message. Why Nested plurals are hard to translate across languages so some translation vendors don't allow it. import {defineMessages} from 'react-intl' const messages = defineMessages({ // WORKS foo: { defaultMessage: '{p1, plural, one{one}}', }, // FAILS bar: { defaultMessage: '{p1, plural, one{one}} {p2, plural, one{two}}', } // ALSO FAILS bar2: { defaultMessage: '{p1, plural, one{{p2, plural, one{two}}}}', } }) ","version":"Next","tagName":"h3"},{"title":"no-offset","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#no-offset","content":" This prevents specifying offset in plural rules in your message. Why Offset has complicated logic implication so some translation vendors don't allow it. import {defineMessages} from 'react-intl' const messages = defineMessages({ // PASS foo: { defaultMessage: '{var, plural, one{one} other{other}}', }, // FAILS bar: { defaultMessage: '{var, plural, offset:1 one{one} other{other}}', }, }) ","version":"Next","tagName":"h3"},{"title":"enforce-id","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#enforce-id","content":" This enforces generated ID to be set in MessageDescriptor. Why Pipelines can enforce automatic/manual ID generation at the linter level (autofix to insert autogen ID) so this guarantees that. import {defineMessages} from 'react-intl'; const messages = defineMessages({ // PASS foo: { id: '19shaf' defaultMessage: '{var, plural, one{one} other{other}}', }, // FAILS bar: { id: 'something', defaultMessage: '{var, plural, offset:1 one{one} other{other}}', }, // FAILS bar: { defaultMessage: '{var, plural, offset:1 one{one} other{other}}', }, }); Options import formatjs from 'eslint-plugin-formatjs' export default [ { plugins: { formatjs, }, rules: { 'formatjs/enforce-id': [ 'error', { idInterpolationPattern: '[sha512:contenthash:base64:6]', }, ], }, }, ] idInterpolationPattern: Pattern to verify ID againstidWhitelist: An array of strings with regular expressions. This array allows allowlist custom ids for messages. For example '\\\\.' allows any id which has dot; '^payment_.*' - allows any custom id which has prefix payment_. Be aware that any backslash \\ provided via string must be escaped with an additional backslash. ","version":"Next","tagName":"h3"},{"title":"no-invalid-icu","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#no-invalid-icu","content":" This bans strings inside defaultMessage that are syntactically invalid. Why It's easy to miss strings that look correct to you as a developer but which are actually syntactically invalid ICU strings. For instance, the following would cause an eslint error: formatMessage( { defaultMessage: '{count, plural one {#} other {# more}}', //Missing a comma! }, { count: 1, } ) ","version":"Next","tagName":"h3"},{"title":"no-id","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#no-id","content":" This bans explicit ID in MessageDescriptor. Why We generally encourage automatic ID generation due to these reasons. This makes sure no explicit IDs are set. ","version":"Next","tagName":"h3"},{"title":"no-complex-selectors","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#no-complex-selectors","content":" Make sure a sentence is not too complex. Complexity is determined by how many strings are produced when we try to flatten the sentence given its selectors. For example: I have {count, plural, one{a dog} other{many dogs}} has the complexity of 2 because flattening the plural selector results in 2 sentences: I have a dog & I have many dogs. Default complexity limit is 20 (using Smartling as a reference) Options import formatjs from 'eslint-plugin-formatjs' export default [ { plugins: { formatjs, }, rules: { 'formatjs/no-complex-selectors': [ 'error', { limit: 3, }, ], }, }, ] ","version":"Next","tagName":"h3"},{"title":"no-useless-message","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#no-useless-message","content":" This bans messages that do not require translation. Why Messages like {test} is not actionable by translators. The code should just directly reference test. ","version":"Next","tagName":"h3"},{"title":"prefer-formatted-message","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#prefer-formatted-message","content":" Use <FormattedMessage> instead of the imperative intl.formatMessage(...) if applicable. // Bad <p> {intl.formatMessage({defaultMessage: 'hello'})} </p> // Good <p> <FormattedMessage defaultMessage="hello" /> </p> Why Consistent coding style in JSX and less syntax clutter. ","version":"Next","tagName":"h3"},{"title":"prefer-pound-in-plural","type":1,"pageTitle":"eslint-plugin-formatjs","url":"/docs/tooling/linter#prefer-pound-in-plural","content":" Use # in the plural argument to reference the count instead of repeating the argument. // Bad I have {count} { count, plural, one {apple} other {apples} } } // Good I have { count, plural, one {# apple} other {# apples} } } // Bad I have { count, plural, one {{count} apple} other {{count} apples} } } // Good I have { count, plural, one {# apple} other {# apples} } } // Bad I won the {ranking}{ count, selectordinal, one {st} two {nd} few {rd} other {th} } place. // Good I won the {ranking}{ count, selectordinal, one {#st} two {#nd} few {#rd} other {#th} } place. Why More concise message.Ensures that the count are correctly formatted as numbers. ","version":"Next","tagName":"h3"}],"options":{"id":"default"}}