i18n: route explorer and shield status strings through TR()

Centralise the remaining hardcoded English literals in two otherwise
fully-translated files (explorer_tab: 40 TR calls, shield_dialog: 23) so
they join the i18n system with an English source key + fallback:

- explorer_tab: the three search-error messages (invalid response, hash
  not found, not-connected) now use explorer_* keys. Also guards a hash
  lookup behind an active daemon connection and disables the block-detail
  prev/next nav while a fetch is in flight (both were the reason these
  error paths could fire).
- shield_dialog: the operation status/error strings (submitting, submitted,
  failed, status, error-checking-status, shield/merge failed) now use
  shield_* keys.
- i18n: add the new explorer_* and shield_* English source keys.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-05 15:09:18 -05:00
parent ec48538881
commit 061db16004
3 changed files with 36 additions and 14 deletions

View File

@@ -221,7 +221,7 @@ static void applyBlockDetailResult(const json& result, const std::string& error)
}
if (result.is_null()) {
s_search_error = "Invalid response from daemon";
s_search_error = TR("explorer_invalid_response");
s_show_detail_modal = false;
return;
}
@@ -388,7 +388,7 @@ static void navigateToHash(App* app, const std::string& hash) {
s_expanded_tx_idx = 0;
s_show_detail_modal = false;
} else {
s_search_error = "No block or transaction found for this hash";
s_search_error = TR("explorer_hash_not_found");
}
};
});
@@ -417,6 +417,11 @@ static void performSearch(App* app, const std::string& query) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
});
if (isHex64) {
// A hash lookup needs the daemon; navigateToHash() would otherwise return silently.
if (!app->rpc() || !app->rpc()->isConnected()) {
s_search_error = TR("explorer_not_connected");
return;
}
navigateToHash(app, query);
return;
}
@@ -1039,6 +1044,9 @@ static void renderBlockDetailModal(App* app) {
// Nav buttons on same line
ImGui::SameLine(contentW - Layout::spacingXl() * 3);
// Disable prev/next while a fetch is in flight so navigation can't stack fetches.
ImGui::BeginDisabled(s_detail_loading);
// Prev
if (s_detail_height > 1) {
ImGui::PushFont(Type().iconMed());
@@ -1065,6 +1073,8 @@ static void renderBlockDetailModal(App* app) {
ImGui::PopID();
ImGui::PopFont();
}
ImGui::EndDisabled();
}
ImGui::Separator();

View File

@@ -181,7 +181,7 @@ void ShieldDialog::render(App* app)
const char* btn_label = (s_mode == Mode::ShieldCoinbase) ? TR("shield_funds") : TR("merge_funds");
if (material::StyledButton(btn_label, ImVec2(shieldBtn.width, 0), S.resolveFont(shieldBtn.font))) {
s_operation_pending = true;
s_status_message = "Submitting operation...";
s_status_message = TR("shield_submitting");
if (s_mode == Mode::ShieldCoinbase) {
std::string from(s_from_address), to(s_to_address);
@@ -201,14 +201,14 @@ void ShieldDialog::render(App* app)
s_operation_pending = false;
if (error.empty()) {
s_operation_id = result.value("opid", "");
s_status_message = "Operation submitted: " + s_operation_id;
s_status_message = std::string(TR("shield_op_submitted")) + s_operation_id;
Notifications::instance().success(TR("shield_started"));
// Register with the shared poller so an async failure is
// surfaced (and balances refresh) even after this dialog closes.
app->trackOperation(s_operation_id);
} else {
s_status_message = "Error: " + error;
Notifications::instance().error("Shield failed: " + error);
s_status_message = std::string(TR("shield_error_prefix")) + error;
Notifications::instance().error(std::string(TR("shield_send_failed")) + error);
}
};
});
@@ -235,14 +235,14 @@ void ShieldDialog::render(App* app)
s_operation_pending = false;
if (error.empty()) {
s_operation_id = result.value("opid", "");
s_status_message = "Operation submitted: " + s_operation_id;
s_status_message = std::string(TR("shield_op_submitted")) + s_operation_id;
Notifications::instance().success(TR("merge_started"));
// Register with the shared poller so an async failure is
// surfaced (and balances refresh) even after this dialog closes.
app->trackOperation(s_operation_id);
} else {
s_status_message = "Error: " + error;
Notifications::instance().error("Merge failed: " + error);
s_status_message = std::string(TR("shield_error_prefix")) + error;
Notifications::instance().error(std::string(TR("merge_send_failed")) + error);
}
};
});
@@ -293,16 +293,16 @@ void ShieldDialog::render(App* app)
s_status_message = TR("shield_completed");
Notifications::instance().success(TR("shield_merge_done"));
} else if (status == "failed") {
std::string errMsg = op.value("error", nlohmann::json{}).value("message", "Unknown error");
s_status_message = "Operation failed: " + errMsg;
Notifications::instance().error("Operation failed: " + errMsg);
std::string errMsg = op.value("error", nlohmann::json{}).value("message", TR("shield_unknown_error"));
s_status_message = std::string(TR("shield_op_failed")) + errMsg;
Notifications::instance().error(std::string(TR("shield_op_failed")) + errMsg);
} else if (status == "executing") {
s_status_message = TR("shield_in_progress");
} else {
s_status_message = "Status: " + status;
s_status_message = std::string(TR("shield_status_label")) + status;
}
} else if (!error.empty()) {
s_status_message = "Error checking status: " + error;
s_status_message = std::string(TR("shield_status_check_error")) + error;
}
};
});

View File

@@ -1501,6 +1501,15 @@ void I18n::loadBuiltinEnglish()
strings_["shield_to_address"] = "To Address (Shielded):";
strings_["shield_utxo_limit"] = "UTXO Limit:";
strings_["shield_wildcard_hint"] = "Use '*' to shield from all transparent addresses";
strings_["shield_submitting"] = "Submitting operation...";
strings_["shield_op_submitted"] = "Operation submitted: ";
strings_["shield_op_failed"] = "Operation failed: ";
strings_["shield_error_prefix"] = "Error: ";
strings_["shield_status_label"] = "Status: ";
strings_["shield_status_check_error"] = "Error checking status: ";
strings_["shield_unknown_error"] = "Unknown error";
strings_["shield_send_failed"] = "Shield failed: ";
strings_["merge_send_failed"] = "Merge failed: ";
strings_["merge_description"] = "Merge multiple UTXOs into a single shielded address. This can help reduce wallet size and improve privacy.";
strings_["merge_funds"] = "Merge Funds";
strings_["merge_started"] = "Merge operation started";
@@ -1568,6 +1577,9 @@ void I18n::loadBuiltinEnglish()
strings_["explorer_tx_outputs"] = "Outputs";
strings_["explorer_tx_size"] = "Size";
strings_["explorer_invalid_query"] = "Enter a block height or 64-character hash";
strings_["explorer_invalid_response"] = "Invalid response from daemon";
strings_["explorer_hash_not_found"] = "No block or transaction found for this hash";
strings_["explorer_not_connected"] = "Not connected to daemon — cannot look up a block or transaction hash";
strings_["explorer_no_results"] = "No matching cached blocks";
}