Skip to content

Translations

Bartholomew Ho edited this page Nov 15, 2026 · 1 revision

Translations

Your mod's text in the player's language: its rows, pages, pop-ups and hotkeys. Translations are gettext PO files, the format translators already know, built into your mod.

New in 0.12.0. Needs FH2 Mod Platform 2.9.0 or later. On an older platform, Tr gives back your English and the rest does nothing, so your mod still runs there.

Example

protected override void OnInit()
{
    AddTranslations();   // every .po file built into the mod
    AddSetting(new ToggleSetting("Trees", Tr("row.Trees.label", "Breakable trees"), true)
    {
        Description = Tr("row.Trees.description", "Trees break when you drive into them."),
    });
}
Protected Overrides Sub OnInit()
    AddTranslations()
    AddSetting(New ToggleSetting("Trees", Tr("row.Trees.label", "Breakable trees"), True) With {
        .Description = Tr("row.Trees.description", "Trees break when you drive into them.")
    })
End Sub

And Lang\pl.po in the project:

msgctxt "row.Trees.label"
msgid "Breakable trees"
msgstr "Łamliwe drzewa"

with this in the .csproj / .vbproj:

<ItemGroup>
  <EmbeddedResource Include="Lang\*.po" />
</ItemGroup>

How it works

  • Each text has a key, the PO file's msgctxt ("row.Trees.label"), and its English, the msgid. Anything without a translation shows in English.
  • Text from Tr follows the game's language by itself. Pass it straight to a row's label, description or choices, a page, a hotkey's label, a notice or SetDescription. The platform knows which key it came from, and looks it up again each time it writes the page. That matters because the game picks its language a few seconds after OnInit.
  • Text you build from it (a number filled in, say) is yours, and stays as it was: set it again when the page opens (PageOptions.Opened).
  • A translation made from different English than you pass (you changed the English since) isn't used, so it never shows with the wrong meaning.
  • Pass the same English each time.

Members

On Mod:

Member What it does
AddTranslations(Assembly? from = null) → int Every .po file embedded in your mod, each named after its language (pl.po, Lang\pt-BR.po). Returns how many entries were taken. From OnInit.
AddTranslation(string language, string po) → int One language's PO file, as text: "pl", "pt-BR", "zh-Hant".
Tr(string? key, string english) → string english in the player's language. Tr(english) for entries without a key.
TrPlural(string? key, string one, string other, long n) → string Text with a count, "{n} car" / "{n} cars": the language's own rules pick the form (Polish has three), and {n} is filled in the language's way.
SetStringTr(string table, ushort key, string msgKey, string english) SetString in every language: each of the game's string tables gets its own language's text. From OnInit.
SetSettingText(string key, string? label, string? description, IReadOnlyList<string>? choices) → bool Changes a row's text later. Null leaves that part as it is.
SetDescription(string description) Changes your mod's description. The platform also looks up ModInfo.Description itself, under the key mod.description.

On ModPlatform:

Member What it does
Language (property, string) The language text is translated into, as a tag: "en", "pl", "pt-BR", "zh-Hant"...
GameLanguage (property, string?) The game's text language, as its string tables name it: "EN", "PL", "CHT"... Null until the game has one. Game.Language gives the same.
FormatNumber(double value, int decimals = 0) → string 1,234.5 in English, 1.234,5 in German, 12 345,5 in Polish.
FormatDate(DateOnly date) → string 24.10.2026 in German, 2026-10-24 in English.

For translators

Put your file at fh2-mods\lang\<the mod's name>\<language>.po, for example fh2-mods\lang\WreckingBall\pl.po. It's used instead of the one built into the mod, so you can try yours without a build. platform.log says when it's used, and lists entries it left out (a {placeholder} that doesn't match the English, say).

Test without knowing the language: test=1 in fh2-mods\platform-language.ini shows every translated text padded, in [brackets].

See also

Clone this wiki locally