NRF SDK 0.9

Creating a mod

Translate the mod name and description

Name the mod, its windows and its signals in the game language while keeping identifiers stable.

Declare text once

Prerequisites: a mod declared with signalMod or toolMod and an assets/translations.json file. This page translates the displayed mod name and description, then construction names. It complements button and message translation.

Inside signalMod or toolMod
metadata(
    author = "Your name",
    name = tr("mod.name"),
    description = tr("mod.description")
)
assets/translations.json
{
  "fallback": "fr",
  "languages": {
    "fr": {
      "mod.name": "Mes signaux",
      "mod.description": "Des signaux pour mon réseau."
    },
    "en": {
      "mod.name": "My signals",
      "mod.description": "Signals for my network."
    }
  }
}

You can mix plain text and tr. author remains the author’s credit. The display name is optional; omitting it uses the name from mod.json. References also support tr’s named parameters, resolved at build time. Every key must exist in the fallback language.

Distinguish the mod, group and window

A tool has several visible names. Use the product name for the mod and a short title describing each window’s purpose. For example, the BB Timechange group contains a Date and time row; repeating BB Timechange in that row adds no information.

Displayed textDeclaration to use
Name in the game’s mod lists and detailsmetadata(name = tr("mod.name"), ...)
Group in Options → NRF HubThe title of toolMod or signalMod. With toolMod(modInfo), modInfo.title comes from name in mod.json.
Window title and row under Shortcutswindow("clock", tr("window.clock"), ...)

metadata.name does not replace the group title. In this example, the project sets name: "BB Timechange" in mod.json; the catalogue gives the mod details the same name and translates the window title separately.

Inside nimby.mod, with import nimby.*
fun createMod() = toolMod(modInfo) {
    metadata(
        author = "Your name",
        name = tr("mod.name"),
        description = tr("mod.description")
    )
    window("clock", tr("window.clock"), shortcut = "F9") { event ->
        showWindow(event, clock().dateTime().toString(), emptyList())
    }
}
assets/translations.json
{
  "fallback": "en",
  "languages": {
    "fr": {
      "mod.name": "BB Timechange",
      "mod.description": "Consulter la date et l’heure du jeu.",
      "window.clock": "Date et heure"
    },
    "en": {
      "mod.name": "BB Timechange",
      "mod.description": "View the game date and time.",
      "window.clock": "Date and time"
    }
  }
}

The keys mod.name and window.clock are your choice: you can rename them by updating the corresponding tr calls. The position of the Kotlin call determines where the text appears. However, "clock" is the window identifier: keep it stable, without tr, to preserve the player’s shortcut.

F9 is only this example’s default shortcut. The player can change or disable it in Options → NRF Hub, under Shortcuts. An existing compatible preference is preserved even if you change the translated title or default value in an update.

Where translations appear

LocationBehaviour
mod.txtName and description in the fallback language. This generated text remains readable when SDK localization is unavailable.
nrf-metadata.jsonResolved text for each language, generated alongside mod.txt. No second file needs manual maintenance.
New-game mod listThe name and details follow the active game language: exact locale, base language, then fallback.
In-game mod managerThe list name, details title and description are adapted as they are displayed. Metadata stored in the save remains intact.
Construction and mod contentsconstruction(name = tr(...), catalogueName = tr(...)) generates translated signal and texture catalogue names. The manager’s resource details also use this text.
Hub and Steam publishingThey retain the metadata from their own manifest. This feature does not translate the Steam page or Hub interface.

A description may contain line breaks; the name remains single-line. Each catalogue belongs to its mod: two packages may use the same keys without sharing their text. Check long names and descriptions in both languages.

Translate each signal model

Inside your signalModel declaration
construction(
    states = listOf("imgs/closed.png", "imgs/open.png"),
    name = tr("signal.construction"),
    catalogueName = tr("signal.catalogue")
)
Keys to add to the same assets/translations.json
{
  "fallback": "fr",
  "languages": {
    "fr": {
      "signal.construction": "Mon signal",
      "signal.catalogue": "Mes feux"
    },
    "en": {
      "signal.construction": "My signal",
      "signal.catalogue": "My lights"
    }
  }
}

name appears in the construction menu; catalogueName names the texture set. Omit catalogueName to reuse name. Plain strings remain supported. With tr, leave nameKey and catalogueNameKey unset: generation associates text with the correct mod and model.

The fallback catalogue name is English when that translation exists, otherwise the fallback language. Rebuild the package after editing JSON and check both languages in the game. A translation changes display text, never identifiers, paths or texture order.