React i18n - Extend react-intl with your own context and markup

TL;DR; Instead of using the default FormattedMessage component and useIntl hook from react-intl, you should provide your own version of these components with custom variables injected by default. Creating your own wrapper will simplify your code and give more power to your translation keys.

When it comes to internationalization in React the react-intl package is a robust choice and will give you plenty of flexibility in terms of making your translations dynamic, handling pluralization etc.

But like with your code, there are plenty of constants you do not want to hardcode into your translations. This also applies to links and small components you wish to embed inside your translations.

Fortunately it is possible to wrap react-intl inside custom hooks and components to extend it with custom context and markup.

In this article, I will start by showing the basics of using react-intl then show you how to provide your own customized version for better reusability.

Setting up react-intl

Installing and configuring react-intl inside your application is fairly straightforward.

First add the package to your application:

Then create a lang folder with an english translation file:

Add a registry with all your available languages:

Finally, configure your top App Component to use react-intl with the chosen language:

Alright, we've got react-intl setup. Now let's cover the basics of how to use it.

Using react-intl

In this section we'll see how to use react-intl to translate messages and how to dynamically format these messages.

Component & Hook

There are two ways to use react-intl: components and hooks. They're essentially the same. Let's see both approaches.

Here is how to use react-intl using a component. This is the easiest and most common use of react-intl.

If you need to access messages, you can use the hook version. This is particularly useful when you need to inject translated messages into component props.

The props of the hook and component versions are the same in the end. Going forward I will use the component version because it is simpler to format. But remember you can always use the hook version if you need.

Message Formatting

Now let's see how to make your messages dynamic. The react-intl library is ICU compliant and has therefore a wide range of dynamic formatting directives.

Formatting always has the following structure in translation keys:

Now this is what these examples look like in React:

You can read more about message syntax on in the FormatJS documentation.

Component injection

You can extend the react-intl markup with custom components. Custom components can be injected in the form of variables or tags.

Here is a concrete example of injecting a break variable and a link tag.

From there you can inject any custom component into your translation files!

Convenient right? We can do more :)

RichMessage: your custom version of react-intl

As you can see above, it's fairly straightforward to inject custom context into react-intl translation keys.

So what about creating a wrapper around react-intl to make common configuration parameters available in your translation keys without having to explicitly pass values every time. Nothing easier!

Let's start by creating a custom component. This component will inject a list of constant variables into react-intl plus any user-defined variable.

Let's also create a hook version of this component. Note that we only extend useIntl with a formatRichMessage function, we do not override anything. This means that the native react-intl functions are still available in our hook.

Now let's define that missing RICH_TAGS constant. This constant defines all the variables and tags available by default in our translation keys. You will notice that we even created a reusable component for external links.

Finally, let's create a module index to expose our newly created components:

That's it! The constants and tags defined in RICH_TAGS will now always be available in our translation context. We just need to use our new component and hook to benefit from them.

This is the component approach:

This is the hook approach:

Easy!

Wrapping up

The react-intl library provides a lot of out-of-the-box functionalities. We strongly recommend reading the FormatJS documentation to get a good grasp on the formatting options it provides.

Once you are comfortable with it, we highly recommend you create a RichMessage/RichIntl wrapper to expose your constants and extend the FormatJS markup with your own.

Having a custom wrapper will make your translation keys easier to read and your React code simpler by not having to pass important constants as values every time.

About us

Keypup is on a mission to help developers and tech leads work better with each others on development projects. Our platform automatically centralizes, prioritizes and assigns people and actions on issues and pull requests to optimize your development flow.

Don't get lost because you have to juggle with twenty pull requests across five development projects. We'll clean and organize that for you to ensure a smooth landing.

---

Code snippets hosted with ❤ by GitHub

You may also like reading: