--- myst: html_meta: "description": "Internationalization (i18n) is the process of creating user interfaces which are suitable for different languages and cultural contexts." "property=og:description": "Internationalization (i18n) is the process of creating user interfaces which are suitable for different languages and cultural contexts." "property=og:title": "Internationalization" "keywords": "Volto, Plone, frontend, React, Blocks, Internationalization, i18n" --- (internationalization)= # Internationalization Internationalization (i18n) is the process of creating user interfaces which are suitable for different languages and cultural contexts. Volto uses the library [react-intl](https://www.npmjs.com/package/react-intl) to provide translations for any potential language. Anything you can read in the [official documentation of react-intl](https://formatjs.io/docs/react-intl/) also applies for Volto. However this section teaches you about the most common use cases relating to i18n you probably will have when developing your {doc}`../addons` or contributing to the Volto core itself. ## Broad overview The workflow for creating *new* translatable texts is as follows: 1. Create translatable i18n strings in your code 2. Extract all i18n strings from your code with a script and create artifacts like `.po` and `.pot` files 3. Use your favorite editor to translate all i18n strings (i.e. edit the `.po` files) 4. Re-run the script, which then moves the translations from the `.po` files into for Volto usable `.json` files This way of organizing translations relies on [gettext](https://en.wikipedia.org/wiki/Gettext), a proven and established system with great tool support. All translation files are located under the directory `locales`. This might look like this: ```shell $ tree locales/ locales/ ├── de │ └── LC_MESSAGES │ └── volto.po ├── de.json ├── en │ └── LC_MESSAGES │ └── volto.po ├── en.json ├── es │ └── LC_MESSAGES │ └── volto.po ├── es.json ├── it │ └── LC_MESSAGES │ └── volto.po ├── it.json ├── ja │ └── LC_MESSAGES │ └── volto.po ├── ja.json ├── nl │ └── LC_MESSAGES │ └── volto.po ├── nl.json └── volto.pot 12 directories, 13 files ``` The file `volto.pot` holds all extracted i18n strings and acts as master template for all the `*.po` files. The translation for each language is stored within a dedicated sub-directory (like `en` for English, `it` for Italian, etc.) and are stored as `*.po` file and separately stored directly under `locales` as `*.json` file. (creating-i18n-strings)= ## Creating i18n Strings ### Translating Text Within HTML Elements `react-intl` can identify translatable texts with the `FormattedMessage` components and `defineMessages` functions declarations. It is also possible to format your messages as your liking in both of them. This is an example of how you can write a text with contents `Hello World`, which can be identified via `hello_world`: ```jsx import { FormattedMessage } from 'react-intl'; function HelloWorld(props) { return (
); } ``` The identifier `hello_world` is then commonly used between all the translations. There are also more features available such as using placeholders. See the docs for all features in the [FormattedMessage component](https://formatjs.io/docs/react-intl/components#formattedmessage). ### Translating Attributes As `FormatMessage` is only suitable for creating text within HTML elements, it cannot be used for translating individual attributes. But with the method [formatMessage](https://formatjs.io/docs/react-intl/api/#formatmessage) there exists another way to translate primitive strings. This approach can be best explained with an example: Assume you have a component called `TeaserImage` which contains an image that has for accessibility reasons the `alt` attribute. To translate the `alt` attribute, you have to do the following steps: 1. Import the following necessary methods: ```js import { defineMessages, injectIntl, intlShape } from 'react-intl'; ``` 2. Define a message (or more) via [defineMessages](https://formatjs.io/docs/react-intl/api/#definemessagesdefinemessage): ```js const messages = defineMessages({ teaserAltText: { id: 'teaser_alt_text', defaultMessage: 'Teaser Alt Text', }, }); ``` 3. As the method `formatMessage` in our component class/function is needed, there is a special prop `intl`, that needs to be injected in our components. In case of being a class component: ```js class TeaserImage extends Component { ... } export default injectIntl(TeaserImage); ``` Since you now have another prop available, it has to be to properly defined in the propTypes: ```jsx TeaserImage.propTypes = { intl: intlShape.isRequired, ... }; ``` In case of being a functional component: ```js import { useIntl } from 'react-intl'; const TeaserImage = (props) => { // We can use the hook to inject the `intl` prop const intl = useIntl() ... } export default TeaserImage; ``` Although one could use also the composable approach in a functional component as well. 4. As last step, the method can be used like this: ```jsx {intl.formatMessage(messages.teaserAltText)} ``` ## Extracting i18n Strings Volto provides an i18n extraction script to get all translatable strings from your application. This script can be invoked by this command: ```sh yarn i18n ``` This will generate the following output: ```console Extracting messages from source files... Synchronizing messages to pot file... Synchronizing messages to po files... Generating the json files... done! ``` As the output suggests it will first extract all messages from the source files into `.json` files. Then it will synchronize the extracted messages with the `.pot` master template and with all the `.po` files found in the project. This script will combine the messages located in Volto itself and the current project, and combine them into the `.json` files. ## Overriding i18n messages If you want to override an existing translation, you should declare the original message again somewhere else in your project. For example in `src/config.js` or in your `src/index.js` of your add-on: ```js import { defineMessages } from 'react-intl'; defineMessages({ back: { id: 'Back', defaultMessage: 'Back', }, }); ``` Then run `yarn i18n`. You will find the translation ready to override in your `locales` directory, such as `locales/de/LC_MESSAGES/volto.po`. ``` #: src/config msgid "Back" msgstr "My overridden translation" ``` After setting the override, then run `yarn i18n` again to create the `de.json` translation files. Restart Volto to see the changes applied. ```{note} Shadowed components do _not_ override translations. 99% of the time you do not want them to do that. Thus the `customizations` folder is excluded from the i18n build. If your customization introduces a new translation, you should add the new definition in `src/config.js` or in your `src/index.js` of your add-on. ``` ## Translating add-ons See {ref}`addon-i18n`. ## Contributing translations for an unsupported language The Volto project welcomes all speakers from the world to include any language, which is not supported yet. If your language's po file is not available in Volto, [open an issue in GitHub](https://github.com/plone/volto/issues) so we can create it for you, and after that you can start contributing your translations!