Merchant Center applications use react-intl, a library built on top of the ECMAScript Internationalization API.

In the React components, you can use things like <FormattedMessage> or intl.formatMessage to render the correct translation message based on the active locale.

We usually define a messages.js file co-located to the React component using those messages. The file defines messages as following:

import { defineMessages } from 'react-intl';
export default defineMessages({
title: {
id: 'StateMachines.ListView.title',
description: 'The page title of state machines list',
defaultMessage: 'State Machines',

This is the default message, which will be used in case there is no translation available for the given locale.

Extracting messages for translations

To generate translation files, we provide a mc-scripts extract-intl script, which will aggregate all react Intl messages into a core.json file:

"StateMachines.ListView.title": "State Machines"

The core.json is the so-called source file, which should be used as reference file for the translations in the other locales.

Depending on your translation process, you can decide to manage the translations in a separate service (at commercetools we use Transifex) or to manually provide the translations.

The mc-scripts extract-intl command provides some extra options to deal with different scenarios.

Extract Intl messages

Using the messages in the application

The JSON files containing the translations need to be loaded within the application. The <ApplicationShell> expects a applicationMessages prop that is used to load the messages in the react-intl provider. The applicationMessages prop can either be a JSON object or a function returning a Promise with the loaded messages.

To keep the bundle size low, the application should only load the messages for a specific locale and not all of them. This can be achieved by using the Code-Splitting feature.

Given the translation messages are located in the i18n/data folder, you can define a function to dynamically load the messages:

// entry-point.js
const loadMessages = lang => {
let loadAppI18nPromise;
switch (lang) {
case 'de':
loadAppI18nPromise = import(
'../../i18n/data/de.json' /* webpackChunkName: "app-i18n-de" */
case 'es':
loadAppI18nPromise = import(
'../../i18n/data/es.json' /* webpackChunkName: "app-i18n-es" */
loadAppI18nPromise = import(
'../../i18n/data/en.json' /* webpackChunkName: "app-i18n-en" */
return loadAppI18nPromise.then(
result => result.default,
error => {
`Something went wrong while loading the app messages for ${lang}`,
return {};
const Application = () => (
// other props