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östenstring.Lang.Localized(...)verpackt den aufgelösten Text alsLocStrFormattedfü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
ModIdmuss mit einem Buchstaben oder einer Ziffer beginnen. - Danach sind in der
ModIdBuchstaben, Ziffern,_und-erlaubt. - Die
TextIddarf zusätzlich Punkte enthalten, etwasettings.audio.volume. - Punkte sind in der
ModIdnicht 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/