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:
2026-03-11 00:40:50 -05:00
parent f416ff3d09
commit 2c5a658ea5
71 changed files with 43567 additions and 5267 deletions

View File

@@ -128,22 +128,19 @@ void RequestPaymentDialog::render(App* app)
auto qr = S.drawElement("dialogs.request-payment", "qr-code");
auto actionBtn = S.button("dialogs.request-payment", "action-button");
if (material::BeginOverlayDialog("Request Payment", &s_open, win.width, 0.94f)) {
if (material::BeginOverlayDialog(TR("request_title"), &s_open, win.width, 0.94f)) {
const auto& state = app->getWalletState();
ImGui::TextWrapped(
"Generate a payment request that others can scan or copy. "
"The QR code contains your address and optional amount/memo."
);
ImGui::TextWrapped("%s", TR("request_description"));
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
// Address selection
ImGui::Text("Receive Address:");
ImGui::Text("%s", TR("request_receive_address"));
std::string addr_display = s_address[0] ? s_address : "Select address...";
std::string addr_display = s_address[0] ? s_address : TR("request_select_address");
if (addr_display.length() > static_cast<size_t>(zAddrLbl.truncate)) {
addr_display = addr_display.substr(0, zAddrFrontLbl.truncate) + "..." + addr_display.substr(addr_display.length() - zAddrBackLbl.truncate);
}
@@ -152,7 +149,7 @@ void RequestPaymentDialog::render(App* app)
if (ImGui::BeginCombo("##Address", addr_display.c_str())) {
// Z-addresses
if (!state.z_addresses.empty()) {
ImGui::TextDisabled("-- Shielded Addresses --");
ImGui::TextDisabled("%s", TR("request_shielded_addrs"));
for (size_t i = 0; i < state.z_addresses.size(); i++) {
const auto& addr = state.z_addresses[i];
std::string label = addr.address;
@@ -169,7 +166,7 @@ void RequestPaymentDialog::render(App* app)
// T-addresses
if (!state.t_addresses.empty()) {
ImGui::TextDisabled("-- Transparent Addresses --");
ImGui::TextDisabled("%s", TR("request_transparent_addrs"));
for (size_t i = 0; i < state.t_addresses.size(); i++) {
const auto& addr = state.t_addresses[i];
std::string label = addr.address;
@@ -189,7 +186,7 @@ void RequestPaymentDialog::render(App* app)
ImGui::Spacing();
// Amount (optional)
ImGui::Text("Amount (optional):");
ImGui::Text("%s", TR("request_amount"));
ImGui::SetNextItemWidth(amountInput.width);
if (ImGui::InputDouble("##Amount", &s_amount, 0.1, 1.0, "%.8f")) {
s_uri_dirty = true;
@@ -200,7 +197,7 @@ void RequestPaymentDialog::render(App* app)
ImGui::Spacing();
// Label (optional)
ImGui::Text("Label (optional):");
ImGui::Text("%s", TR("request_label"));
ImGui::SetNextItemWidth(-1);
if (ImGui::InputText("##Label", s_label, sizeof(s_label))) {
s_uri_dirty = true;
@@ -211,7 +208,7 @@ void RequestPaymentDialog::render(App* app)
// Memo (optional, only for z-addr)
bool is_zaddr = (s_address[0] == 'z');
if (is_zaddr) {
ImGui::Text("Memo (optional):");
ImGui::Text("%s", TR("request_memo"));
ImGui::SetNextItemWidth(-1);
if (ImGui::InputTextMultiline("##Memo", s_memo, sizeof(s_memo), ImVec2(-1, memoInput.height > 0 ? memoInput.height : 60))) {
s_uri_dirty = true;
@@ -245,7 +242,7 @@ void RequestPaymentDialog::render(App* app)
// Payment URI display
if (!s_payment_uri.empty()) {
ImGui::Text("Payment URI:");
ImGui::Text("%s", TR("request_payment_uri"));
ImGui::SetNextItemWidth(-1);
// Use a selectable text area for the URI
@@ -256,23 +253,23 @@ void RequestPaymentDialog::render(App* app)
ImGui::Spacing();
// Copy button
if (material::StyledButton("Copy URI", ImVec2(actionBtn.width, 0), S.resolveFont(actionBtn.font))) {
if (material::StyledButton(TR("request_copy_uri"), ImVec2(actionBtn.width, 0), S.resolveFont(actionBtn.font))) {
ImGui::SetClipboardText(s_payment_uri.c_str());
Notifications::instance().success("Payment URI copied to clipboard");
Notifications::instance().success(TR("request_uri_copied"));
}
ImGui::SameLine();
if (material::StyledButton("Copy Address", ImVec2(actionBtn.width, 0), S.resolveFont(actionBtn.font))) {
if (material::StyledButton(TR("copy_address"), ImVec2(actionBtn.width, 0), S.resolveFont(actionBtn.font))) {
ImGui::SetClipboardText(s_address);
Notifications::instance().success("Address copied to clipboard");
Notifications::instance().success(TR("address_copied"));
}
}
ImGui::Spacing();
// Close button
if (material::StyledButton("Close", ImVec2(actionBtn.width, 0), S.resolveFont(actionBtn.font))) {
if (material::StyledButton(TR("close"), ImVec2(actionBtn.width, 0), S.resolveFont(actionBtn.font))) {
s_open = false;
}
material::EndOverlayDialog();