> ## 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 and text

> Choose the language a product speaks, reword its text, and add a translation.

Every piece of text an Element Labs product shows to a player comes from a language file inside the
resource. You can change the wording, switch language, or add a language the product does not ship
with, without waiting for a product update.

## Purpose

Player-facing text is kept out of the product itself so that you can own it. A product ships one
file per language it supports, and picks the one your configuration selects.

```text theme={null}
resources/[element]/element_map/
  locales/
    en.json
    it.json
```

Which of those languages the product uses is decided by the `locales` configuration namespace, in
`configs/locales.jsonc`. That file is the only place the choice is recorded.

## Options

### Choosing the language

The active language is a configuration value, in the `locales` namespace:

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

| Key         | Effect                                                                                  |
| ----------- | --------------------------------------------------------------------------------------- |
| `active`    | The language the product uses.                                                          |
| `fallback`  | The language used for any text missing from the active one.                             |
| `available` | The languages the product may use. A language absent from this list cannot be selected. |

Each value is a language code matching a file in `locales`, without the extension: `it` needs
`locales/it.json`.

Set `active` to a language that is not in `available` and the product uses `fallback` instead.
Nothing fails and nothing is reported, so check the spelling against the file names in `locales` if
the language does not change.

The same values apply to every player on the server. There is no per-player language selection.

### How a missing piece of text behaves

Text is looked up by key. Three outcomes, in order:

1. The key exists in the active language: that text is shown.
2. The key is missing from the active language but present in the fallback language: the fallback
   text is shown, in the middle of otherwise translated text.
3. The key is missing from both: the key name itself is shown on screen, for example
   `hud.legend.title`.

A key name appearing in the interface is the visible signature of an incomplete language file. See
[Text is wrong or missing](/support/text-is-wrong-or-missing).

A language file that cannot be read at all (missing, or with a syntax error) is reported once:

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

Every key then falls through to the fallback language, so the interface stays usable in the wrong
language rather than going blank.

### Rewording shipped text

Open the file for the active language and edit the value. Keys are grouped into sections; keep the
structure and change only the text.

```json theme={null}
{
  "hud": {
    "waypoint": "Destination",
    "poi": "Point of Interest"
  }
}
```

Do not rename or remove a key. A key the product looks for and cannot find falls back as described
above; a key you invent is never read.

### Placeholders and plurals

Text can contain placeholders that the product fills in at the moment it is shown. Keep them exactly
as they appear in the shipped text, including their names: a renamed placeholder is filled with
nothing and leaves a gap in the sentence.

| Form                                 | Meaning                                     |
| ------------------------------------ | ------------------------------------------- |
| `{name}`                             | Replaced by the value the product supplies. |
| `{count, number}`                    | The same, stated as a number.               |
| `{count, plural, one {…} other {…}}` | Chooses a wording based on the number.      |

Inside a plural, `#` is replaced by the number itself, and a branch named `=0`, `=1` and so on
covers one exact number:

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

Which branches a language uses is decided by that language's grammar. `one` and `other` cover
English, Italian, Spanish, Portuguese, German and Dutch. French treats zero as `one`. Polish,
Russian and Ukrainian also use `few` and `many`. A language the product has no rules for behaves like
English. Always provide `other`: it is used whenever no other branch matches.

### Adding a language

1. Copy the file of a language the product already ships, for example `locales/en.json`, to
   `locales/<code>.json`.

2. Translate the values. Keep every key, and keep the placeholders unchanged.

3. Add the new file to the `files` block in the resource's `fxmanifest.lua`, beside the language
   files already listed there. Without this line the file stays on the server and never reaches
   players, so the language appears to have no effect.

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

4. Add the code to `available` in `configs/locales.jsonc`, and set `active` to it:

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

   `available` replaces the shipped list rather than adding to it, so include the languages the
   product already has.

5. Restart the resource.

A key you leave untranslated is not empty: it falls back to the fallback language, so a partial
translation is usable while you finish it.

An added language is three edits: the language file, `fxmanifest.lua`, and the configuration. An
update replaces all three. Keep copies of every one of them.

## Example

Switching a product to Italian and rewording one line:

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

```json theme={null}
// locales/it.json
{
  "hud": {
    "waypoint": "Destinazione",
    "poi": "Punto di interesse"
  }
}
```

## Applying changes

Language files and the `locales` configuration are read when the resource starts. Restart the
resource to apply an edit:

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

## Safety

* **Your edits are replaced by an update.** Language files ship inside the release, exactly like
  configuration files. Keep your copies outside the resource directory and restore them after an
  update. See [Update a product or the SDK](/getting-started/updating).
* **A language file that cannot be read yields no text at all** for that language, so every key
  falls back to the fallback language. It reports one warning naming the language. Check for a
  trailing comma or a missing bracket if a translation stops appearing after an edit.
* **`active` and `fallback` must both appear in `available`.** An `active` outside the list uses
  `fallback`; a `fallback` outside the list uses the first language in `available`. Both are silent.
* **Keep the fallback language complete.** It is what fills every gap in every other language, so a
  key missing from it is a key name on screen.

## Related

* [Configuration files](/sdk/configuration): the rules that apply to `configs/locales.jsonc`
* [Text is wrong or missing](/support/text-is-wrong-or-missing)
* [Update a product or the SDK](/getting-started/updating)
