Now that you've declared your messages, extracted them, sent them to your translation vendor and they have given you back the translated JSON of the same format, it's time to talk about how to distribute & consume the translated JSON.
Compiling Messages#
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:
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.
Translation Management System (TMS) Integration#
If your TMS/vendor has a different JSON format, prefer one of the built-in --format formatter names or pre-process the file before running @formatjs/cli. Passing a custom formatter file to compile --format <formatFile> is deprecated and prints a warning. For example, the deprecated formatter-file flow looks like this:
If your vendor accepts the format like
{
"[id]": {
"string": "[message]",
"comment": "[description]"
}
}
you can run
npm run compile -- lang/fr.json --ast --out-file compiled-lang/fr.json --format formatter.js
where formatter.js is:
export function compile(msgs) {
const results = {}
for (const [id, msg] of Object.entries(msgs)) {
results[id] = msg.string
}
return results
}
Prefer the built-in formatters for popular TMSes when possible.
Distribution#
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:
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)
}