React-Intl: An API and Component Analysis

Posted by Zain Sajjad on January 13, 2020

GSD

In our recent post, we conducted an in-depth analysis of the top 4 component libraries for translations in React applications and concluded, react-intl and react-i18next are the most effective amongst top translation libraries. 

In this post, we will go through the component library of react-intl and see how we can develop more scalable multilingual apps.

Integration

React Intl uses the provider pattern supply messages to the component tree of our app. 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:

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 all react-intl components. 

ReactDOM.render(

 <IntlProvider

   locale="en"

   textComponent={React.Fragment}

   messages={translationsFromLocale}

 >

   <App />

 </IntlProvider>,

 document.getElementById("app")

);

Once our app is wrapped in IntlProvider we’re all set to use any of react-intl component in any of our components.

Number Formatting

React-intl supports locale-based number formatting with two major features:

  1. Pluralization
  2. Unit display

Pluralization

For pluralization, react-intl uses native Intl.PluralRules that's available for most of the modern browsers. For browsers that don’t have PluralRules, you can use polyfill provided by react-intl.

Polyfill:

npm install @formatjs/intl-pluralrules

And initialize it at the top of your app, by requiring this polyfill.

If (!Intl.PluralRules){

   require(“@formatjs/intl-pluralrules/polyfill”);

   require(“@formatjs/intl-pluralrules/dist/local-date/en”); //Add locale

}

Usage:

The pluralization component allows you to define messages against `zero`, `one`, `two`, `few`, `many` or `other` value. It renders the message based on the given value of the number given.

<FormattedNumber 

 value={messagesCount}

 zero="All Caught up"

 one="Just single message" 

 two="Two message unseen" 

 few="A few message awaiting you" 

 many="A lot of things to catch up" 

 other="messages" 

/>

Units Display:

The other part of FormattedNumber display is rendering value with its unit. To use the unit display we have to install a polyfill.

Polyfill:

npm install @formatjs/intl-unified-numberformat

And initialize it before using anywhere in the app.

import { UnifiedNumberFormat } from "@formatjs/intl-unified-numberformat";

 

UnifiedNumberFormat.__addLocaleData(

 require("@formatjs/intl-unified-numberformat/dist/locale-data/en.json") // locale-data for en

);

This polyfill supports more than 40 different units.

Usage:

 <FormattedNumber value={1000} style="unit" unit="kilogram" unitDisplay="long|short|narrow" />

You can add any of the units from the given list and display its long, short or narrow versions.

Date Formatting

One of the most challenging tasks for frontend developers today is to render correct dates and times. Moment.js, date-fns and many other similar libraries are trying to solve this problem in different manners. As far as the rendering of dates is concerned, react-intl is the best solution, providing full control over date display as it uses Intl.DateTimeFormat under the hood.

Usage:

<FormattedDate

   value={new Date(1459832991883)}

   year="numeric|2-digit"

   month="long|short|narrow|numeric|2-digit"

   day="numeric|2-digit"

   era="long|short|narrow"

/>

Here are the details of props for this component

  • `year`: The representation of the year. Possible values are:
    • "numeric" (e.g., 2012)
    • "2-digit" (e.g., 12)
  • `month`:
    • "numeric" (e.g., 2)
    • "2-digit" (e.g., 02)
    • "long" (e.g., March)
    • "short" (e.g., Mar)
    • "narrow" (e.g., M). Two months may have the same narrow style for some locales (e.g. May's narrow style is also M).
  • `day`:
    • "numeric" (e.g., 1)
    • "2-digit" (e.g., 01)
  • `era`:
    • "long" (e.g., Anno Domini)
    • "short" (e.g., AD)
    • "narrow" (e.g., A)

banner-cta-react-blue-background.png

Time Formatting

React-intl’s time formatting ships in two forms:

  1. Simple Time Formatting
  2. Relative Time Formatting

Simple Time Formatting

It uses Intl.DateTimeFormat under the hood and renders time according to selected locale given options.

Usage:

<FormattedTime

   value={new Date()}

   hour="numeric|2-digit"

   minute="numeric|2-digit"

   second="numeric|2-digit"

   timeZoneName="long|short|narrow"

/>

Here values of hours, minutes and seconds can be 2-digits or numeric, while timeZoneName can be "long" (e.g., British Summer Time) or "short" (e.g., GMT+1)

Relative TIme Formatting:

Relative time formatting is one of the distinguishing features available with react-intl. It allows developers to show more user-friendly dates for cases like time to start, time remaining before it ends, etc. React-intl updates this component with developer-defined frequency. 

Polyfill:

For relative time formatting, react-intl relies on native Intl.RelativeTimeFormat that is available with most of the modern browsers excluding (IE 11 & Safari 12-). To support older browsers, we have to add polyfill provided by formatJS.

For installing polyfill:

npm install @formatjs/intl-relativetimeformat

At the top of the app, we have to initialize this polyfill if it is not available in the browser.

if (!Intl.RelativeTimeFormat) {

 require("@formatjs/intl-relativetimeformat/polyfill");

 require("@formatjs/intl-relativetimeformat/dist/locale-data/en"); // Add locale data for de

}

Usage:

<FormattedRelativeTime value={0} numeric="auto" updateIntervalInSeconds={10} />

FormattedRelativeTime takes the following props:

  • value: A numeric difference at the time of the initial render, the next value is calculated by react-intl based on `updateIntervalInSeconds` and some optimization we will discuss later.
  • updateIntervalInSeconds: It will re-render this component after the given seconds and display the updated value. For our given example, it will re-render every 10 seconds and display value accordingly. Here the formatting can us smart, once the value crosses minute mark, it will stop rendering every 10 seconds and rather it will now re-render the next minute. 
  • numeric?: 'always' | 'auto' // 'auto' will translate the difference in timing phrases such as for '1 day ago' it will be 'yesterday'.
  • style: 'long' | 'short' | 'narrow'

Utils:

React-intl previously gave a best-fit algorithm for relative time calculations. In v3 it requires a polyfill to calculate the difference between dates.

https://www.npmjs.com/package/@formatjs/intl-utils

String Formatting

Another cool feature of react-intl is the `FormattedMessage` component. It allows you to combine many different formats together in a string along with rich formatting. Before we dive into the usage, let’s look into our examples for rich formatting, combining formats, and the props for this component. 

  • Id: A unique identifier across the app for a given message to distinguish it from different translations.
  • defaulMessage: In the case where the id is not defined in the messages of selected locale, react-intl uses this message as a fallback.
  • description: This value helps cross-functional teams to understand the scope of the message and where it is used. 
  • values: Object of values accessed in the message.
  • tagName: By default, It 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.

Let's explore some examples to understand it further.

Combining Different Formats:

In this example, we will combine number and plural formatting with our simple string message. 

<FormattedMessage

   id="combination"

   defaultMessage="Hello you have {count, number} {count, plural, one {Message} other {Messages}}"

   description="Combination for formats"

   values={{

     count: 1000

   }}

   tagName="p"

 />

Here you can see `values`, the object has the `count` key that is being used to display the number and plural value within a string.

Rich Text Formatting:

Here you can integrate different tags within a single message, to show a rich text.

 
<FormattedMessage

id="richFormatting"

defaultMessage="To buy a shoe, <a>visit our website</a> and <cta>buy a shoe</cta> {icon}"

values={{

a: (...chunks) => (

<a

class="external_link"

target="_blank"

rel="noopener noreferrer"

href="https://www.shoe.com/"

>

{chunks}

</a>

),

cta: (...chunks) => <strong class="important">{chunks}</strong>,

icon: (

<svg

viewBox="0 0 24 24"

width="24"

height="24"

stroke="currentColor"

stroke-width="2"

fill="none"

stroke-linecap="round"

stroke-linejoin="round"

class="css-i6dzq1"

>
<circle cx="9" cy="21" r="1"></circle>

<circle cx="20" cy="21" r="1"></circle>

<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>

</svg>

)
}}
/>



As seen, all tags accept function as the component with all chunks supplied as an argument to function, this gives us great flexibility to style apps better without breaking out of our translation paradigm.

Closing Up:

Components of react-intl provide an idiomatic-React way of integrating internationalization into a React app with it’s rich API to implement all of its features and benefits.You can check out all of these components in action here

banner-cta-react-blue-background.png

Sign up to receive tutorials and updates on React-intl.
    
Zain Sajjad

Zain is a Senior Frontend Engineer at Peekaboo Guru. He is passionate about anything and everything React, React Native, JavaScript & Mobile Machine Learning.

ButterCMS is the #1 rated Headless CMS

Related articles

Don’t miss a single post

Get our latest articles, stay updated!