From 5355394a5a36d492b87ef73bec86af0e1b99293b Mon Sep 17 00:00:00 2001 From: Zero <128979226+lux-zero-161@users.noreply.github.com> Date: Fri, 12 Jun 2026 15:46:34 +0200 Subject: [PATCH] Implement RMLUI string translation via LCE StringTable Replace hardcoded English strings in RML UI files with {IDS_XXX} placeholders that are translated at runtime via RmlUi's TranslateString override, which looks up keys in the LCE StringTable. - Override SystemInterface_Win64::TranslateString to scan for {KEY} patterns and resolve them via StringTable::getString(wstring) - Add GetLCEStringTable() accessor to CConsoleMinecraftApp - Update PauseMenu.rml, SettingsMenu.rml, HelpOptions.rml with IDS_XXX keys - Update dynamic dialog SetInnerRML calls in UIScene_PauseMenu.cpp - Fix CMakePresets.json: remove hardcoded VS2022 ml64.exe path --- CMakePresets.json | 3 +- Minecraft.Client/Assets/UI/HelpOptions.rml | 10 +-- Minecraft.Client/Assets/UI/PauseMenu.rml | 24 +++---- Minecraft.Client/Assets/UI/SettingsMenu.rml | 18 ++--- .../Common/UI/UIScene_PauseMenu.cpp | 14 ++-- .../Windows64/RmlUi_SystemInterface_Win64.cpp | 70 ++++++++++++++++++- Minecraft.Client/Windows64/Windows64_App.h | 1 + 7 files changed, 104 insertions(+), 36 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index f1c4167c..cb08b959 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -14,8 +14,7 @@ "cacheVariables": { "PLATFORM_DEFINES": "_WINDOWS64", "PLATFORM_NAME": "Windows64", - "IGGY_LIBS": "iggy_w64.lib;iggyperfmon_w64.lib;iggyexpruntime_w64.lib", - "CMAKE_ASM_MASM_COMPILER": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.16.27023/bin/HostX64/x64/ml64.exe" + "IGGY_LIBS": "iggy_w64.lib;iggyperfmon_w64.lib;iggyexpruntime_w64.lib" } } ], diff --git a/Minecraft.Client/Assets/UI/HelpOptions.rml b/Minecraft.Client/Assets/UI/HelpOptions.rml index 2b579398..dcddf046 100644 --- a/Minecraft.Client/Assets/UI/HelpOptions.rml +++ b/Minecraft.Client/Assets/UI/HelpOptions.rml @@ -6,11 +6,11 @@
- - - - - + + + + +
diff --git a/Minecraft.Client/Assets/UI/PauseMenu.rml b/Minecraft.Client/Assets/UI/PauseMenu.rml index 97610aa2..34a71c56 100644 --- a/Minecraft.Client/Assets/UI/PauseMenu.rml +++ b/Minecraft.Client/Assets/UI/PauseMenu.rml @@ -6,25 +6,25 @@
- - - - - + + + + +
-

Exit Game?

+

{IDS_CONFIRM_EXIT_GAME}

- - - + + +
-

Overwrite existing save?

+

{IDS_CONFIRM_SAVE_GAME}

- - + +
diff --git a/Minecraft.Client/Assets/UI/SettingsMenu.rml b/Minecraft.Client/Assets/UI/SettingsMenu.rml index 37b86491..01f5be53 100644 --- a/Minecraft.Client/Assets/UI/SettingsMenu.rml +++ b/Minecraft.Client/Assets/UI/SettingsMenu.rml @@ -6,18 +6,18 @@
- - - - - - + + + + + +
-

Reset all settings to defaults?

+

{IDS_RESET_TO_DEFAULTS}

- - + +
diff --git a/Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp b/Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp index e15c9217..41899ec1 100644 --- a/Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp @@ -303,11 +303,11 @@ void UIScene_PauseMenu::ShowSaveDialog(bool show) if (!ProfileManager.IsFullVersion()) { - if (saveText) saveText->SetInnerRML("You need to unlock the full game to save."); + if (saveText) saveText->SetInnerRML("{IDS_UNLOCK_TOSAVE_TEXT}"); } else { - if (saveText) saveText->SetInnerRML("Overwrite existing save?"); + if (saveText) saveText->SetInnerRML("{IDS_CONFIRM_SAVE_GAME}"); } m_document->GetElementById("save_cancel")->Focus(); @@ -395,11 +395,11 @@ void UIScene_PauseMenu::ShowExitDialog(bool show) if (g_NetworkManager.GetPlayerCount() > 1) { - if (exitText) exitText->SetInnerRML("Exit Game (disconnect other players)?"); + if (exitText) exitText->SetInnerRML("{IDS_CONFIRM_EXIT_GAME_CONFIRM_DISCONNECT_SAVE}"); } else { - if (exitText) exitText->SetInnerRML("Exit Game?"); + if (exitText) exitText->SetInnerRML("{IDS_CONFIRM_EXIT_GAME}"); } if (exitCancel) exitCancel->Focus(); } @@ -408,8 +408,8 @@ void UIScene_PauseMenu::ShowExitDialog(bool show) // Trial version: simple OK/Cancel, "progress will be lost" if (exitSave) exitSave->SetProperty("display", "none"); if (exitNosave) exitNosave->SetProperty("display", "inline-block"); - if (exitNosave) exitNosave->SetInnerRML("Yes"); - if (exitText) exitText->SetInnerRML("Exit Game (progress will be lost)?"); + if (exitNosave) exitNosave->SetInnerRML("{IDS_YES}"); + if (exitText) exitText->SetInnerRML("{IDS_CONFIRM_EXIT_GAME_PROGRESS_LOST}"); if (exitCancel) exitCancel->Focus(); } @@ -424,7 +424,7 @@ void UIScene_PauseMenu::ShowExitDialog(bool show) auto* exitSave = m_document->GetElementById("exit_save"); auto* exitNosave = m_document->GetElementById("exit_nosave"); if (exitSave) exitSave->SetProperty("display", "inline-block"); - if (exitNosave) exitNosave->SetInnerRML("Exit without Saving"); + if (exitNosave) exitNosave->SetInnerRML("{IDS_EXIT_GAME_NO_SAVE}"); if (exitNosave) exitNosave->SetProperty("display", "inline-block"); m_document->GetElementById("exit_game")->Focus(); diff --git a/Minecraft.Client/Windows64/RmlUi_SystemInterface_Win64.cpp b/Minecraft.Client/Windows64/RmlUi_SystemInterface_Win64.cpp index 03260e48..7ab7f78f 100644 --- a/Minecraft.Client/Windows64/RmlUi_SystemInterface_Win64.cpp +++ b/Minecraft.Client/Windows64/RmlUi_SystemInterface_Win64.cpp @@ -1,4 +1,7 @@ #include "RmlUi_SystemInterface_Win64.h" +#include "..\Common\Consoles_App.h" +#include "StringTable.h" +#include "Windows64_App.h" SystemInterface_Win64::SystemInterface_Win64() { @@ -22,7 +25,72 @@ double SystemInterface_Win64::GetElapsedTime() int SystemInterface_Win64::TranslateString(Rml::String& translated, const Rml::String& input) { translated = input; - return 0; + int count = 0; + + StringTable* st = app.GetLCEStringTable(); + if (!st) + return 0; + + std::string result; + result.reserve(input.size()); + + for (size_t i = 0; i < input.size(); ) + { + if (input[i] == '{') + { + size_t end = input.find('}', i + 1); + if (end != Rml::String::npos) + { + Rml::String key = input.substr(i + 1, end - i - 1); + // Convert UTF-8 key to wide string for StringTable lookup + int wlen = MultiByteToWideChar(CP_UTF8, 0, key.c_str(), (int)key.size(), nullptr, 0); + if (wlen > 0) + { + std::wstring wkey(wlen, L'\0'); + MultiByteToWideChar(CP_UTF8, 0, key.c_str(), (int)key.size(), &wkey[0], wlen); + LPCWSTR wstr = st->getString(wkey); + if (wstr && wcslen(wstr) > 0) + { + // Convert wide result back to UTF-8 + int utf8len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr); + if (utf8len > 0) + { + std::string utf8(utf8len - 1, '\0'); // -1 for null terminator + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &utf8[0], utf8len, nullptr, nullptr); + result += utf8; + count++; + } + else + { + result += input.substr(i, end - i + 1); + } + } + else + { + result += input.substr(i, end - i + 1); + } + } + else + { + result += input.substr(i, end - i + 1); + } + i = end + 1; + } + else + { + result += input[i]; + i++; + } + } + else + { + result += input[i]; + i++; + } + } + + translated = result; + return count; } void SystemInterface_Win64::JoinPath(Rml::String& translated_path, const Rml::String& document_path, const Rml::String& path) diff --git a/Minecraft.Client/Windows64/Windows64_App.h b/Minecraft.Client/Windows64/Windows64_App.h index 2f39fbb8..391ba7c9 100644 --- a/Minecraft.Client/Windows64/Windows64_App.h +++ b/Minecraft.Client/Windows64/Windows64_App.h @@ -29,6 +29,7 @@ public: virtual void ReadBannedList(int iPad, eTMSAction action=static_cast(0), bool bCallback=false) {} C4JStringTable *GetStringTable() { return nullptr;} + StringTable *GetLCEStringTable() { return m_stringTable; } // original code virtual void TemporaryCreateGameStart();