# Localization

> Translate UI, story text and script messages with per-language string tables and a player-facing language picker.

Source: https://feather-engine.com/docs/presentation/localization/

Localization keeps one string table per project. Each key holds a text per language. UI markup, story
text and built-in screen templates refer to keys with `@{key}`, and scripts look them up with `tr`.
Players choose their language in the pause menu.

## Set up languages and strings

1. Open **Window → Localization**.
2. Under **Languages**, click **Add language** and enter a code such as `en`, `it`, `de` or `ja`.
3. Click a language to make it the default. The default is used when a translation is missing.
4. Click **Add key**, name it, and type its text in each language column.

New projects start with one language, `en`, which is also the default.

## Use keys

| Where | Syntax |
| --- | --- |
| [Game UI](/docs/presentation/game-ui/) markup, screen templates and [story](/docs/gameplay/story/) text | `@{key}` |
| Scripts | `tr("key")` |

```html
<panel class="menu">
  <h1>@{menu.title}</h1>
  <button onclick="start">@{menu.start}</button>
</panel>
```

Text is resolved in the player's language. If that language has no text for the key, the default
language is used; if the default has none either, the key itself is shown.

### Placeholders

`tr(key, map)` fills `{name}` placeholders in the text from a map:

```rust
// The key "greeting" holds "Welcome back, {name}" in en.
fn start() {
    toast(tr("greeting", #{ name: "Ada" }));
}
```

## Language picker

When a project has more than one language, the pause menu's **Settings** shows a **Language** row with
every language code. The player's choice is saved.

## Script API

| Function | Description |
| --- | --- |
| `tr(key)` | The text for a key in the current language |
| `tr(key, map)` | The same, with `{name}` placeholders filled from the map |
| `set_language(code)` | Switches the language |
| `language()` | The current language code |
| `languages()` | Every language code in the project |

## Limits

| Limit | Value |
| --- | --- |
| Languages | 1 to 64 |
| Language codes | 1 to 16 letters, digits, `-` or `_` |
| String keys | 50,000 |
| Key length | 1 to 128 characters, without `}` |

## Automate it

| Command | Purpose |
| --- | --- |
| `localization.get` | Languages, the default, strings and the keys each language is missing. `language` resolves every string for one language; `prefix` filters keys |
| `localization.set` | Sets the language list and the default language |
| `localization.upsert` | Adds or changes translations; an empty text removes one |
| `localization.remove` | Deletes keys |

Add Italian and translate two menu strings:

```bash
feather-cli --connect .feather-session.json command localization.set \
  --json '{"languages":["en","it"],"default_language":"en"}'

feather-cli --connect .feather-session.json command localization.upsert --json '{
  "strings": {
    "menu.title": {"en": "Main menu", "it": "Menu principale"},
    "menu.start": {"en": "Start", "it": "Inizia"}
  }
}'
```

Use `localization.get` to list the keys each language is still missing. See
[Agents & automation](/docs/agents/overview/) for connecting a live session.
