> ## Documentation Index
> Fetch the complete documentation index at: https://docs.elementlabs.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Languages

> How a product picks its language, how to reword its text, and how to add a translation.

Every piece of text a product shows comes from a language file in its `locales` folder, one file per
language. You can reword any text, and add a language the product does not ship, without waiting for
an update.

## How a product picks its language

Each product works in one of two ways. Its configuration overview says which.

| The product | How the language is chosen | `configs/locales.jsonc` |
| - | - | - |
| **Follows each player's game** | Each player sees the language set in their game's settings, and the text switches within a second when they change it. A player whose language the product does not ship sees English. You can add languages the game does not have and choose the one players start in; each player can still pick another one. | Present, with `default` and `extra`. Both can be left as they ship. |
| **Uses one language for the server** | You choose the language in `configs/locales.jsonc`, and every player sees it. | Present, with `active`, `fallback` and `available`. |

## Before you start

* The language files are in the product's folder, for example
  `resources/[element]/element_3d_pausemenu/locales/en.json`.
* Keep a copy of every file you change. An update replaces them. See
  [Update a product](https://docs.elementlabs.net/get-started/update.md).

## Steps

### Choose the server's language

For a product that uses one language for the server:

```jsonc theme={null}
{
  "namespace": "locales",
  "configVersion": 1,
  "scope": "shared",
  "values": {
    "active": "it"
  }
}
```

| Key | Meaning |
| - | - |
| `active` | The language every player sees. |
| `fallback` | The language used for any text missing from `active`. |
| `available` | The languages the product may use. A language not in this list cannot be chosen. |

Each value is the name of a file in `locales` without `.json`: `it` means `locales/it.json`. Restart
the resource to apply it.

### Choose the language players start in, and add the server's own

For a product that follows each player's game, `configs/locales.jsonc` holds what the game cannot
offer: languages it does not have, such as Swedish, and the language a player sees before they have
picked one.

```jsonc theme={null}
{
  "namespace": "locales",
  "configVersion": 1,
  "scope": "client",
  "values": {
    "default": "sv",
    "extra": {
      "sv": "Svenska"
    }
  }
}
```

| Key | Default | Meaning |
| - | - | - |
| `default` | `"game"` | The language a player sees until they pick one: `"game"` for the language their game is set to, or the name of a language file, one of the game's or one in `extra`. |
| `extra` | `{}` | Languages the game does not have, as the name of the language file and the name players see in the list, written in that language. |

Every player can still change the language from the product's own settings. Their pick is kept on
their own machine, for this server, and wins over `default` from then on, including when you change
`default` later. Picking the language their game is in makes the product follow the game again.

A language in `extra` changes only the product's own text. The game has no Swedish to switch to,
so its own menus stay in the language the game is set to.

Each language in `extra` needs its file in `locales`, listed in `fxmanifest.lua`; see
[Add a language](#add-a-language). Restart the resource to apply a change.

### Reword a piece of text

Open the file for the language players see and change the text after the colon. Keep the key, the
quotes and the braces as they are:

```json theme={null}
{
  "map": {
    "waypoint": "Destination"
  }
}
```

Text can contain placeholders the product fills in, such as `{count}` or `{name}`. Keep them, with
the same names. A renamed placeholder is replaced with nothing and leaves a gap in the sentence.

Some text changes with a number:

```json theme={null}
{
  "map": {
    "markers": "{count, plural, =0 {No markers} one {# marker} other {# markers}}"
  }
}
```

`#` is the number. `=0` matches exactly zero. `one` and `other` are chosen by the language's grammar:

| Language | Forms it uses |
| - | - |
| English, German, Dutch, Italian, Spanish, Portuguese | `one` for 1, `other` for the rest |
| French | `one` for 0 and 1, `other` for the rest |
| Polish | `one` for 1, `few` for 2 to 4 (but not 12 to 14) and numbers ending in them, `many` for the rest |
| Russian, Ukrainian | `one` for numbers ending in 1 (but not 11), `few` for those ending in 2 to 4 (but not 12 to 14), `many` for the rest |
| Any other language | the same as English |

Always keep `other` in a plural.

### Add a language

**1. Copy a language file**

Copy `locales/en.json` to a new file named after the language.

For a product that **follows the player's game**, use the game's own name for one of its
languages, so that players whose game is in it see it:

| Game language | File |
| - | - |
| English | `en.json` |
| French | `fr.json` |
| German | `de.json` |
| Italian | `it.json` |
| Spanish | `es.json` |
| Spanish (Mexico) | `es-mx.json`. Without it, players on Mexican Spanish see `es.json`. |
| Portuguese (Brazil) | `pt.json` |
| Polish | `pl.json` |
| Russian | `ru.json` |
| Korean | `ko.json` |
| Japanese | `ja.json` |
| Chinese (Traditional) | `zh-tw.json` |
| Chinese (Simplified) | `zh-cn.json` |

Any other language is one of the server's: name the file after it, such as `sv.json` for
Swedish, and add it to `extra` in a later step.

**2. Translate the text**

Translate the text after each colon. Keep every key and every placeholder. A key you have not
translated yet shows the fallback language, so a half-finished file is usable.

**3. List the file in fxmanifest.lua**

Add it to the `files` block in the product's `fxmanifest.lua`, next to the language files already
there:

```lua theme={null}
files {
  "locales/en.json",
  "locales/fr.json",
}
```

Without this line the file never reaches players, and the language seems to do nothing.

**4. Make it available, for a product that uses one language for the server**

In `configs/locales.jsonc`, add it to `available` and, to use it, set `active`. `available`
replaces the shipped list, so keep the languages already in it:

```jsonc theme={null}
{
  "namespace": "locales",
  "configVersion": 1,
  "scope": "shared",
  "values": {
    "active": "fr",
    "available": ["en", "fr"]
  }
}
```

A product that follows the player's game reads only `extra` and `default` there: skip this step
for a game language.

**5. Add it to extra, for a server language of a product that follows the player's game**

In `configs/locales.jsonc`, add the file's name and the name players see, and set `default` to it
if players should start in it:

```jsonc theme={null}
{
  "namespace": "locales",
  "configVersion": 1,
  "scope": "client",
  "values": {
    "default": "sv",
    "extra": {
      "sv": "Svenska"
    }
  }
}
```

**6. Restart the resource**

```text theme={null}
restart element_3d_pausemenu
```

## Check that it worked

Join the server and confirm the text is in the expected language everywhere, with no key names such
as `map.waypoint` on screen and no gaps in sentences. Look at a screen that shows a count too, so the
plural forms are covered.

## When text is missing

Text is looked up by its key in three places, in order:

1. the language the player sees;
2. the fallback language: English for a product that follows the player's game, `fallback` for one
   that uses one language for the server;
3. nowhere: the key itself appears on screen, for example `map.waypoint`.

A key name on screen means a key is missing from the fallback language too. Keep the fallback
language complete: it fills every gap in every other language.

A language file that cannot be read, because of a syntax error, yields no text at all, and every key
falls back. The console says so once:

```text theme={null}
[WARN ] [   Locales] Locale file for "fr" is missing or invalid.
```

The usual cause is a comma after the last entry or a missing quote. Language files are plain JSON,
not `.jsonc` like configuration files: leave comments out of them.

For a product that follows each player's game, an entry that cannot work is left out and the console
says why, once per start:

```text theme={null}
[WARN ] [   Locales] extra "sv" in configs/locales.jsonc ignored: locales/sv.json is missing, invalid, or not listed in files in fxmanifest.lua.
```

The other entries still apply. The messages are listed in
[Console messages](https://docs.elementlabs.net/troubleshooting/console-messages.md#configuration-and-language-files).

For a product that uses one language for the server, two choices fail without a message:

* an `active` that is not in `available` uses `fallback` instead;
* a `fallback` that is not in `available` uses the first language in `available`.

More symptoms and their fixes are in [Text is wrong or missing](https://docs.elementlabs.net/troubleshooting/text-is-wrong.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.