# Translations

koja-mdt ships with 22 languages. Both the in-game messages and the whole tablet interface are translated.

| Code | Language | Code | Language |
|---|---|---|---|
| `en` | English | `ro` | Romanian |
| `pl` | Polish | `hu` | Hungarian |
| `de` | German | `sv` | Swedish |
| `fr` | French | `da` | Danish |
| `es` | Spanish | `fi` | Finnish |
| `pt` | Portuguese | `no` | Norwegian |
| `it` | Italian | `lt` | Lithuanian |
| `nl` | Dutch | `el` | Greek |
| `cs` | Czech | `bg` | Bulgarian |
| `sk` | Slovak | `ru` | Russian |
| `uk` | Ukrainian | `tr` | Turkish |

## How it works

Each language is one file, `locales/<code>.json`, with two sections:

```json title="locales/en.json"
{
  "game": { "notify": { "no_access": "You don't have access to the MDT." } },
  "ui":   { "voice": { "title": "Dispatcher voice" } }
}
```

- `game` holds texts shown by the Lua scripts: notifications, keybind names, chat suggestions, the ticket book labels.
- `ui` holds all texts of the tablet interface and the web portal.

Missing keys fall back to English, key by key, so a partial translation is safe. The `locales/fragments/` folder holds the translations split by topic. The resource itself only loads `locales/<code>.json`.

Texts that take values use format markers such as `%s` and `%d` in `game` and `{n}` style placeholders in `ui`. Keep them unchanged.

## Server language

Set the default for everyone:

```lua title="shared/config.lua"
Config.Locale = 'pl'
```

If the file for that code does not exist, English is used.

## Per-player language

By default every player can choose their own language in Settings, Language:

```lua title="shared/config.lua"
Config.Languages = {
    playerChoice = true,   -- set to false to force Config.Locale for everyone
    offered = {},          -- empty offers all languages; or { 'en', 'pl', 'de' } to limit the list
}
```

The choice is stored in the officer's settings in the database (`koja_mdt_officers.settings`) and applies to:

- the MDT interface and the web portal;
- the notifications the server sends to that player (duty on and off, access errors and similar).

Clearing the personal choice returns the player to the server default. If `playerChoice` is `false`, everyone sees `Config.Locale`. The server default code is always offered, even when it is not in the `offered` list.

## Editing a translation

1. Open `locales/<code>.json`.
2. Change the text values. Do not rename keys.
3. Restart `koja-mdt`.

To add or fix only a few texts, you can keep other keys untouched. Anything you remove falls back to English.

## Adding a language

1. Copy `locales/en.json` to `locales/<code>.json`, using a code made of letters, digits, `_` or `-`.
2. Translate the values in both `game` and `ui`.
3. Set `Config.Locale = '<code>'`.
4. Restart `koja-mdt`.

:::hint{type="warning" title="Limit of custom languages"}
The language picker in Settings lists the 22 built in codes plus your server default. A new code you add yourself works as the server language, but players cannot switch to it from the picker unless it is the server default, because the list of selectable codes is part of the escrowed `shared/locale.lua`. If you want a language added to the picker, ask for it as a feature request.
:::

## Dispatcher voice language

The spoken dispatcher uses its own clips and is set separately with `Config.DispatchVoice.language`. Clips ship for English (`en`) and Polish (`pl`), with shared clips for the phonetic alphabet, districts and streets. A missing clip falls back to the browser's speech synthesis if a voice exists for the language. See `Config.DispatchVoice` in [Configuration](/new/mdt/configuration).

## Date, time and currency

These come from `Config.Ui` (`dateLocale`, `clockFormat`, `currency`), not from the translation files.
