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

# Localization

> Translate every label at runtime. English is the source, and you only list what you change.

Copy resolves through the localization layer, while data like numbers, keys, and hex codes is left alone. English is the source, and each English string is its own key, so a translation table only lists the strings you change. Anything you skip stays in English, and a regional id like `pt-br` beats the bare `pt`.

With no `locale` given, the window follows the player's Roblox language on its own.

## Translation tables

Pass tables keyed by locale id.

```lua theme={null}
Rayfield:CreateWindow({
    name = "Example",
    translations = {
        fr = { ["Auto Sprint"] = "Sprint auto", ["Signed in as"] = "Connecté en tant que" },
        es = { ["Auto Sprint"] = "Sprint automático" },
    },
})
```

Switch languages live, with no rebuild.

```lua theme={null}
window:SetLocale("fr")
```

Add a pack at runtime.

```lua theme={null}
window:RegisterTranslations({ de = { ["Auto Sprint"] = "Auto-Sprint" } })
```

## A custom resolver

To resolve copy yourself, pass a `translator`. It is a function `(source, localeId)` that returns a string, or `nil` to fall through to the tables. It is checked first, so it wins.

```lua theme={null}
Rayfield:CreateWindow({
    name = "Example",
    translator = function(source, localeId)
        return myTranslationService(source, localeId)  -- or nil to fall back
    end,
})
```

Swap it at runtime with `window:SetTranslator(fn)`, then re-apply the locale to refresh the screen.
