# Localization

> Translate an Envy game UI with keyed text and per-language tables, preview a pseudo-locale to catch clipping, export CSV for translators and switch language at runtime.

Source: https://envyui.com/docs/localization

A text layer opts into translation with a **key**. Its content is the text in the base language; tables hold the other languages.

```json
"i18n": {
  "base": "en",
  "tables": {
    "de": { "title.press": "Beliebige Taste drücken" },
    "fr": { "title.press": "Appuyez sur une touche" }
  }
}
```

```json
"text": { "content": "Press any button", "key": "title.press" }
```

- Translations can use data templates like `{player.name}` and list templates like `{item.name}`.
- A missing translation shows the base text.
- Locales match exactly first, then by language: `de-AT` finds `de`, `pt` finds `pt-BR`.
- **pseudo** shows accented text about 35% longer than the base, so you find clipping before real translations arrive.

## In the editor

The Data panel's Languages tab adds locales, shows a table per locale and generates keys for all text. Export CSV for translators and import it back. The canvas and preview can show any locale or the pseudo-locale, and typing on the canvas while a locale is shown edits that translation.

## At runtime

```gdscript
ui.locale = TranslationServer.get_locale()
ui.set_locale("de")
```

```js
const ui = Envy.mount(host, doc, { locale: navigator.language });
ui.setLocale("fr");
```

Switching rebuilds the open screens in place and keeps data, overlays and focus. The Last Hunt's title screen is translated into German, French, Spanish and Brazilian Portuguese; switch language in the [live demo](/#play).

Text that shows a component property (`{prop.Label}`) isn't translated by key: translate the value the instance sets instead.
