Localization
StoneForge's own interface (the Mods window, settings, warnings, loading status) follows the language selected in Stoneshard. Only US English (en-US) ships so far; anything without a translation stays in English. Logs and compiler messages are always in English.
A C# mod can translate its own text the same way.
Translation files
Put them in the mod's Localization folder, one file for each language, named by culture:
mods/MyMod/Localization/en-US.json
mods/MyMod/Localization/fr.json
mods/MyMod/Localization/fr-CA.json
Each is a UTF-8 JSON object of keys and text:
{
"challenge.reward": "Reward: {0:N0} crowns",
"settings.title": "Challenge settings"
}
Reading text
string reward = context.Localization.Get("challenge.reward", 100);
string language = context.Localization.Language; // e.g. "en-US"
context.Localization |
|
|---|---|
Get(key, arguments...) |
The text for the game's language, formatted with the arguments. |
GetTemplate(key) |
The text unformatted, placeholders and all. |
Language |
The game's language, as a culture name. |
TranslationsChanged |
The language or a translation file changed. |
LanguageChanged |
The game's language changed (only that). |
Bind(target, refresh) |
Runs refresh on target now and whenever translations change. |
A lookup tries the game's culture, then its parent (fr-CA, then fr), then en-US and en. A key that's missing everywhere comes back as the key itself. Each mod has its own catalog, so two mods can use the same keys.
- Placeholders are numbered (
{0},{1}) and can be reordered in a translation, but each translation must use the same numbers as the English entry. `` are literal braces. - Numbers are formatted for the game's culture.
- Write whole sentences, not fragments to join.
- Errors fall back to English, and are logged: malformed JSON, duplicate keys, bad format strings, or mismatched placeholders. A catalog is limited to 1 MB.
Live editing
StoneForge watches the Localization folder. A saved file shows in the game within moments, with no reload of the mod. While a file is malformed, the last good version stays in use.
Keeping UI up to date
Text already given to a UI element doesn't change by itself. Refresh it when translations change:
context.Localization.TranslationsChanged += () =>
rewardLabel.Text = context.Localization.Get("challenge.reward", reward);
Or bind it, which also sets it now:
context.Localization.Bind(rewardLabel,
label => label.Text = context.Localization.Get("challenge.reward", reward));
MainMenu.AddButton(context, () => context.Localization.Get("settings.title"), OpenSettings);
A binding holds its target weakly: don't capture the target in the callback (use the parameter). Callbacks run on the game thread and go with the mod.
MainMenu.AddButton, AddBefore, AddAfter and EscMenu.AddButton take their text as a function, too, so it follows the language.
Settings labels, item names and skill descriptions aren't translated for you: pass localized text when you define them. Dialogues, quests and contracts take text keys (TextKey, TitleKey...) from the mod's catalog.
MSL mods keep their own localization: StoneForge doesn't change their text.
Languages
Stoneshard's languages: Russian, English, Chinese, German, Spanish (Latin America), French, Italian, Portuguese, Polish, Turkish, Japanese and Korean. Check other scripts' characters and longer text in the game before shipping a translation.
StoneForge's own catalog is StoneForge.API/Localization/en-US.json in its repository. More languages go beside it, named by culture; they're built into the API.