Localization
Localization is configured in the creator via Game / Locales.
Locale data uses TOML. Each top-level table is one language, for example [en], [de], or [fr].
Format
[en]
combat.damage.incoming = "{attacker} hits you for {amount} damage"
combat.damage.outgoing = "You hit {defender} for {amount} damage"
system.cant_do_that_yet = "Can't do that yet"
system.cant_afford = "You can't afford that"
system.you_bought = "You bought"
system.exit_menu = "Goodbye"
[de]
combat.damage.incoming = "{attacker} trifft dich fuer {amount} Schaden"
combat.damage.outgoing = "Du triffst {defender} fuer {amount} Schaden"
system.cant_do_that_yet = "Das geht noch nicht"
system.cant_afford = "Du kannst dir das nicht leisten"
system.you_bought = "Du hast gekauft"
system.exit_menu = "Auf Wiedersehen"
The active locale is selected in Game / Settings:
[game]
locale = "en"
Use locale = "auto" to follow the system locale.
Key Names
Use namespaced keys.
system.*: built-in runtime and UI stringscombat.*: combat-related text- your own domains like
quest.*,dialog.*,merchant.*,ui.*
This keeps project strings organized and avoids collisions.
Built-in System Keys
The currently used built-in system keys are:
system.cant_do_that_yetsystem.cant_affordsystem.you_boughtsystem.exit_menu
These are used by server/client systems directly, so they should exist in every supported locale.
Message Resolution
Localized text is resolved by key first, then placeholders inside the final string are filled.
Example:
[en]
combat.damage.outgoing = "You hit {defender} for {amount} damage"
If rules reference combat.damage.outgoing, the runtime first loads that locale string, then replaces placeholders like:
{attacker}{defender}{amount}{kind}{from_id}{target_id}
For your own custom message(...) calls, you can pass named parameters on the locale key itself.
Example locale entry:
[en]
dialog.hit = "You hit {target} for {amount} damage"
Example script message:
message(id(), "{dialog.hit,target=target.class_name,amount=N:3}", "system")
Supported parameter value forms:
E:<id>.<attr>for entity attributes likeE:11.nameorE:11.class_nameIt:<id>.<attr>/Item:<id>.<attr>for item attributesN:<value>for integersF:<value>for floatsself.<attr>,sender.<attr>,attacker.<attr>,target.<attr>,item.<attr>for message-context shortcuts- plain text like
target=Urg
That means:
E:11.nameusually gives the instance name, for exampleUrgE:11.class_namegives the template/class name, for exampleOrctarget.nameusually gives the sender instance name in a received messagetarget.class_nameusually gives the sender class name in a received messageself.namegives the receiver entity name
Rules Integration
Rules-driven combat messages should usually use locale keys, not hardcoded English strings.
[combat.messages]
incoming_key = "combat.damage.incoming"
incoming_category = "warning"
outgoing_key = "combat.damage.outgoing"
outgoing_category = "system"
This lets you translate combat text without changing gameplay rules.
Text Widgets
Screen text widgets use the same locale-key system.
Example widget text:
{ui.status.gold}: {PLAYER.FUNDS}
ATK: {PLAYER.ATTACK}
DEF: {PLAYER.ARMOR}
LV: {PLAYER.LEVEL}
XP: {PLAYER.EXP}
Weapon DMG: {PLAYER.WEAPON.DMG}
Armor Total: {PLAYER.ARMOR.ARMOR}
{ui.quest.ready}
Example locale entries:
[en]
ui.status.gold = "Gold"
ui.quest.ready = "Quest ready"
Current behavior:
- locale keys like
{ui.status.gold}are resolved throughGame / Locales - existing
PLAYER.*status placeholders still work in text widgets PLAYER.FUNDSshows the current player fundsPLAYER.<ATTR>shows a player attribute valuePLAYER.LEVELresolves throughgame.levelPLAYER.EXPandPLAYER.EXPERIENCEresolve throughgame.experiencePLAYER.ATTACKsumsDMGacross the player's equipped weapon slotsPLAYER.ARMORsumsARMORacross the player's equipped gear slotsPLAYER.WEAPON.<ATTR>sums an attribute across the player's configured weapon slotsPLAYER.EQUIPPED.<ATTR>sums an attribute across all equipped itemsPLAYER.ARMOR.<ATTR>sums an attribute across the player's configured gear slotsWORLD.HOUR,WORLD.MINUTE,WORLD.TIME,WORLD.TIME_12, andWORLD.TIME_24show the current in-game time
For localized messages and templates, the same derived values are available through entity references and context aliases, for example:
self.weapon.DMGself.armor.ARMORtarget.weapon.DMGE:11.equipped.ARMOR