# Internationalization


Translated strings fall into 4 categories:
- System strings: depending on the platform, Qt (the widget library) may use
  system dialogs, like the file picker.
- Qt internal strings: the translation for some standard dialogs (like the
  OK/Cancel buttons on a message box) is provided by Qt itself.
- Plover's UI.
- The UI of the various installed Plover plugins.

The first 2 cases are mostly out of our control, and consequently this guide
only covers the last 2.


## Language selection

The correct language is automatically selected at startup according to the system
preferences.

For testing, it's possible to force Plover to select another language by setting the
`LANGUAGE` environment variable to the desired language code (e.g. `fr` for French).


## For developers

The standard Python package [`gettext`](https://docs.python.org/3/library/gettext.html)
is used for translating strings at runtime. [`Babel`](https://pypi.org/project/Babel/)
is used by the build system for extracting, compiling, and generally managing translations
catalogs.

A {class}`Translator<plover.i18n.Translator>` helper class is provided by {mod}`plover.i18n`. An instance of that
class (configured according to the system locale), is available as {data}`_<plover._>` from
the main package.

This instance can be "called" directly:

```python
from plover import _

print(_("message to be translated"))
```

`_(...)` is a shortcut for `_.gettext(...)`. The plural variant is also
available with `_.ngettext(...)`. Finally, a string can be marked for
translation without translating it using `_._(...)`.

All the user-faced strings of the Qt GUI should be marked for translation. When
formatting a string, `str.format(...)` should be used (avoid `%` interpolation),
and only keyword placeholders should be used.

Rational: this make translating easier (more context), and allow for re-arranging the
arguments (which might be needed depending on the language being targeted).

It's also possible to add a note for the translators with a preceding comment. The format
is as follows:

```python
# i18n: A very important note to translators.
print(_("message to be translated"))
```

All the translations catalogs live under `plover/messages`:
* `plover.pot` is the main catalog, and can be updated using: `python setup.py
  extract_messages` (please make sure UI generated files are up-to-date first
  by running `python ./setup.py build_ui -f`).
* The text-based translations catalog for each supported language lives in
  `{language_code}/LC_MESSAGES/plover.po`
* The corresponding binary catalogs ultimately used at runtime (`{language_code}/LC_MESSAGES/plover.mo`)
  are automatically compiled during the `build` phase, and must not be committed. 
* Strings in the UI generated files are automatically marked.
* You can mark strings that are not translatable in `designer-qt5`: for
  example, the window title of a custom widget will never be seen.


### Setting up Setuptools

See the "i18n" section in `setup.py` for how to use the helpers provided by
`plover_build_utils` to configure Babel and automatically mark strings in
generated UI files.

Note: the helpers expect your main package to make a `Translator` instance
available for sub-modules:

```python
from plover.i18n import Translator

_ = Translator(__package__, resource_dir='messages')
```

Note: don't forget to add `Babel` to your build dependencies (in `pyproject.toml`).


## For translators


### Initial steps

1. Each release provides a *Translations Catalogs* archive, download the one
   corresponding to your version of Plover.
2. Extract the contents of the archive right under Plover's configuration
   folder. The tree should look like this:
   ```
   ${plover_config_folder}/messages
   ├── es
   │   └── LC_MESSAGES
   │       └── plover.po
   ├── fr
   │   └── LC_MESSAGES
   │       └── plover.po
   ├── it
   │   └── LC_MESSAGES
   │       └── plover.po
   └── plover.pot
   ```
3. Download and install [Poedit](https://poedit.net/).


### Creating a new translation

1. Launch Poedit
2. Click on "Create New Translation", navigate to Plover's configuration folder
   and open: `messages/plover.pot`.
3. Select the language you're going to translate to.
4. Click on the save icon: Poedit will propose to name the file according to
   the language code, instead, save the file in `messages/${language_code}/LC_MESSAGES/plover.po`.
   E.g if you're translating to Italian, the file must be saved as `messages/it/LC_MESSAGES/plover.po`.
5. Translate, translate, translate!


### Updating an existing translation

1. Launch Poedit
2. Click on "Edit a Translation", navigate to Plover's configuration folder
   and open the `.po` file corresponding to your language. E.g for Italian,
   the file will be named `messages/it/LC_MESSAGES/plover.po`.
3. In the top menu, click on "Catalog", and then "Update from POT file...":
   navigate to Plover's configuration folder and select `messages/plover.pot`.
4. Translate, translate, translate!


### Testing

Save your translation, and start / restart Plover.


### Tips & Tricks

- You can use "File -> Open config folder" in Plover's menu to easily locate
  its configuration folder. 
- Some translations contain special keyword placeholders that will be replaced
  at runtime: those should be left as is. For example in this translation:
  `{machine} is {state}`, the `{machine}` and `{state}` parts must not be
  translated or removed. However, the order can be changed if necessary.
- Some translations have notes: comments (some of them automatically generated),
  that can help provide more context about the translation. Those notes appear
  in the bottom right of Poedit's interface.
