feat: Full UI internationalization, pool hashrate stats, and layout caching
- Replace all hardcoded English strings with TR() translation keys across every tab, dialog, and component (~20 UI files) - Expand all 8 language files (de, es, fr, ja, ko, pt, ru, zh) with complete translations (~37k lines added) - Improve i18n loader with exe-relative path fallback and English base fallback for missing keys - Add pool-side hashrate polling via pool stats API in xmrig_manager - Introduce Layout::beginFrame() per-frame caching and refresh balance layout config only on schema generation change - Offload daemon output parsing to worker thread - Add CJK subset fallback font for Chinese/Japanese/Korean glyphs
This commit is contained in:
@@ -30,6 +30,14 @@
|
||||
namespace dragonx {
|
||||
namespace ui {
|
||||
|
||||
// Helper: build "TranslatedLabel##id" for ImGui widgets that use label as ID
|
||||
static std::string TrId(const char* tr_key, const char* id) {
|
||||
std::string s = TR(tr_key);
|
||||
s += "##";
|
||||
s += id;
|
||||
return s;
|
||||
}
|
||||
|
||||
// Case-insensitive substring search
|
||||
static bool containsIgnoreCase(const std::string& str, const std::string& search) {
|
||||
if (search.empty()) return true;
|
||||
@@ -774,13 +782,13 @@ static void RenderBalanceClassic(App* app)
|
||||
ImGui::InputTextWithHint("##AddrSearch", "Filter...", addr_search, sizeof(addr_search));
|
||||
|
||||
ImGui::SameLine(0, Layout::spacingLg());
|
||||
ImGui::Checkbox("Hide 0 Balances", &s_hideZeroBalances);
|
||||
ImGui::Checkbox(TrId("hide_zero_balances", "hide0").c_str(), &s_hideZeroBalances);
|
||||
{
|
||||
int hc = app->getHiddenAddressCount();
|
||||
if (hc > 0) {
|
||||
ImGui::SameLine(0, Layout::spacingLg());
|
||||
char hlbl[64];
|
||||
snprintf(hlbl, sizeof(hlbl), "Show Hidden (%d)", hc);
|
||||
snprintf(hlbl, sizeof(hlbl), TR("show_hidden"), hc);
|
||||
ImGui::Checkbox(hlbl, &s_showHidden);
|
||||
} else {
|
||||
s_showHidden = false;
|
||||
@@ -883,7 +891,8 @@ static void RenderBalanceClassic(App* app)
|
||||
|
||||
ImU32 greenCol = S.resolveColor("var(--accent-shielded)", Success());
|
||||
ImU32 goldCol = S.resolveColor("var(--accent-transparent)", Warning());
|
||||
float rowPadLeft = Layout::spacingLg();
|
||||
float rowPadLeft = Layout::cardInnerPadding();
|
||||
float rowPadRight = Layout::cardInnerPadding();
|
||||
float rowIconSz = std::max(S.drawElement("tabs.balance", "address-icon-min-size").size, S.drawElement("tabs.balance", "address-icon-size").size * hs);
|
||||
float innerW = ImGui::GetContentRegionAvail().x;
|
||||
|
||||
@@ -931,10 +940,10 @@ static void RenderBalanceClassic(App* app)
|
||||
// --- Button zone (right edge): [eye] [star] ---
|
||||
float btnH = rowH - Layout::spacingSm() * 2.0f;
|
||||
float btnW = btnH;
|
||||
float btnGap = Layout::spacingXs();
|
||||
float btnGap = Layout::spacingSm();
|
||||
float btnY = rowPos.y + (rowH - btnH) * 0.5f;
|
||||
float rightEdge = rowPos.x + innerW;
|
||||
float starX = rightEdge - btnW - Layout::spacingSm();
|
||||
float starX = rightEdge - btnW - rowPadRight;
|
||||
float eyeX = starX - btnGap - btnW;
|
||||
float btnRound = 6.0f * dp;
|
||||
bool btnClicked = false;
|
||||
@@ -958,7 +967,7 @@ static void RenderBalanceClassic(App* app)
|
||||
else app->favoriteAddress(addr.address);
|
||||
btnClicked = true;
|
||||
}
|
||||
if (bHov) ImGui::SetTooltip("%s", row.favorite ? "Remove favorite" : "Favorite address");
|
||||
if (bHov) ImGui::SetTooltip("%s", row.favorite ? TR("remove_favorite") : TR("favorite_address"));
|
||||
}
|
||||
|
||||
// Eye button (zero balance or hidden)
|
||||
@@ -980,7 +989,7 @@ static void RenderBalanceClassic(App* app)
|
||||
else app->hideAddress(addr.address);
|
||||
btnClicked = true;
|
||||
}
|
||||
if (bHov) ImGui::SetTooltip("%s", row.hidden ? "Restore address" : "Hide address");
|
||||
if (bHov) ImGui::SetTooltip("%s", row.hidden ? TR("restore_address") : TR("hide_address"));
|
||||
}
|
||||
|
||||
// Content zone ends before buttons
|
||||
@@ -1103,17 +1112,17 @@ static void RenderBalanceClassic(App* app)
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (row.hidden) {
|
||||
if (ImGui::MenuItem("Restore Address"))
|
||||
if (ImGui::MenuItem(TR("restore_address")))
|
||||
app->unhideAddress(addr.address);
|
||||
} else if (addr.balance < 1e-9) {
|
||||
if (ImGui::MenuItem("Hide Address"))
|
||||
if (ImGui::MenuItem(TR("hide_address")))
|
||||
app->hideAddress(addr.address);
|
||||
}
|
||||
if (row.favorite) {
|
||||
if (ImGui::MenuItem("Remove Favorite"))
|
||||
if (ImGui::MenuItem(TR("remove_favorite")))
|
||||
app->unfavoriteAddress(addr.address);
|
||||
} else {
|
||||
if (ImGui::MenuItem("Favorite Address"))
|
||||
if (ImGui::MenuItem(TR("favorite_address")))
|
||||
app->favoriteAddress(addr.address);
|
||||
}
|
||||
effects::ImGuiAcrylic::EndAcrylicPopup();
|
||||
@@ -1387,13 +1396,13 @@ static void RenderSharedAddressList(App* app, float listH, float availW,
|
||||
ImGui::SetNextItemWidth(searchW);
|
||||
ImGui::InputTextWithHint("##AddrSearch", "Filter...", addr_search, sizeof(addr_search));
|
||||
ImGui::SameLine(0, Layout::spacingLg());
|
||||
ImGui::Checkbox("Hide 0 Balances", &s_hideZeroBalances);
|
||||
ImGui::Checkbox(TrId("hide_zero_balances", "hide0_v2").c_str(), &s_hideZeroBalances);
|
||||
{
|
||||
int hc = app->getHiddenAddressCount();
|
||||
if (hc > 0) {
|
||||
ImGui::SameLine(0, Layout::spacingLg());
|
||||
char hlbl[64];
|
||||
snprintf(hlbl, sizeof(hlbl), "Show Hidden (%d)", hc);
|
||||
snprintf(hlbl, sizeof(hlbl), TR("show_hidden"), hc);
|
||||
ImGui::Checkbox(hlbl, &s_showHidden);
|
||||
} else {
|
||||
s_showHidden = false;
|
||||
@@ -1461,10 +1470,10 @@ static void RenderSharedAddressList(App* app, float listH, float availW,
|
||||
float ch = ImGui::GetContentRegionAvail().y;
|
||||
if (ch < 60) ch = 60;
|
||||
if (addr_search[0]) {
|
||||
ImVec2 textSz = ImGui::CalcTextSize("No matching addresses");
|
||||
ImVec2 textSz = ImGui::CalcTextSize(TR("no_addresses_match"));
|
||||
ImGui::SetCursorPosX((cw - textSz.x) * 0.5f);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ch * 0.25f);
|
||||
ImGui::TextDisabled("No matching addresses");
|
||||
ImGui::TextDisabled("%s", TR("no_addresses_match"));
|
||||
} else {
|
||||
const char* msg = "No addresses yet";
|
||||
ImVec2 msgSz = ImGui::CalcTextSize(msg);
|
||||
@@ -1482,7 +1491,8 @@ static void RenderSharedAddressList(App* app, float listH, float availW,
|
||||
addrScrollMaxY = ImGui::GetScrollMaxY();
|
||||
ImU32 greenCol = S.resolveColor("var(--accent-shielded)", Success());
|
||||
ImU32 goldCol = S.resolveColor("var(--accent-transparent)", Warning());
|
||||
float rowPadLeft = Layout::spacingLg();
|
||||
float rowPadLeft = Layout::cardInnerPadding();
|
||||
float rowPadRight = Layout::cardInnerPadding();
|
||||
float rowIconSz = std::max(S.drawElement("tabs.balance", "address-icon-min-size").size,
|
||||
S.drawElement("tabs.balance", "address-icon-size").size * hs);
|
||||
float innerW = ImGui::GetContentRegionAvail().x;
|
||||
@@ -1522,10 +1532,10 @@ static void RenderSharedAddressList(App* app, float listH, float availW,
|
||||
// --- Button zone (right edge): [eye] [star] ---
|
||||
float btnH = rowH - Layout::spacingSm() * 2.0f;
|
||||
float btnW = btnH;
|
||||
float btnGap = Layout::spacingXs();
|
||||
float btnGap = Layout::spacingSm();
|
||||
float btnY = rowPos.y + (rowH - btnH) * 0.5f;
|
||||
float rightEdge = rowPos.x + innerW;
|
||||
float starX = rightEdge - btnW - Layout::spacingSm();
|
||||
float starX = rightEdge - btnW - rowPadRight;
|
||||
float eyeX = starX - btnGap - btnW;
|
||||
float btnRound = 6.0f * dp;
|
||||
bool btnClicked = false;
|
||||
@@ -1549,7 +1559,7 @@ static void RenderSharedAddressList(App* app, float listH, float availW,
|
||||
else app->favoriteAddress(addr.address);
|
||||
btnClicked = true;
|
||||
}
|
||||
if (bHov) ImGui::SetTooltip("%s", row.favorite ? "Remove favorite" : "Favorite address");
|
||||
if (bHov) ImGui::SetTooltip("%s", row.favorite ? TR("remove_favorite") : TR("favorite_address"));
|
||||
}
|
||||
|
||||
// Eye button (zero balance or hidden)
|
||||
@@ -1571,7 +1581,7 @@ static void RenderSharedAddressList(App* app, float listH, float availW,
|
||||
else app->hideAddress(addr.address);
|
||||
btnClicked = true;
|
||||
}
|
||||
if (bHov) ImGui::SetTooltip("%s", row.hidden ? "Restore address" : "Hide address");
|
||||
if (bHov) ImGui::SetTooltip("%s", row.hidden ? TR("restore_address") : TR("hide_address"));
|
||||
}
|
||||
|
||||
// Content zone ends before buttons
|
||||
@@ -1672,17 +1682,17 @@ static void RenderSharedAddressList(App* app, float listH, float availW,
|
||||
QRPopupDialog::show(addr.address, row.isZ ? "Z-Address" : "T-Address");
|
||||
ImGui::Separator();
|
||||
if (row.hidden) {
|
||||
if (ImGui::MenuItem("Restore Address"))
|
||||
if (ImGui::MenuItem(TR("restore_address")))
|
||||
app->unhideAddress(addr.address);
|
||||
} else if (addr.balance < 1e-9) {
|
||||
if (ImGui::MenuItem("Hide Address"))
|
||||
if (ImGui::MenuItem(TR("hide_address")))
|
||||
app->hideAddress(addr.address);
|
||||
}
|
||||
if (row.favorite) {
|
||||
if (ImGui::MenuItem("Remove Favorite"))
|
||||
if (ImGui::MenuItem(TR("remove_favorite")))
|
||||
app->unfavoriteAddress(addr.address);
|
||||
} else {
|
||||
if (ImGui::MenuItem("Favorite Address"))
|
||||
if (ImGui::MenuItem(TR("favorite_address")))
|
||||
app->favoriteAddress(addr.address);
|
||||
}
|
||||
effects::ImGuiAcrylic::EndAcrylicPopup();
|
||||
|
||||
Reference in New Issue
Block a user