# Internationalization

*Internationalization* (often abbreviated *i18n* since there are 18 characters
between the first "i" and the last "n" in that word) allows Evennia's core
server to return texts in other languages than English - without anyone having
to edit the source code.

Language-translations are done by volunteers, so support can vary a lot
depending on when a given language was last updated. Below are all languages
(besides English) with some level of support. Generally, any language not
updated after Sept 2022 will be missing some translations.

```{eval-rst}

+---------------+----------------------+--------------+
| Language Code | Language             | Last updated |
+===============+======================+==============+
| de            | German               | Aug 2024     |
+---------------+----------------------+--------------+
| es            | Spanish              | Aug 2019     |
+---------------+----------------------+--------------+
| fr            | French               | Dec 2022     |
+---------------+----------------------+--------------+
| it            | Italian              | Oct 2022     |
+---------------+----------------------+--------------+
| ko            | Korean (simplified)  | Sep 2019     |
+---------------+----------------------+--------------+
| la            | Latin                | Feb 2021     |
+---------------+----------------------+--------------+
| pl            | Polish               | Apr 2024     |
+---------------+----------------------+--------------+
| pt            | Portugese            | Oct 2022     |
+---------------+----------------------+--------------+
| ru            | Russian              | Apr 2020     |
+---------------+----------------------+--------------+
| sv            | Swedish              | Sep 2022     |
+---------------+----------------------+--------------+
| zh            | Chinese (simplified) | Oct 2024     |
+---------------+----------------------+--------------+
```

Language translations are found in the [evennia/locale](github:evennia/locale/)
folder. Read below if you want to help improve an existing translation of
contribute a new one.

## Changing server language

Change language by adding the following to your `mygame/server/conf/settings.py`
file:

```python
    USE_I18N = True
    LANGUAGE_CODE = 'en'

```

Here `'en'` (the default English) should be changed to the abbreviation for one
of the supported languages found in `locale/` (and in the list above). Restart
the server to activate i18n.

```{important}

Even for a 'fully translated' language you will still see English text
in many places when you start Evennia. This is because we expect you (the
developer) to know English (you are reading this manual after all). So we
translate *hard-coded strings that the end player may see* - things you
can't easily change from your mygame/ folder. Outputs from Commands and
Typeclasses are generally *not* translated, nor are console/log outputs.

To cut down on work, you may consider only translating the player-facing commands (look, get etc) and leave the default admin commands in English. To change the language of some commands (such as `look`) you need to override the relevant hook-methods on your Typeclasses (check out the code for the default command to see what it calls).
```

```{sidebar} Windows users

If you get errors concerning `gettext` or `xgettext` on Windows,
see the [Django documentation](https://docs.djangoproject.com/en/4.1/topics/i18n/translation/#gettext-on-windows).
A self-installing and up-to-date version of gettext for Windows (32/64-bit) is
available on Github as [gettext-iconv-windows](https://github.com/mlocati/gettext-iconv-windows).

```

## Translating Evennia

Translations are found in the core `evennia/` library, under
`evennia/evennia/locale/`. You must make sure to have cloned this repository
from [Evennia's github](github:evennia) before you can proceed.

If you cannot find your language in `evennia/evennia/locale/` it's because no one
has translated it yet.  Alternatively you might have the language but find the
translation bad ... You are welcome to help improve the situation!

To start a new translation you need to first have cloned the Evennia repository
with GIT and activated a python virtualenv as described on the
[Setup Quickstart](../Setup/Installation.md) page.

Go to `evennia/evennia/` - that is, not your game dir, but inside the `evennia/`
repo itself. If you see the `locale/` folder you are in the right place.  Make
sure your `virtualenv` is active so the `evennia` command is available. Then run

     evennia makemessages --locale <language-code>

where `<language-code>` is the [two-letter locale code](http://www.science.co.il/Language/Codes.asp)
for the language you want to translate, like 'sv' for Swedish or 'es' for
Spanish. After a moment it will tell you the language has been processed.  For
instance:

     evennia makemessages --locale sv

If you started a new language, a new folder for that language will have emerged
in the `locale/` folder. Otherwise the system will just have updated the
existing translation with eventual new strings found in the server. Running this
command will not overwrite any existing strings so you can run it as much as you
want.

Next head to `locale/<language-code>/LC_MESSAGES` and edit the `**.po` file you
find there. You can edit this with a normal text editor but it is easiest if
you use a special po-file editor from the web (search the web for "po editor"
for many free alternatives), for example:

- [gtranslator](https://wiki.gnome.org/Apps/Gtranslator)
- [poeditor](https://poeditor.com/)

The concept of translating is simple, it's just a matter of taking the english
strings you find in the `django.po` file and add your language's translation best
you can. Once you are done, run

    evennia compilemessages

This will compile all languages. Check your language and also check back to your
`.po` file in case the process updated it - you may need to fill in some missing
header fields and should usually note who did the translation.

When you are done, make sure that everyone can benefit from your translation!
Make a PR against Evennia with the updated `django.po` file. Less ideally (if git is
not your thing) you can also attach it to a new post in our forums.

### Hints on translation

Many of the translation strings use `{ ... }` placeholders. This is because they
are to be used in `.format()` python operations. While you can change the
_order_  of these if it makes more sense in your language, you must _not_
translate the variables in these formatting tags - Python will look for them!

    Original: "|G{key} connected|n"
    Swedish:  "|G{key} anslöt|n"

You must also retain line breaks _at the start and end_ of a message, if any
(your po-editor should stop you if you don't). Try to also end with the same
sentence delimiter (if that makes sense in your language).

    Original: "\n(Unsuccessfull tried '{path}')."
    Swedish: "\nMisslyckades med att nå '{path}')."

Finally, try to get a feel for who a string is for. If a special technical term
is used it may be more confusing than helpful to translate it, even if it's
outside of a `{...}` tag. A mix of English and your language may be clearer
than you forcing some ad-hoc translation for a term everyone usually reads in
English anyway.

    Original: "\nError loading cmdset: No cmdset class '{classname}' in '{path}'.
               \n(Traceback was logged {timestamp})"
    Swedish:  "Fel medan cmdset laddades: Ingen cmdset-klass med namn '{classname}' i {path}.
               \n(Traceback loggades {timestamp})"

## Marking Strings in Code for Translation

If you modify the Python module code, you can mark strings for translation by passing them to the `gettext()` method. In Evennia, this is usually imported as `_()` for convenience:

```python
from django.utils.translation import gettext as _
string = _("Text to translate")
```

### Formatting Considerations

When using formatted strings, ensure that you pass the "raw" string to `gettext` for translation first and then format the output. Otherwise, placeholders will be replaced before translation occurs, preventing the correct string from being found in the `.po` file. It's also recommended to use named placeholders (e.g., `{char}`) instead of positional ones (e.g., `{}`) for better readability and maintainability.

```python
# incorrect:
string2 = _("Hello {char}!".format(char=caller.name))

# correct:
string2 = _("Hello {char}!").format(char=caller.name)
```

This is also why f-strings don't work with `gettext`:

```python
# will not work
string = _(f"Hello {char}!")
```
