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

# Internationalization

> Provide translations for server gameplay text, client menus, and reusable modules.

# Internationalization

RPGJS uses the same i18n shape on the server and the client. Modules can ship
default translations, and the game can override them with `provideI18n()`.

## Configure Translations

```ts theme={null}
// src/i18n.ts
export default {
  defaultLocale: "fr",
  fallbackLocale: "en",
  messages: {
    fr: {
      "npc.guard.hello": "Bonjour {name}",
      "choice.fight": "Combattre",
      "rpg.menu.items": "Objets"
    },
    en: {
      "npc.guard.hello": "Hello {name}",
      "choice.fight": "Fight",
      "rpg.menu.items": "Items"
    }
  }
}
```

Use the same config on both sides when the game needs translated gameplay text
on the server and translated local UI on the client.

```ts theme={null}
// src/server.ts
import { createServer, provideI18n, provideServerModules } from "@rpgjs/server"
import i18n from "./i18n"

export default createServer({
  providers: [
    provideI18n(i18n),
    provideServerModules([])
  ]
})
```

```ts theme={null}
// src/config.client.ts
import { provideI18n, provideClientModules } from "@rpgjs/client"
import i18n from "./i18n"

export default {
  providers: [
    provideI18n(i18n),
    provideClientModules([])
  ]
}
```

## Translate Gameplay Text

The GUI APIs still receive final strings. Translate explicitly with
`player.i18n()` or `player.t()`.

```ts theme={null}
async onAction(player) {
  const { t } = player.i18n()

  await player.showText(t("npc.guard.hello", {
    name: player.name
  }))

  const choice = await player.showChoices(t("npc.guard.question"), [
    { text: t("choice.fight"), value: "fight" },
    { text: t("choice.run"), value: "run" }
  ])
}
```

## Player Locale

```ts theme={null}
player.setLocale("fr")
player.getLocale()
```

The locale is stored in the player snapshot, so `save()`, `load()`, and session
restore keep the selected language.

## Module Defaults and Game Overrides

Reusable modules can provide default translations:

```ts theme={null}
export const QuestModule = {
  server: {
    i18n: {
      en: {
        "quest.accepted": "Quest accepted"
      },
      fr: {
        "quest.accepted": "Quête acceptée"
      }
    }
  },
  client: {
    i18n: {
      en: {
        "quest.menu.title": "Quest Log"
      },
      fr: {
        "quest.menu.title": "Journal de quêtes"
      }
    }
  }
}
```

If the game provides the same key through `provideI18n()`, the game translation
wins. Use namespaces such as `quest.*` or `my-module.*` for module keys.

## Client Menus

Built-in RPGJS menus use `rpg.*` keys internally, such as `rpg.menu.items` and
`rpg.save.title`. Override these keys in the game config to rename or translate
the default menus.
