Unleash the hidden superpowers of react-intl (Part 1)
Part 1: How to beautify the react.js markup for your translations using babel macros
Let images speak to see what you will get:
We do not like this clutter:
const name = 'John Doe';<FormattedMessage
id="welcome"
defaultMessage={`Hello {name}!`}
values={{ name: <b>{name}</b> }}
/>
While react-intl works awesome having those FormattedMessage
everywhere does not really help keeping your code nice and readable. Wouldn’t it be nicer you just could write:
<FormattedMessage id=”welcome”>Hello <b>{name}</b>!</FormattedMessage>
babel macros to the rescue
You could easily write a babel plugin to transform the above simplified markup to the needed react-intl FormattedMessage. But there is a better way using Kent C. Dodds babel macros (https://github.com/kentcdodds/babel-plugin-macros). There comes a big advantage with using macros (beside they are super simple to create) you can use those with applications created with create-react-app without ejecting (on time of writing needs an alpha build v2.x.x).
A babel macro is basically just a function that gets a reference of the nodes using the macro:
const { createMacro } = require('babel-plugin-macros')
module.exports = createMacro(myMacro)
function myMacro({references, state, babel}) {
// the FormattedMessage imported in below code snippet
const { FormattedMessage = [] } = references; // transform each occurance
FormattedMessage.forEach(referencePath => { /* transform */ });
}
We won’t go through all the details of the macro used to transform the simpler markup — but you can checkout the code here:
https://github.com/locize/locize-react-intl-example/blob/master/src/intl.macro.js
You can use the macro like:
// import the macro component
import { FormattedMessage } from "./intl.macro";// and use it
<FormattedMessage id=”welcome”>Hello <b>{name}</b>!</FormattedMessage>
The macro will transform it to the react-intl FormattedMessage:
<FormattedMessage
id="welcome"
defaultMessage={`Hello {name}!`}
values={{ name: <b>{name}</b> }}
/>
Plurals and Select
We could add some more macro magic to also simpler plurals and selects:
import { Select, Plural } from "./intl.macro";// select
<FormattedMessage
id="avoid_bugs"
defaultMessage="{gender,select,he{He avoids bugs.}she{She avoids bugs.}other{They avoid bugs.}}"
values={{ count: 10 }}
/>// will become
<Select
id="avoid_bugs"
switch={gender}
male="He avoids bugs."
female="She avoids bugs."
other="They avoid bugs."
/>// plurals
<FormattedMessage
id="items_count"
defaultMessage="{count,plural,=0{There is no item.}one{There is # item.}other{There are # items.}}"
values={{ count: 10 }}
/>// will become:
<Plural
id="items_count"
count={itemsCount1}
$0="There is no item."
one="There is # item."
other="There are # items."
/>
For more options (like nesting components) have a look at the sample usages:
https://github.com/locize/locize-react-intl-example/blob/master/src/ComponentUsingMacro.js
So in this first part you learnt how you can use the babel-plugin-macros module to get your markup to be more readable as compared to just use the bare FormattedMessage
provided by react-intl.
Don’t forget you can build upon the sample here:
In the second part coming soon you will learn how to extend your react.js project using react-intl to provide internationalization to enable a simple continuous localization lifecycle that is also suitable for large projects needing to split translations into multiple files.
Hope you liked the first part — stay tuned for the second.