.. _i18n:

# Internationalization

RiskScape has built-in support for Internationalization (or *i18n*, as shorthand). This support allows users to use RiskScape in their
native language (where available).

The Internationalization support in RiskScape is extensible, so you can add new translations if a
particular language is not yet supported. This also allows you to override the default RiskScape
messages and use a more domain-specific language, for example if you wanted to customize RiskScape
for a specific subset of users.

## Language selection

RiskScape uses Java's built-in internationalization support, but with a few extensions.  RiskScape uses your system's
locale settings to search for the most applicable messages.  A more detailed explanation of this system is published on
[Oracle's Java Documentation](https://docs.oracle.com/javase/8/docs/technotes/guides/intl/index.html)

RiskScape's extensions to this system allow you to provide your own set of translations
(known as a *Resource Bundle*). The next section explains how to do this.

## Translating RiskScape

RiskScape's internationalization support uses plain-text (UTF8-encoded) files, called Resource Bundles.
These files contain the text for all user-facing messages in RiskScape.
Each message is identified by a unique code, e.g.

```text
riskscape.cli.usage = Welcome To RiskScape
# ^ the code          ^ the message
```

### Quick-start

- Locate the `i18n` directory in your RiskScape installation directory.
- Run `riskscape i18n --locale es_US --output-dir wip-dir` substituting locale and directory as you want.
- Translate the message text in the generated files.
- Copy these translations into the `i18n` RiskScape installation directory.
- Test the translations by running RiskScape with the `user.language` and `user.country` settings as below or by
  changing your system's locale.

### Generating translatable messages

The `i18n` sub-command generates resource bundle (`.properties`) files that contain all
of the messages codes in RiskScape, ready for translation.

```none
riskscape i18n --output-dir=working-dir-for-translation --locale es_US
```

The default message text (i.e. English) is used in the generated files initially.
You can now go through and modify the message text as needed.
Note that it is important that you do not change the codes - only change the message text.

For help determining the appropriate `--locale` value to use, see
[Java 8 supported locales](https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html).
Note that you only need to specify the country portion of the locale if there are regional dialects
of the language you're working with. Otherwise, it's simplest just to use the language portion
of the locale. For example, if translating to Japanese, you can just use `--locale=ja` rather than
`--locale=ja_JP`.

To test your translations, copy your modified resource bundle (i.e. `.properties`) files into RiskScape's `i18n` directory.
If your system locale is already set to the target language, your new translations should appear when you run RiskScape, i.e. `riskscape --help`.

Alternatively, if your system locale is not set to your target language, you can override the setting when you run RiskScape.
For example, to set the locale that RiskScape uses to ``es_US``, enter the following into your terminal prompt:
- ``set JAVA_TOOL_OPTIONS=-Duser.language=es -Duser.country=US`` (Windows Command Prompt)
- ``$env:JAVA_TOOL_OPTIONS="-Duser.language=es -Duser.country=US"`` (Windows PowerShell)
- ``export JAVA_TOOL_OPTIONS='-Duser.language=es -Duser.country=US'`` (Linux/Docker)

Then run `riskscape --help` to see your translations.

.. tip::
  For more background on what setting the locale via ``JAVA_TOOL_OPTIONS`` is
  actually doing, refer to :ref:`java_options`.

### Resource bundles

RiskScape uses four different resource bundles for messages:

* `help` - help text that describes how to use various parts of the RiskScape engine. For example,
 the descriptions displayed by `riskscape model info default` come from this file.

* `cli-help` - help text for the various the RiskScape command line options. For example,
`riskscape --help` uses the text from this file.

* `problems` - text for reporting problems back to users to help them progress. For example,
running an invalid command like `riskscape pipeline run bad-id` results in an error message that's
translatable.

* `labels` - various labels for objects in RiskScape, e.g. what to call things when they're printed out in the user
  interface. This includes the table headings such as *id* and *description* for commands like `riskscape model list`.

Aside from the pointers listed here, In depth details of Resource Bundles can be found in the link to [Java's
Internationalization documentation](https://docs.oracle.com/javase/8/docs/technotes/guides/intl/index.html).

### Resource bundle filenames

Resources bundles use the Java properties file format, and follow a few rules for how they are named.  The name of the
file is important, as it contains [locale](https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html)
information that dictates how RiskScape will use it.
To add label translations for American English, the file would need
to be named `labels_en_US.properties`.  To add translations for American Spanish, the file would need to be named
`labels_es_US.properties`. To add translations for Spanish that aren't country-specific,
the file would need to be named `labels_es.properties`.

### Message selection

RiskScape applies the following rules when deciding what text to display for a message:

* The most specific message that can be found for your locale will be used.
  For example, RiskScape will check for a language *and* country match (e.g. `es_US`) first before it
  tries to find just a language match (e.g. `es`).
* If no match for your locale was found, RiskScape falls back to using the default locale (i.e. English).
* If there are multiple matches for a message (i.e. you have added your own translation, and a message
  for the locale also exists in the built-in RiskScape code), then the user-provided translation will win.
* If you are using RiskScape plugins, then the plugin's message takes takes priority over the core/built-in
  RiskScape translations, but any user-provided translations will still win.
  Behaviour is undefined if the same message exists across multiple plugins.

Future versions of RiskScape may also allow translations to be provided from further external file locations.

### Example using Windows

#### Terminal setup

First, open up a terminal prompt. We recommend using Windows Command Prompt.
Note that PowerShell requires more setup steps in order to display UTF-8 characters correctly.

Check the system locale that your terminal is using.

```text
java -XshowSettings:locale .
```

If your current locale is not the target language you are translating to, then you have two options. Either:
- Change the [Windows system locale](https://java.com/en/download/help/locale.xml).
- Change the locale that Java uses, i.e. enter the following command:

  ```text
  set JAVA_TOOL_OPTIONS="-Duser.language=es -Duser.country=US"
  ```

Re-run `java -XshowSettings:locale .` and check the locale now matches what you are translating.

Next, check the [Windows code page](https://en.wikipedia.org/wiki/Windows_code_page)
that is currently set in the terminal. Enter `chcp` and it will display a number, e.g. 850.
Refer to the [Windows documentation](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-ucoderef/28fefe92-d66c-4b03-90a9-97b473223d43)
for a list of supported code pages, and what these numbers mean.

RiskScape will set the console's code page to 65001 by default, which is UTF-8 encoding.
You can also set this by entering the command:
```text
chcp 65001
```

Now is a good time to check that any special characters in your target language will be
displayed correctly in the terminal. Create a new file in whatever plain-text editor
you prefer to use (e.g. Notepad). Add any characters that are specific to your target language
(e.g. `ā é î õ ü`) and save the file as `temp.txt`. Then from the terminal, display the file using:
```text
more temp.txt
```

They should hopefully be displayed correctly. For contrast, you could temporarily change `chcp`
back to its original setting and see the difference it makes.

.. warning::
  RiskScape output will use UTF-8 encoding by default. If the 65001 code page (UTF-8)
  is not suitable for your target language for some reason, then you will need to override
  RiskScape's default encoding. To change the file encoding that RiskScape uses
  (to code page 1252 in this example) use the following command:
  ``set RISKSCAPE_OPTS=-Dfile.encoding=cp1252``

#### Create the translation files

Create a working-directory folder to do the translations in.
This example will use `C:\RiskScape_Projects\US_Spanish`.

Then create the RiskScape resource bundle files for your target locale. 

```text
riskscape i18n --locale es_US --output-dir C:\RiskScape_Projects\US_Spanish
Picked up JAVA_TOOL_OPTIONS: -Duser.language=mi -Duser.country=NZ
Wrote 124 keys for help
C:\RiskScape_Projects\US_Spanish\help_es_US.properties
Wrote 12 keys for labels
C:\RiskScape_Projects\US_Spanish\labels_es_US.properties
Wrote 60 keys for problems
C:\RiskScape_Projects\US_Spanish\problems_es_US.properties
Wrote 102 keys for cli-help
C:\RiskScape_Projects\US_Spanish\cli-help_es_US.properties
```

.. tip::
  Make sure your target locale is already set in your terminal *before* running this command.
  That way, any existing translations in RiskScape will be preserved.
  For example, if there were already some Spanish translations in RiskScape, then
  these would be retained in the files generated.

Open the properties files in a plain-text editor (e.g. Notepad) and start translating the
message text.

.. note::
    Although the files are plain-text, there are still some syntax rules you need to be careful with.
    Otherwise your translated message may not be displayed correctly.

    * Do not alter the message code (the bit on the left-hand side of the ``=``).
    * If the translated text spans multiple lines, the last character on each line **must** be a backslash, i.e. ``\``.
    * Some characters, like single-quotes (``'``) are *escape* characters. This means you always need to use *two* single-quotes (``''``) where you want one single-quote (``'``) displayed in the message.

#### Test the translations

In order for RiskScape to use your translated text, your resource bundle files need to
be added to the `i18n` sub-directory in the RiskScape installation directory.

If you followed the installation instructions, this directory will be `C:\RiskScape\riskscape\i18n\`.
If you are unsure where your RiskScape installation directory is, the :ref:`upgrade`
instructions have some tips.

Copy your translated resource bundle files into the installation directory. E.g. 

```text
copy C:\RiskScape_Projects\US_Spanish\*.properties C:\RiskScape\riskscape\i18n\
```

Now when you run a RiskScape command, such as `riskscape --help` or `riskscape model info default`,
your should see your translated text appear.

As you add more message translations, remember to copy the updated `.properties` files into
the RiskScape installation `i18n` sub-directory.
Alternatively, you could modify the files in the `i18n` folder directly, but it is a good idea
to still keep a backup copy of your work somewhere.

.. tip::
  If you install a new version of RiskScape, you will need to copy your translated ``.properties``
  files into the ``i18n`` folder again. To avoid having to do this, we recommend
  :ref:`commit_translations` back to the RiskScape codebase.

.. note::
  You do not have to translate *every* single message in the resource bundle.
  However, when you are finished, please delete any untranslated message/code pairs
  from the resource bundle files.
  RiskScape will display the default (i.e. English) text for any messages that are missing
  from your resource bundle.

### Example using Docker

Note that if you are using a RiskScape docker image to generate the i18n files, then you'll need to
mount the directory you're working in as a volume. Otherwise any modifications you make to the i18n
files will be lost when you exit the docker session.

For example, to run the RiskScape docker image (on Linux) and mount your current working directory as a volume, use:
```none
docker run --rm -it -v$PWD:/home/riskscape/i18n riskscape-cli
```

For a Windows user, the same command would look like:
```none
docker run --rm -it -v%cd%:/home/riskscape/i18n riskscape-cli
```

Next, create the i18n resource bundle files in the directory you mounted:
```none
riskscape i18n --locale es_US --output-dir /home/riskscape/i18n
chmod o+w /home/riskscape/i18n/*.properties
```

By default, any files that were created within a docker session are read-only.
The second `chmod` command makes the resource bundle files writable for any user.
This means you can edit the i18n files from outside the docker session,
using your editor of choice.

Once you have made changes to resource bundle files, in your docker session
copy the edited files into the RiskScape installation directory:

```none
cp /home/riskscape/i18n/*.properties /opt/riskscape-cli/i18n/
```

Then to test the translations, make sure your locale is set appropriately
and run a `riskscape` command to display the help text, e.g.

```none
export JAVA_TOOL_OPTIONS='-Duser.language=es -Duser.country=US'
riskscape --help
```

.. _commit_translations:

### Committing completed translations

Once you have completed your translation, we recommend committing your translated
text back to the RiskScape codebase. To do so, you can simply email your resource
bundle files to riskscape-dev@catalyst.net.nz.

The reason we recommend this is because future changes to the RiskScape code may alter
the message codes in the resource bundle files. If this happens, then some of your
translated text may no longer be displayed correctly on future versions of RiskScape.

If your translations are committed to the RiskScape codebase, then the resource
bundle files will live alongside the RiskScape code. This means that if a i18n message
code changes in future, then your resource bundle files will also be updated, and
your translation will continue to work.
