Localization (Display Names & Translations)

Give your content player-facing names and translate them per language, keyed by the stable identifier.

Every piece of content has a stable identifier (name / id) — the key recipes, drops, Lua and save files point at. What a player reads is a separate thing: an optional English display name, and optional per-language translations. Both layers are additive — add neither and the UI title-cases the identifier — so nothing you already ship breaks.

The shown label is resolved in this order, first hit wins:

  1. lang/<locale>.yaml — a translation for the player’s language, keyed by identifier.
  2. display-name — the English name authored in the content config.
  3. Title-cased identifier — the mod prefix stripped and words capitalized (cherry_log → Cherry Log).

The identifier never changes with language: a translated build changes labels, not keys. This is also why you should rename before you translate, never after — renaming an identifier orphans every translation of it (and, for milestones, its achievement).


display-name (the English label)

display-name is an optional, client-only field on every player-visible category:

# mods/YourMod/affix-config.yaml
affixes:
  - name: searing            # identifier — stable, referenced everywhere
    display-name: Searing     # English label the player sees
    tags: [sword]

Categories that take display-name: items (and the blocks/consumables that register as items), mobs, mounts, affixes, infusions, weather, and per-placement mob overrides in structures. Structural identifiers (loot tables, presets, world builders, terrain, biomes) are plumbing and have none.

Status effects are translation-only. Their config is server-side and only the effect’s id reaches the client, so a display-name there is not shown; give status effects a translated name through lang/<locale>.yaml (below), and English falls back to the title-cased id.


lang/<locale>.yaml (translations)

Ship one file per language your mod translates, in a lang/ directory at your mod’s root. No manifest entry is needed — it is a directory convention, like assets/.

mods/YourMod/lang/fr.yaml     # French
mods/YourMod/lang/de.yaml     # German

Each file is a flat map of identifier → translated string. Key on the bare identifier (the engine namespaces it to your mod automatically, exactly like a name:); prefix another mod’s name only to translate its content:

# mods/YourMod/lang/fr.yaml   — French names, keyed by identifier
searing: "<your French translation>"        # translates YourMod:searing
OtherMod:frostbite: "<your French translation>"   # translates another mod's content

Rules and behavior:

  • Keys are identifiers, values are the translated text. Do not translate the key.
  • A second string on the same content takes a suffix, so it never collides with the content’s name: a lore entry’s body is <id>.body, a milestone’s banner name is <id>.milestone.
  • A file for a language you have not translated can simply be omitted — any identifier with no entry falls back to display-name, then the title-cased id, so a partial file is valid.
  • English needs no file. English names come from display-name; lang/en.yaml is not read.
  • Only the identifier is required to be stable; you may add, remove, or complete translations freely between versions.

Creation ships localized in the Latin tier — fr, es, de, it, pt, pl — the languages the bundled pixel font covers. Other scripts (Cyrillic, CJK, Hangul) need a wider font asset and are out of scope for now.


Example

A mod adds a weather and translates its name to French and German:

# mods/Tempest/weather-config.yaml
weathers:
  - name: ashfall
    display-name: Ashfall        # English
    timing: { min-ms: 60000, max-ms: 180000, transition-out-ms: 4000 }
# mods/Tempest/lang/fr.yaml
ashfall: "<your French translation>"
# mods/Tempest/lang/de.yaml
ashfall: "<your German translation>"

A player on French sees the French name; on German, the German one; on English (or any language with no entry), Ashfall; and if display-name were omitted too, Ashfall from the title-cased identifier.

Last updated