Internationalization
The react-admin user interface uses English as the default language. But you can also display the UI and content in other languages, allow changing language at runtime, and even lazy-loading optional languages to avoid increasing the bundle size with all translations.
You will use translation features mostly via the i18nProvider, and a set of hooks (useTranslate, useLocaleState).
Weāll use a bit of custom vocabulary in this section:
- āi18nā is a shorter way to write āinternationalizationā (an āiā followed by 18 letters followed by ānā)
- ālocaleā is a concept similar to language, but it also includes the concept of country. For instance, there are several English locales (like
en_usanden_gb) because US and UK citizens donāt use exactly the same language. For react-admin, the ālocaleā is just a key for your i18nProvider, so it can have any value you want. - ātranslation keyā is a string that is used to identify a piece of text in your application, e.g. āra.action.saveā for the
<SaveButton>label
Anatomy Of An i18nProvider
Just like for data fetching and authentication, react-admin is agnostic to your translation backend. It relies on a provider for internationalization. Itās called the i18nProvider, and it manages translation and language changes.
It should be an object with the following methods:
// in src/i18nProvider.ts
export const i18nProvider = {
// required
translate: (key, options) => string,
changeLocale: locale => Promise<void>,
getLocale: () => string,
// optional
getLocales: () => [{ locale: string, name: string }],
}
Use the <Admin i18nProvider> prop to define the i18nProvider of a react-admin app:
import { i18nProvider } from './i18nProvider';
const App = () => (
<Admin
dataProvider={dataProvider}
i18nProvider={i18nProvider}
>
{/* ... */}
</Admin>
);
If you want to add or update translations, youāll have to provide your own i18nProvider.
Translation Keys
React-admin components use translation keys for their text and rely on the i18nProvider to translate them.
For instance, the <SaveButton> renders the word āSaveā in English and āEnregistrerā in French. This is because the button actually renders the return value of the i18nProvider.translate('ra.action.save') method:
import { Button, useTranslate } from 'react-admin';
const SaveButton = ({ doSave }) => {
const translate = useTranslate(); // returns the i18nProvider.translate() method
return (
<Button onClick={doSave}>
{translate('ra.action.save')}
</Button>
);
};
If you build an app for users from several countries, you should do the same: always use translation keys instead of plain text in your own components:
// in src/MyHelloButton.js
import * as React from "react";
import { useTranslate } from 'react-admin';
export const MyHelloButton = () => {
const translate = useTranslate();
const handleClick = () => {
/* ... */
};
return (
<button>{translate('myroot.hello.world')}</button>
);
};
Check the Translating the UI for example usage of the useTranslate hook.
ra-i18n-polyglot
Although you can build an i18nProvider from scratch, react-admin provides a package called ra-i18n-polyglot that leverages the Polyglot.js library to build an i18nProvider based on a dictionary of translations.
// in src/i18nProvider.js
import polyglotI18nProvider from 'ra-i18n-polyglot';
import en from 'ra-language-english';
import fr from 'ra-language-french';
const translations = { en, fr };
export const i18nProvider = polyglotI18nProvider(
locale => translations[locale],
'en', // default locale
[{ locale: 'en', name: 'English' }, { locale: 'fr', name: 'FranƧais' }],
);
// in src/App.js
import { Admin } from 'react-admin';
import { i18nProvider } from './i18nProvider';
const App = () => (
<Admin
i18nProvider={i18nProvider}
dataProvider={dataProvider}
>
...
</Admin>
);
Check the translation setup documentation for details about ra-i18n-polyglot and how to configure it.
ra-i18n-i18next
React-admin also provides a package called ra-i18n-i18next that leverages the i18next library to build an i18nProvider based on a dictionary of translations.
You might prefer this package over ra-i18n-polyglot when:
- you already use i18next services such as locize
- you want more control on how you organize translations, leveraging multiple files and namespaces
- you want more control on how you load translations
- you want to use features not available in Polyglot such as:
// in src/i18nProvider.js
import i18n from 'i18next';
import { useI18nextProvider, convertRaTranslationsToI18next } from 'ra-i18n-i18next';
const i18nInstance = i18n.use(
resourcesToBackend(language => {
if (language === 'fr') {
return import(
`ra-language-french`
).then(({ default: messages }) =>
convertRaTranslationsToI18next(messages)
);
}
return import(`ra-language-english`).then(({ default: messages }) =>
convertRaTranslationsToI18next(messages)
);
})
);
export const useMyI18nProvider = () => useI18nextProvider({
i18nInstance,
availableLocales: [
{ locale: 'en', name: 'English' },
{ locale: 'fr', name: 'French' },
],
});
// in src/App.tsx
import { Admin } from 'react-admin';
import { useMyI18nProvider } from './i18nProvider';
const App = () => {
const i18nProvider = useMyI18nProvider();
if (!i18nProvider) return null;
return (
<Admin
i18nProvider={i18nProvider}
dataProvider={dataProvider}
>
...
</Admin>
);
};
Check the ra-i18n-i18next documentation for details.
Translation Files
ra-i18n-polyglot relies on JSON objects for translations. This means that the only thing required to add support for a new language is a JSON file.
Translation files match a translation key to a translated text. They look like the following:
const englishMessages = {
// react-admin components
ra: {
action: {
cancel: 'Cancel',
clone: 'Clone',
confirm: 'Confirm',
create: 'Create',
delete: 'Delete',
edit: 'Edit',
export: 'Export',
list: 'List',
refresh: 'Refresh',
save: 'Save',
},
boolean: {
true: 'Yes',
false: 'No',
null: ' ',
},
/* ...*/
},
// resources and fields
resources: {
shoe: {
name: 'Shoe |||| Shoes',
fields: {
model: 'Model',
stock: 'Nb in stock',
color: 'Color',
},
},
customer: {
name: 'Customer |||| Customers',
fields: {
first_name: 'First name',
last_name: 'Last name',
dob: 'Date of birth',
}
}
/* ...*/
},
// custom components
acme: {
buttons: {
allow: 'Allow',
deny: 'Deny',
},
notifications: {
error: 'An error occurred',
success: 'Success',
},
/* ...*/
}
};
Tip: The default (English) messages are available in the ra-language-english package source.
When building an internationalized app with react-admin, the usual workflow is therefore to let developers write the main translation file. Then, pass this file to a team of translators, with the task to translate it. They can use any software they want for that (even software using Gettext/PO files, as itās possible to convert POT to and from JSON). Finally, aggregate all the translations into an i18nProvider.
Check the translation setup documentation to understand how to build your own translation file, the list of available translations to find a translation for your language, and Translating the UI to understand how to translate react-admin commponents.
