Internationalization
RPGJS uses the same i18n shape on the server and the client. Modules can ship default translations, and the game can override them withprovideI18n().
Configure Translations
Translate Gameplay Text
The GUI APIs still receive final strings. Translate explicitly withplayer.i18n() or player.t().
Player Locale
save(), load(), and session
restore keep the selected language.
Module Defaults and Game Overrides
Reusable modules can provide default translations:provideI18n(), the game translation
wins. Use namespaces such as quest.* or my-module.* for module keys.
Client Menus
Built-in RPGJS menus userpg.* 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.
Choosing a language in Options
The built-in Options menu lists only languages registered by the game throughprovideI18n({ messages }). Module/framework catalogues do not add choices. With
no game catalogue, only defaultLocale is listed. Configure the same catalogues
on client and server for both standalone RPG and MMORPG games. RPGJS ships English
and French interface labels; provide rpg.* translations for other game languages.
I18nService.getAvailableLocales() exposes the same game-only list. Language names
use their native spelling. Automatic mode tries each navigator.languages entry
in order: exact locale first, then an available base language (fr-CA → fr).
If none matches, it uses defaultLocale. An unavailable stored choice returns to
automatic mode. Storage is scoped by globalConfig.projectId (or _id, then the
page pathname); assign a unique project id when hosting several games together.
Unavailable browser storage simply makes the preference session-only.
Client getLocale() and t() participate in CanvasEngine reactive computations.
Use computed(() => client.t('menu.title')) for derived labels, not a string
translated once at component creation. Open built-in menus retain their current
selection while their labels change.
The selected language is included in each connection before gameplay join hooks,
and subsequent changes use the player.locale action. The server validates the
locale against its game catalogues (or its configured defaultLocale fallback)
and changes only the sending player’s locale.
Reconnection and room transfers carry the current preference; loading an older
save does not override a connected player’s preference. Future player.t() calls
use it. An already displayed dialogue and literal authored strings are not
automatically retranslated. An offline snapshot still retains its saved locale
until a current connection preference is applied.