Summary
The client currently uses two parallel translation systems:
- Legacy
.bmd files (text.bmd, item.bmd, etc.) — binary, index-based lookup (e.g. GlobalText[100]).
src/bin/Translations/<lang>/*.json — key-based runtime lookup (e.g. EDITOR_TEXT(\"btn_save\")).
Replace both with a single .resx-based localization system that compiles to generated C++ accessor classes at build time.
Target design
Source format
- One
.resx file per resource group per locale, e.g.:
src/Localization/
Editor.en.resx
Editor.de.resx
Items.en.resx
Items.de.resx
GlobalText.en.resx
GlobalText.de.resx
.resx is plain XML — editable in Visual Studio, Rider, or any text editor on Linux/Mac.
Build-time code generator
- A resx-to-C++ generator produces typed accessor headers, integrated into the CMake build.
- Generated output (committed or in build dir, TBD) provides one class per resource group per locale, plus an index header.
Call-site usage
Compile-time-checked typed accessors:
ImGui::Text(\"%s\", L.editor.btnSave());
ImGui::Text(\"%s\", L.items.itemName(itemId));
ImGui::Text(\"%s\", L.global.greeting(playerName)); // placeholder substitution
- Typos fail at compile time.
- IDE autocomplete works.
- Placeholder / format-string support for parameterized strings.
Runtime layer
- Locale switching at runtime.
- Configurable fallback locale (e.g. fall back to
en when a key is missing in the active locale).
- Defined behaviour for missing keys (log + return key name, or fail loudly in debug).
Migration plan
- Land the resx system + generator + runtime layer alongside the existing systems.
- Migrate strings from
text.bmd, item.bmd, and any other .bmd localization files.
- Migrate strings from
src/bin/Translations/<lang>/*.json.
- Remove the legacy code paths:
GlobalText array indexing, text.bmd loader, EDITOR_TEXT macro, JSON translation loader.
- Delete the legacy data files.
A temporary integer-ID compatibility shim (L(100) → resolves to the migrated key) may help during migration but is not a long-term API — every call site should end up using the typed accessors.
Documentation
Add docs/translation-system.md covering:
- How to add a new string (which
.resx, naming convention).
- How to add a new locale.
- How the build-time generator runs.
- How locale switching and fallback work at runtime.
Link it from README.md and from the AI/contributor entry point (#32).
Acceptance criteria
Summary
The client currently uses two parallel translation systems:
.bmdfiles (text.bmd,item.bmd, etc.) — binary, index-based lookup (e.g.GlobalText[100]).src/bin/Translations/<lang>/*.json— key-based runtime lookup (e.g.EDITOR_TEXT(\"btn_save\")).Replace both with a single
.resx-based localization system that compiles to generated C++ accessor classes at build time.Target design
Source format
.resxfile per resource group per locale, e.g.:.resxis plain XML — editable in Visual Studio, Rider, or any text editor on Linux/Mac.Build-time code generator
Call-site usage
Compile-time-checked typed accessors:
Runtime layer
enwhen a key is missing in the active locale).Migration plan
text.bmd,item.bmd, and any other.bmdlocalization files.src/bin/Translations/<lang>/*.json.GlobalTextarray indexing,text.bmdloader,EDITOR_TEXTmacro, JSON translation loader.A temporary integer-ID compatibility shim (
L(100)→ resolves to the migrated key) may help during migration but is not a long-term API — every call site should end up using the typed accessors.Documentation
Add
docs/translation-system.mdcovering:.resx, naming convention).Link it from
README.mdand from the AI/contributor entry point (#32).Acceptance criteria
en+de)..bmdtranslation files andTranslations/*.jsonremoved.GlobalText/EDITOR_TEXTcode paths removed.docs/translation-system.mdadded.