Pinned by Arystus on 2026-08-09Locked

Mod Guide DE

Arystus · 3 days ago

MultiLangLib in einer eigenen Mod verwenden

Diese Anleitung bindet MultiLangLib als gemeinsame Übersetzungsbibliothek in eine Captain-of-Industry-Mod ein. Im Beispiel heißt die Consumer-Mod MyMod.

1. Abhängigkeit deklarieren

Ergänze die manifest.json deiner Mod um MultiLangLib. Der Eintrag verwendet absichtlich keine Leerzeichen um >=:

{
  "id": "MyMod",
  "version": "1.0.0",
  "primary_dlls": [ "MyMod.dll" ],
  "mod_dependencies": [ "MultiLangLib>=0.1.0" ]
}

Damit wird deine Mod erst geladen, wenn eine geeignete MultiLangLib-Version vorhanden ist.

2. DLL referenzieren

Referenziere die installierte MultiLangLib.dll in deiner Projektdatei, kopiere sie aber nicht in das Ausgabeverzeichnis deiner Mod:

<ItemGroup>
  <Reference Include="MultiLangLib">
    <HintPath>$(APPDATA)\Captain of Industry\Mods\MultiLangLib\MultiLangLib.dll</HintPath>
    <Private>false</Private>
  </Reference>
</ItemGroup>

Private=false ist wichtig: Es soll genau eine gemeinsame MultiLangLib-DLL geladen werden. Wenn beide Projekte im selben Quellbaum liegen, kannst du stattdessen einen Projektverweis mit Private="false" verwenden.

3. Mod-Verzeichnis registrieren

Importiere den Namespace und registriere das Stammverzeichnis deiner Mod im Konstruktor:

using MultiLangLib;
using Mafi.Core.Mods;

public sealed class MyMod : DataOnlyMod {

    public MyMod(ModManifest manifest) : base(manifest) {
        Lang.RegisterMod(manifest.Id, manifest.RootDirectoryPath);
    }

    // Weitere Mod-Implementierung ...
}

Die Registrierung ist empfohlen. Bei normal installierten Geschwisterordnern kann MultiLangLib das Verzeichnis zwar selbst finden, die ausdrückliche Registrierung funktioniert aber auch mit abweichenden Verzeichnisstrukturen zuverlässig.

4. Sprachdateien anlegen

Lege die Übersetzungen im lang-Verzeichnis deiner eigenen Mod ab:

MyMod\
├── MyMod.dll
├── manifest.json
└── lang\
    ├── de.json
    └── en.json

Das empfohlene Format ist ein einfaches JSON-Objekt. de.json:

{
  "window.title": "Produktionsübersicht",
  "window.close": "Schließen",
  "welcome": "Willkommen, Captain {0}!"
}

Und en.json:

{
  "window.title": "Production overview",
  "window.close": "Close",
  "welcome": "Welcome, Captain {0}!"
}

Alternativ ist das COI-Arrayformat erlaubt:

[
  [ "multilanglib.MyMod.window.title", "Produktionsübersicht" ],
  [ "window.close", "Schließen" ]
]

Kurze IDs und vollständige Schlüssel dürfen verwendet werden. Verwende innerhalb einer Datei jede ID nur einmal.

5. Texte im Code abrufen

Jeder vollständige Schlüssel folgt diesem Muster:

multilanglib.<ModId>.<TextId>

Typische Aufrufe:

using Mafi.Localization;
using MultiLangLib;

string title = Lang.Get("multilanglib.MyMod.window.title");
string close = Lang.Get("MyMod", "window.close");
LocStrFormatted titleForUi = Lang.Localized("MyMod", "window.title");
string greeting = Lang.Format("multilanglib.MyMod.welcome", playerName);
  • Lang.Get(...) liefert einen bereits aufgelösten string.
  • Lang.Localized(...) verpackt den aufgelösten Text als LocStrFormatted für COI-Oberflächen.
  • Lang.Format(...) ersetzt Platzhalter mit der aktiven Sprachkultur.
  • Lang.TryGet(...) meldet über den Rückgabewert, ob ein Eintrag gefunden wurde.

Eine nackte Zeichenkette wie "multilanglib.MyMod.window.title" wird nicht automatisch vom Spiel ersetzt. Der Schlüssel muss immer über die MultiLangLib-API aufgelöst werden.

Regeln für Schlüssel

  • Die ModId muss mit einem Buchstaben oder einer Ziffer beginnen.
  • Danach sind in der ModId Buchstaben, Ziffern, _ und - erlaubt.
  • Die TextId darf zusätzlich Punkte enthalten, etwa settings.audio.volume.
  • Punkte sind in der ModId nicht erlaubt.
  • Groß- und Kleinschreibung der IDs ist relevant.

Eine statische Hilfsklasse verhindert Tippfehler an Aufrufstellen:

public static class Texts {

    public static string WindowTitle =>
        Lang.Get("MyMod", "window.title");

    public static LocStrFormatted WindowTitleForUi =>
        Lang.Localized("MyMod", "window.title");
}

Suchreihenfolge und Fallback

Für multilanglib.MyMod.window.title und die deutsche Spielsprache sucht MultiLangLib in dieser Reihenfolge:

1. <MyMod>/lang/de.json
2. <MultiLangLib>/lang/MyMod/de.json
3. <MyMod>/lang/en.json
4. <MultiLangLib>/lang/MyMod/en.json
5. multilanglib.MyMod.window.title

Zentrale Dateien unter MultiLangLib\lang\MyMod\ eignen sich beispielsweise für nachträglich bereitgestellte Community-Übersetzungen. Die Datei in der Consumer-Mod hat Vorrang.

Bei regionalen Sprachen wird zunächst die genaue und anschließend die neutrale Variante geprüft, zum Beispiel de-DE.json vor de.json. Im Automatikmodus übernimmt MultiLangLib die von Captain of Industry verwendeten Dateinamen, darunter auch Namen wie pt_BR.json oder zh_Hans.json.

Debuggen

Aktiviere in den Einstellungen von MultiLangLib:

debug_language = true

Danach liefert jeder gültige Lookup seinen vollständigen Schlüssel. So erkennst du im Spiel sofort, welche UI-Stelle welche Übersetzung erwartet.

Weitere Einstellungen:

  • language_override = auto: verwendet die im Spiel gewählte Sprache.
  • language_override = debug: aktiviert ebenfalls die Schlüsselausgabe.
  • language_override = de: erzwingt eine Sprache.
  • language_override = de.json: erzwingt einen wörtlichen Dateinamen.
  • fallback_language = en: legt die Rückfallsprache fest.

MultiLangLib hält geladene Dateien im Cache. Nach Änderungen während der Entwicklung kannst du Lang.Reload() aufrufen. Bereits gerenderte UI-Elemente werden dadurch nicht automatisch neu aufgebaut.

Häufige Fehler

Im Spiel steht nur der Schlüssel: Prüfe Dateiname, ModId, TextId und Groß-/Kleinschreibung. Prüfe außerdem, ob die JSON-Datei gültig ist und ob MultiLangLib aktiviert wurde.

Die Consumer-Mod wird nicht geladen: Prüfe den Eintrag MultiLangLib>=0.1.0 und ob der Ordner tatsächlich MultiLangLib heißt.

Es entsteht ein DLL-Konflikt: Stelle im Projektverweis Private=false ein und liefere MultiLangLib.dll nicht im Ordner deiner Consumer-Mod aus.

Platzhalter bleiben sichtbar: Verwende Lang.Format(...) und übergib für jeden Platzhalter ein passendes Argument. Formatfehler werden protokolliert; MultiLangLib gibt dann sicherheitshalber den unformatierten Text zurück.

Eine geänderte Datei wird nicht neu eingelesen: Rufe während der Entwicklung Lang.Reload() auf oder starte das Spiel neu.

Vollständiges Beispiel

Ein baubares Beispiel mit Manifest, Projektverweis, C#-Aufrufen sowie deutschen und englischen Sprachdateien liegt unter:

examples/ExampleConsumer/
10
Showing 1–1 of 1