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

# Localization

> Per-player-locale messages from lang YAML files, with fallbacks so missing translations never crash.

`xyz.refineryteam.refinerycore.api.i18n.Messages` is a per-player-locale message registry backed by YAML files in `<datafolder>/lang/<locale>.yml`. Each player sees messages in their client language automatically, falling back to a default locale and then to the raw key — so a missing translation degrades gracefully instead of crashing.

## Message files

Ship one YAML file per locale inside your plugin jar and save it to the data folder before loading:

```yaml lang/en_us.yml icon="yaml" theme={"system"}
prefix: "<gradient:#A78BFA:#7F77DD>MyPlugin</gradient> <dark_gray>»</dark_gray> "
errors:
  no-permission: "<red>You can't do that."
  not-found: "<red>Player <white>%target%</white> wasn't found."
```

Keys are dotted config paths (`errors.no-permission`), values are MiniMessage strings, and an optional top-level `prefix` entry is prepended by the prefixed send helpers.

## Setup

```java MyPlugin.java icon="java" theme={"system"}
public final class MyPlugin extends JavaPlugin implements RefineryPluginImplementation {

    private Messages messages;

    @Override
    public void onEnable() {
        saveResource("lang/en_us.yml", false);
        saveResource("lang/de_de.yml", false);

        messages = Messages.of(this);
        messages.load();
        messages.setDefaultLocale(Locale.US);
    }
}
```

`load()` reads every `.yml` in the lang folder and can be called again later to pick up edits (e.g. from a reload command). Missing files are left alone — you ship defaults via `saveResource(...)` yourself.

## Sending messages

```java MyCommand.java icon="java" theme={"system"}
// Prefixed with the bundle's "prefix" entry:
messages.sendPrefixed(player, "errors.not-found",
    Placeholder.unparsed("target", name));

// Unprefixed:
messages.send(player, "errors.no-permission");

// Resolve without sending (e.g. for lore or broadcast building):
Component text = messages.component(player, "errors.not-found",
    Placeholder.unparsed("target", name));
```

| Method                                          | Description                                                                                         |
| ----------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `of(plugin)` / `of(plugin, folder)`             | Creates a registry reading from `lang/` (or a custom sub-folder) inside the data folder             |
| `load()`                                        | Loads/reloads every `.yml` in the lang folder                                                       |
| `setDefaultLocale(Locale)`                      | Fallback locale used when a player's locale has no bundle                                           |
| `setLocale(UUID, Locale)` / `clearLocale(UUID)` | Per-player override (e.g. from a `/language` command)                                               |
| `localeFor(Player)`                             | The effective locale: explicit override → client-reported locale → default                          |
| `component(Player, key, resolvers...)`          | Resolves and formats a message as MiniMessage                                                       |
| `send(Audience, key, resolvers...)`             | Sends a message; console audiences get the default locale                                           |
| `sendPrefixed(Audience, key, resolvers...)`     | Same, prepending the bundle's `prefix` entry if present                                             |
| `raw(Player, key)`                              | Resolves without MiniMessage parsing — for plain-text destinations like scoreboard lines or Discord |
| `exists(key)`                                   | Whether the key exists in any loaded bundle                                                         |
| `availableLocales()`                            | All loaded locale codes (e.g. `["en_us", "de_de"]`)                                                 |

## Locale resolution

For each player, `Messages` checks (in order): an explicit per-player override, then the client-reported locale trying a full match (`en_us`) before a language-only match (`en`), then the default locale. Resolution of a key follows the same graceful chain: the player's bundle → the default bundle → the raw key itself.

<Note>
  Pair `Messages` with [`Placeholders`](/refinerycore/placeholders) if you want `%target%`-style tokens resolved globally across plugins — the example above uses inline MiniMessage `TagResolver`s, which need no registration.
</Note>
