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_us
anden_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.