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:
dan_s
2026-03-11 00:40:50 -05:00
parent cc617dd5be
commit 96c27bb949
71 changed files with 43567 additions and 5267 deletions

View File

@@ -3,6 +3,7 @@
// Released under the GPLv3
#include "i18n.h"
#include "platform.h"
#include <fstream>
#include <cstdio>
@@ -28,15 +29,17 @@ using json = nlohmann::json;
I18n::I18n()
{
// Register built-in languages
// CJK glyphs are provided by the merged NotoSansCJK-Subset fallback font.
// Cyrillic glyphs are included in the Ubuntu font glyph ranges.
registerLanguage("en", "English");
registerLanguage("es", "Español");
registerLanguage("zh", "中文");
registerLanguage("ru", "Русский");
registerLanguage("zh", "Chinese");
registerLanguage("ru", "Russian");
registerLanguage("de", "Deutsch");
registerLanguage("fr", "Français");
registerLanguage("pt", "Português");
registerLanguage("ja", "日本語");
registerLanguage("ko", "한국어");
registerLanguage("ja", "Japanese");
registerLanguage("ko", "Korean");
// Load default English strings (built-in fallback)
loadLanguage("en");
@@ -50,26 +53,35 @@ I18n& I18n::instance()
bool I18n::loadLanguage(const std::string& locale)
{
// First, try to load from file (allows user overrides)
std::string lang_file = "res/lang/" + locale + ".json";
std::ifstream file(lang_file);
if (file.is_open()) {
// Try to load from file: CWD-relative first, then exe-relative
std::string rel_path = "res/lang/" + locale + ".json";
std::string exe_path = Platform::getExecutableDirectory() + "/" + rel_path;
// Try both paths; prefer whichever opens successfully
for (const auto& lang_file : { rel_path, exe_path }) {
std::ifstream file(lang_file);
if (!file.is_open()) continue;
try {
json j;
file >> j;
strings_.clear();
// Load English built-in as fallback base for non-English
if (locale != "en") {
loadBuiltinEnglish();
} else {
strings_.clear();
}
for (auto& [key, value] : j.items()) {
if (value.is_string()) {
strings_[key] = value.get<std::string>();
}
}
current_locale_ = locale;
DEBUG_LOGF("Loaded language file: %s (%zu strings)\n", lang_file.c_str(), strings_.size());
return true;
} catch (const std::exception& e) {
DEBUG_LOGF("Error parsing language file %s: %s\n", lang_file.c_str(), e.what());
}
@@ -110,7 +122,12 @@ bool I18n::loadLanguage(const std::string& locale)
std::string json_str(reinterpret_cast<const char*>(embedded_data), embedded_size);
json j = json::parse(json_str);
strings_.clear();
// Load English built-in as fallback base for non-English
if (locale != "en") {
loadBuiltinEnglish();
} else {
strings_.clear();
}
for (auto& [key, value] : j.items()) {
if (value.is_string()) {
strings_[key] = value.get<std::string>();
@@ -128,17 +145,323 @@ bool I18n::loadLanguage(const std::string& locale)
// If English, use built-in strings
if (locale == "en") {
loadBuiltinEnglish();
current_locale_ = "en";
return true;
}
return false;
}
void I18n::loadBuiltinEnglish()
{
strings_.clear();
// Navigation & Tabs
strings_["overview"] = "Overview";
strings_["balance"] = "Balance";
strings_["send"] = "Send";
strings_["receive"] = "Receive";
strings_["transactions"] = "Transactions";
strings_["history"] = "History";
strings_["mining"] = "Mining";
strings_["peers"] = "Peers";
strings_["market"] = "Market";
strings_["settings"] = "Settings";
strings_["console"] = "Console";
strings_["tools"] = "TOOLS";
strings_["advanced"] = "ADVANCED";
// Settings sections
strings_["appearance"] = "APPEARANCE";
strings_["wallet"] = "WALLET";
strings_["node_security"] = "NODE & SECURITY";
strings_["node"] = "NODE";
strings_["security"] = "SECURITY";
strings_["explorer"] = "EXPLORER";
strings_["about"] = "About";
strings_["backup_data"] = "BACKUP & DATA";
strings_["balance_layout"] = "Balance Layout";
strings_["low_spec_mode"] = "Low-spec mode";
strings_["simple_background"] = "Simple background";
strings_["console_scanline"] = "Console scanline";
strings_["theme_effects"] = "Theme effects";
strings_["acrylic"] = "Acrylic";
strings_["noise"] = "Noise";
strings_["ui_opacity"] = "UI Opacity";
strings_["window_opacity"] = "Window Opacity";
strings_["font_scale"] = "Font Scale";
strings_["refresh"] = "Refresh";
strings_["website"] = "Website";
strings_["report_bug"] = "Report Bug";
strings_["save_settings"] = "Save Settings";
strings_["reset_to_defaults"] = "Reset to Defaults";
// Wallet settings
strings_["save_z_transactions"] = "Save shielded tx history";
strings_["auto_shield"] = "Auto-shield";
strings_["use_tor"] = "Use Tor";
strings_["keep_daemon"] = "Keep daemon running";
strings_["stop_external"] = "Stop external daemon";
strings_["verbose_logging"] = "Verbose logging";
strings_["mine_when_idle"] = "Mine when idle";
strings_["setup_wizard"] = "Run Setup Wizard...";
// RPC / Explorer settings
strings_["rpc_host"] = "Host";
strings_["rpc_port"] = "Port";
strings_["rpc_user"] = "Username";
strings_["rpc_pass"] = "Password";
strings_["transaction_url"] = "Transaction URL";
strings_["address_url"] = "Address URL";
strings_["custom_fees"] = "Allow custom transaction fees";
strings_["fetch_prices"] = "Fetch price data from CoinGecko";
strings_["block_explorer"] = "Block Explorer";
strings_["test_connection"] = "Test Connection";
strings_["rescan"] = "Rescan Blockchain";
// Settings: buttons
strings_["settings_address_book"] = "Address Book...";
strings_["settings_validate_address"] = "Validate Address...";
strings_["settings_request_payment"] = "Request Payment...";
strings_["settings_shield_mining"] = "Shield Mining...";
strings_["settings_merge_to_address"] = "Merge to Address...";
strings_["settings_clear_ztx"] = "Clear Z-Tx History";
strings_["settings_import_key"] = "Import Key...";
strings_["settings_export_key"] = "Export Key...";
strings_["settings_export_all"] = "Export All...";
strings_["settings_backup"] = "Backup...";
strings_["settings_export_csv"] = "Export CSV...";
strings_["settings_encrypt_wallet"] = "Encrypt Wallet";
strings_["settings_change_passphrase"] = "Change Passphrase";
strings_["settings_lock_now"] = "Lock Now";
strings_["settings_remove_encryption"] = "Remove Encryption";
strings_["settings_set_pin"] = "Set PIN";
strings_["settings_change_pin"] = "Change PIN";
strings_["settings_remove_pin"] = "Remove PIN";
strings_["settings_restart_daemon"] = "Restart daemon";
strings_["clear_anyway"] = "Clear Anyway";
// Settings: labels / text
strings_["settings_builtin"] = "Built-in";
strings_["settings_custom"] = "Custom";
strings_["settings_not_found"] = "Not found";
strings_["settings_idle_after"] = "after";
strings_["settings_not_encrypted"] = "Not encrypted";
strings_["settings_locked"] = "Locked";
strings_["settings_unlocked"] = "Unlocked";
strings_["settings_quick_unlock_pin"] = "Quick-unlock PIN";
strings_["settings_pin_active"] = "PIN";
strings_["settings_encrypt_first_pin"] = "Encrypt wallet first to enable PIN";
strings_["settings_data_dir"] = "Data Dir:";
strings_["settings_wallet_size_label"] = "Wallet Size:";
strings_["settings_debug_changed"] = "Debug categories changed \xe2\x80\x94 restart daemon to apply";
strings_["settings_auto_detected"] = "Auto-detected from DRAGONX.conf";
strings_["settings_visual_effects"] = "Visual Effects";
strings_["settings_acrylic_level"] = "Acrylic Level:";
strings_["settings_noise_opacity"] = "Noise Opacity:";
strings_["settings_privacy"] = "Privacy";
strings_["settings_other"] = "Other";
strings_["settings_rpc_connection"] = "RPC Connection";
strings_["settings_configure_rpc"] = "Configure connection to dragonxd daemon";
strings_["settings_wallet_maintenance"] = "Wallet Maintenance";
strings_["settings_wallet_info"] = "Wallet Info";
strings_["settings_block_explorer_urls"] = "Block Explorer URLs";
strings_["settings_configure_explorer"] = "Configure external block explorer links";
strings_["settings_auto_lock"] = "AUTO-LOCK";
strings_["settings_wallet_file_size"] = "Wallet file size: %s";
strings_["settings_wallet_location"] = "Wallet location: %s";
strings_["settings_rpc_note"] = "Note: Connection settings are usually auto-detected from DRAGONX.conf";
strings_["settings_explorer_hint"] = "URLs should include a trailing slash. The txid/address will be appended.";
strings_["settings_connection"] = "Connection";
strings_["settings_reduce_transparency"] = "Reduce transparency";
strings_["settings_save_shielded_local"] = "Save shielded transaction history locally";
strings_["settings_auto_shield_funds"] = "Auto-shield transparent funds";
strings_["settings_use_tor_network"] = "Use Tor for network connections";
strings_["settings_gradient_bg"] = "Gradient bg";
// Settings: tooltips
strings_["tt_theme_hotkey"] = "Hotkey: Ctrl+Left/Right to cycle themes";
strings_["tt_layout_hotkey"] = "Hotkey: Left/Right arrow keys to cycle Balance layouts";
strings_["tt_language"] = "Interface language for the wallet UI";
strings_["tt_scan_themes"] = "Scan for new themes.\nPlace theme folders in:\n%s";
strings_["tt_low_spec"] = "Disable all heavy visual effects\nHotkey: Ctrl+Shift+Down";
strings_["tt_simple_bg"] = "Use a simple gradient for the background\nHotkey: Ctrl+Up";
strings_["tt_simple_bg_alt"] = "Use a gradient version of the theme background image\nHotkey: Ctrl+Up";
strings_["tt_scanline"] = "CRT scanline effect in console";
strings_["tt_theme_effects"] = "Shimmer, glow, hue-cycling per theme";
strings_["tt_blur"] = "Blur amount (0%% = off, 100%% = maximum)";
strings_["tt_noise"] = "Grain texture intensity (0%% = off, 100%% = maximum)";
strings_["tt_ui_opacity"] = "Card and sidebar opacity (100%% = fully opaque, lower = more see-through)";
strings_["tt_window_opacity"] = "Background opacity (lower = desktop visible through window)";
strings_["tt_font_scale"] = "Scale all text and UI (1.0x = default, up to 1.5x).";
strings_["tt_custom_theme"] = "Custom theme active";
strings_["tt_address_book"] = "Manage saved addresses for quick sending";
strings_["tt_validate"] = "Check if a DragonX address is valid";
strings_["tt_request_payment"] = "Generate a payment request with QR code";
strings_["tt_shield_mining"] = "Move transparent mining rewards to a shielded address";
strings_["tt_merge"] = "Consolidate multiple UTXOs into one address";
strings_["tt_clear_ztx"] = "Delete locally cached z-transaction history";
strings_["tt_save_ztx"] = "Store z-address transaction history locally for faster loading";
strings_["tt_auto_shield"] = "Automatically move transparent balance to shielded addresses for privacy";
strings_["tt_tor"] = "Route daemon connections through the Tor network for anonymity";
strings_["tt_keep_daemon"] = "Daemon will still stop when running the setup wizard";
strings_["tt_stop_external"] = "Applies when connecting to a daemon\nyou started outside this wallet";
strings_["tt_verbose"] = "Log detailed connection diagnostics,\ndaemon state, and port owner info\nto the Console tab";
strings_["tt_mine_idle"] = "Automatically start mining when the\nsystem is idle (no keyboard/mouse input)";
strings_["tt_idle_delay"] = "How long to wait before starting mining";
strings_["tt_wizard"] = "Re-run the initial setup wizard\nDaemon will be restarted";
strings_["tt_open_dir"] = "Click to open in file explorer";
strings_["tt_rpc_host"] = "Hostname of the DragonX daemon";
strings_["tt_rpc_user"] = "RPC authentication username";
strings_["tt_rpc_port"] = "Port for daemon RPC connections";
strings_["tt_rpc_pass"] = "RPC authentication password";
strings_["tt_test_conn"] = "Verify the RPC connection to the daemon";
strings_["tt_rescan"] = "Rescan the blockchain for missing transactions";
strings_["tt_encrypt"] = "Encrypt wallet.dat with a passphrase";
strings_["tt_change_pass"] = "Change the wallet encryption passphrase";
strings_["tt_lock"] = "Lock the wallet immediately";
strings_["tt_remove_encrypt"] = "Remove encryption and store wallet unprotected";
strings_["tt_auto_lock"] = "Lock wallet after this much inactivity";
strings_["tt_set_pin"] = "Set a 4-8 digit PIN for quick unlock";
strings_["tt_change_pin"] = "Change your unlock PIN";
strings_["tt_remove_pin"] = "Remove PIN and require passphrase to unlock";
strings_["tt_tx_url"] = "Base URL for viewing transactions in a block explorer";
strings_["tt_addr_url"] = "Base URL for viewing addresses in a block explorer";
strings_["tt_custom_fees"] = "Enable manual fee entry when sending transactions";
strings_["tt_fetch_prices"] = "Retrieve DRGX market prices from CoinGecko API";
strings_["tt_block_explorer"] = "Open the DragonX block explorer in your browser";
strings_["tt_website"] = "Open the DragonX website";
strings_["tt_report_bug"] = "Report an issue on the project tracker";
strings_["tt_save_settings"] = "Save all settings to disk";
strings_["tt_reset_settings"] = "Reload settings from disk (undo unsaved changes)";
strings_["tt_debug_collapse"] = "Collapse debug logging options";
strings_["tt_debug_expand"] = "Expand debug logging options";
strings_["tt_restart_daemon"] = "Restart the daemon to apply debug logging changes";
// Settings: additional tooltips (keys/data row)
strings_["tt_import_key"] = "Import a private key (zkey or tkey) into this wallet";
strings_["tt_export_key"] = "Export the private key for the selected address";
strings_["tt_export_all"] = "Export all private keys to a file";
strings_["tt_backup"] = "Create a backup of your wallet.dat file";
strings_["tt_export_csv"] = "Export transaction history as a CSV spreadsheet";
// Settings: about / debug
strings_["settings_about_text"] = "A shielded cryptocurrency wallet for DragonX (DRGX), built with Dear ImGui for a lightweight, portable experience.";
strings_["settings_copyright"] = "Copyright 2024-2026 DragonX Developers | GPLv3 License";
strings_["debug_logging"] = "DEBUG LOGGING";
strings_["settings_debug_select"] = "Select categories to enable daemon debug logging (-debug= flags).";
strings_["settings_debug_restart_note"] = "Changes take effect after restarting the daemon.";
// Settings window (legacy dialog) descriptions
strings_["settings_language_note"] = "Note: Some text requires restart to update";
strings_["settings_solid_colors_desc"] = "Use solid colors instead of blur effects (accessibility)";
strings_["settings_gradient_desc"] = "Replace textured backgrounds with smooth gradients";
strings_["settings_save_shielded_desc"] = "Stores z-addr transactions in a local file for viewing";
strings_["settings_auto_shield_desc"] = "Automatically move transparent funds to shielded addresses";
strings_["settings_tor_desc"] = "Route all connections through Tor for enhanced privacy";
strings_["settings_rescan_desc"] = "Rescan blockchain for missing transactions";
strings_["settings_clear_ztx_long"] = "Clear Saved Z-Transaction History";
strings_["settings_clear_ztx_desc"] = "Delete locally stored shielded transaction data";
strings_["settings_wallet_not_found"] = "Wallet file not found";
// Balance tab: address actions
strings_["hide_zero_balances"] = "Hide 0 Balances";
strings_["restore_address"] = "Restore Address";
strings_["hide_address"] = "Hide Address";
strings_["remove_favorite"] = "Remove Favorite";
strings_["favorite_address"] = "Favorite Address";
strings_["show_hidden"] = "Show Hidden (%d)";
// Misc dialog strings
strings_["shield_operation_id"] = "Operation ID: %s";
strings_["peers_peer_label"] = "Peer: %s";
strings_["key_export_click_retrieve"] = "Click to retrieve the key from your wallet";
strings_["backup_source"] = "Source: %s";
strings_["export_keys_progress"] = "Exporting %d/%d...";
strings_["import_key_progress"] = "Importing %d/%d...";
strings_["block_click_copy"] = "Click to copy";
strings_["confirm_clear_ztx_title"] = "Confirm Clear Z-Tx History";
strings_["confirm_clear_ztx_warning1"] = "Clearing z-transaction history may cause your shielded balance to show as 0 until a wallet rescan is performed.";
strings_["confirm_clear_ztx_warning2"] = "If this happens, you will need to re-import your z-address private keys with rescan enabled to recover your balance.";
// Send tab
strings_["sending_from"] = "SENDING FROM";
strings_["recent_sends"] = "RECENT SENDS";
strings_["recipient"] = "RECIPIENT";
strings_["memo_optional"] = "MEMO (OPTIONAL)";
strings_["no_recent_sends"] = "No recent sends";
strings_["network_fee"] = "NETWORK FEE";
strings_["amount_details"] = "AMOUNT DETAILS";
strings_["not_connected_to_daemon"] = "Not connected to daemon";
strings_["select_source_address"] = "Select a source address...";
strings_["no_addresses_with_balance"] = "No addresses with balance";
strings_["blockchain_syncing"] = "Blockchain syncing (%.1f%%)... Balances may be inaccurate.";
strings_["wallet_empty"] = "Your wallet is empty";
strings_["wallet_empty_hint"] = "Switch to Receive to get your address and start receiving funds.";
strings_["go_to_receive"] = "Go to Receive";
strings_["review_send"] = "Review Send";
strings_["fee_low"] = "Low";
strings_["fee_normal"] = "Normal";
strings_["fee_high"] = "High";
strings_["submitting_transaction"] = "Submitting transaction...";
strings_["transaction_sent_msg"] = "Transaction sent!";
strings_["copy_error"] = "Copy Error";
strings_["dismiss"] = "Dismiss";
strings_["clear_form_confirm"] = "Clear all form fields?";
strings_["yes_clear"] = "Yes, Clear";
strings_["keep"] = "Keep";
strings_["undo_clear"] = "Undo Clear";
// Receive tab
strings_["recent_received"] = "RECENT RECEIVED";
strings_["payment_request"] = "PAYMENT REQUEST";
strings_["copy"] = "Copy";
strings_["new"] = "+ New";
strings_["share"] = "Share";
strings_["select_receiving_address"] = "Select a receiving address...";
strings_["no_addresses_match"] = "No addresses match filter";
strings_["no_recent_receives"] = "No recent receives";
strings_["waiting_for_daemon"] = "Waiting for daemon connection...";
strings_["addresses_appear_here"] = "Your receiving addresses will appear here once connected.";
strings_["loading_addresses"] = "Loading addresses...";
strings_["clear_request"] = "Clear Request";
strings_["copy_uri"] = "Copy URI";
strings_["qr_unavailable"] = "QR unavailable";
strings_["received_label"] = "Received";
// Transactions tab
strings_["no_transactions"] = "No transactions found";
strings_["no_matching"] = "No matching transactions";
strings_["transaction_id"] = "TRANSACTION ID";
strings_["search_placeholder"] = "Search...";
strings_["all_filter"] = "All";
strings_["sent_filter"] = "Sent";
strings_["received_filter"] = "Received";
strings_["mined_filter"] = "Mined";
strings_["export_csv"] = "Export CSV";
strings_["transactions_upper"] = "TRANSACTIONS";
strings_["received_upper"] = "RECEIVED";
strings_["sent_upper"] = "SENT";
strings_["mined_upper"] = "MINED";
strings_["from_upper"] = "FROM";
strings_["to_upper"] = "TO";
strings_["shielded_to"] = "SHIELDED TO";
strings_["address_upper"] = "ADDRESS";
strings_["memo_upper"] = "MEMO";
strings_["shielded_type"] = "Shielded";
strings_["recv_type"] = "Recv";
strings_["sent_type"] = "Sent";
strings_["immature_type"] = "Immature";
strings_["mined_type"] = "Mined";
strings_["mature"] = "Mature";
strings_["copy_txid"] = "Copy TxID";
strings_["view_details"] = "View Details";
strings_["full_details"] = "Full Details";
strings_["showing_transactions"] = "Showing %d\xe2\x80\x93%d of %d transactions (total: %zu)";
strings_["txs_count"] = "%d txs";
strings_["conf_count"] = "%d conf";
strings_["confirmations_display"] = "%d confirmations | %s";
// Balance Tab
strings_["summary"] = "Summary";
@@ -280,18 +603,455 @@ bool I18n::loadLanguage(const std::string& locale)
strings_["warning"] = "Warning";
strings_["amount_exceeds_balance"] = "Amount exceeds balance";
strings_["transaction_sent"] = "Transaction sent successfully";
current_locale_ = "en";
DEBUG_LOGF("Using built-in English strings (%zu strings)\n", strings_.size());
return true;
}
// Fallback: reload English so we never leave stale strings
DEBUG_LOGF("Language file not found: %s — falling back to English\n", lang_file.c_str());
if (locale != "en") {
loadLanguage("en");
}
return false;
// --- Common / Shared ---
strings_["add"] = "Add";
strings_["address_copied"] = "Address copied to clipboard";
strings_["address_label"] = "Address:";
strings_["amount_label"] = "Amount:";
strings_["date_label"] = "Date:";
strings_["delete"] = "Delete";
strings_["fee_label"] = "Fee:";
strings_["file_save_location"] = "File will be saved in: ~/.config/ObsidianDragon/";
strings_["hide"] = "Hide";
strings_["label"] = "Label:";
strings_["loading"] = "Loading...";
strings_["memo_label"] = "Memo:";
strings_["notes"] = "Notes";
strings_["notes_optional"] = "Notes (optional):";
strings_["output_filename"] = "Output filename:";
strings_["paste_from_clipboard"] = "Paste from Clipboard";
strings_["show"] = "Show";
strings_["time_days_ago"] = "%d days ago";
strings_["time_hours_ago"] = "%d hours ago";
strings_["time_minutes_ago"] = "%d minutes ago";
strings_["time_seconds_ago"] = "%d seconds ago";
strings_["unknown"] = "Unknown";
strings_["validating"] = "Validating...";
strings_["warning_upper"] = "WARNING!";
// --- About Dialog ---
strings_["about_block_explorer"] = "Block Explorer";
strings_["about_block_height"] = "Block Height:";
strings_["about_build_date"] = "Build Date:";
strings_["about_build_type"] = "Build Type:";
strings_["about_chain"] = "Chain:";
strings_["about_connections"] = "Connections:";
strings_["about_credits"] = "Credits";
strings_["about_daemon"] = "Daemon:";
strings_["about_debug"] = "Debug";
strings_["about_edition"] = "ImGui Edition";
strings_["about_github"] = "GitHub";
strings_["about_imgui"] = "ImGui:";
strings_["about_license"] = "License";
strings_["about_license_text"] = "This software is released under the GNU General Public License v3 (GPLv3). You are free to use, modify, and distribute this software under the terms of the license.";
strings_["about_peers_count"] = "%zu peers";
strings_["about_release"] = "Release";
strings_["about_title"] = "About ObsidianDragon";
strings_["about_version"] = "Version:";
strings_["about_website"] = "Website";
// --- Address Book Dialog ---
strings_["address_book_add"] = "Add Address";
strings_["address_book_add_new"] = "Add New";
strings_["address_book_added"] = "Address added to book";
strings_["address_book_count"] = "%zu addresses saved";
strings_["address_book_deleted"] = "Entry deleted";
strings_["address_book_edit"] = "Edit Address";
strings_["address_book_empty"] = "No saved addresses. Click 'Add New' to add one.";
strings_["address_book_exists"] = "Address already exists in book";
strings_["address_book_title"] = "Address Book";
strings_["address_book_update_failed"] = "Failed to update - address may be duplicate";
strings_["address_book_updated"] = "Address updated";
// --- Backup Dialog ---
strings_["backup_backing_up"] = "Backing up...";
strings_["backup_create"] = "Create Backup";
strings_["backup_created"] = "Wallet backup created";
strings_["backup_description"] = "Create a backup of your wallet.dat file. This file contains all your private keys and transaction history. Store the backup in a secure location.";
strings_["backup_destination"] = "Backup destination:";
strings_["backup_tip_external"] = "Store backups on external drives or cloud storage";
strings_["backup_tip_multiple"] = "Create multiple backups in different locations";
strings_["backup_tip_test"] = "Test restoring from backup periodically";
strings_["backup_tips"] = "Tips:";
strings_["backup_title"] = "Backup Wallet";
strings_["backup_wallet_not_found"] = "Warning: wallet.dat not found at expected location";
// --- Block Info Dialog ---
strings_["block_bits"] = "Bits:";
strings_["block_click_next"] = "Click to view next block";
strings_["block_click_prev"] = "Click to view previous block";
strings_["block_get_info"] = "Get Block Info";
strings_["block_hash"] = "Block Hash:";
strings_["block_height"] = "Block Height:";
strings_["block_info_title"] = "Block Information";
strings_["block_merkle_root"] = "Merkle Root:";
strings_["block_nav_next"] = "Next >>";
strings_["block_nav_prev"] = "<< Previous";
strings_["block_next"] = "Next Block:";
strings_["block_previous"] = "Previous Block:";
strings_["block_size"] = "Size:";
strings_["block_timestamp"] = "Timestamp:";
strings_["block_transactions"] = "Transactions:";
// --- Console Tab ---
strings_["console_auto_scroll"] = "Auto-scroll";
strings_["console_available_commands"] = "Available commands:";
strings_["console_capturing_output"] = "Capturing daemon output...";
strings_["console_clear"] = "Clear";
strings_["console_clear_console"] = "Clear Console";
strings_["console_cleared"] = "Console cleared";
strings_["console_click_commands"] = "Click commands above to insert them";
strings_["console_click_insert"] = "Click to insert";
strings_["console_click_insert_params"] = "Click to insert with parameters";
strings_["console_close"] = "Close";
strings_["console_commands"] = "Commands";
strings_["console_common_rpc"] = "Common RPC commands:";
strings_["console_completions"] = "Completions:";
strings_["console_connected"] = "Connected to daemon";
strings_["console_copy_all"] = "Copy All";
strings_["console_copy_selected"] = "Copy";
strings_["console_daemon"] = "Daemon";
strings_["console_daemon_error"] = "Daemon error!";
strings_["console_daemon_started"] = "Daemon started";
strings_["console_daemon_stopped"] = "Daemon stopped";
strings_["console_disconnected"] = "Disconnected from daemon";
strings_["console_errors"] = "Errors";
strings_["console_filter_hint"] = "Filter output...";
strings_["console_help_clear"] = " clear - Clear the console";
strings_["console_help_getbalance"] = " getbalance - Show transparent balance";
strings_["console_help_getblockcount"] = " getblockcount - Show current block height";
strings_["console_help_getinfo"] = " getinfo - Show node information";
strings_["console_help_getmininginfo"] = " getmininginfo - Show mining status";
strings_["console_help_getpeerinfo"] = " getpeerinfo - Show connected peers";
strings_["console_help_gettotalbalance"] = " gettotalbalance - Show total balance";
strings_["console_help_help"] = " help - Show this help message";
strings_["console_help_setgenerate"] = " setgenerate - Control mining";
strings_["console_help_stop"] = " stop - Stop the daemon";
strings_["console_line_count"] = "%zu lines";
strings_["console_new_lines"] = "%d new lines";
strings_["console_no_daemon"] = "No daemon";
strings_["console_not_connected"] = "Error: Not connected to daemon";
strings_["console_rpc_reference"] = "RPC Command Reference";
strings_["console_search_commands"] = "Search commands...";
strings_["console_select_all"] = "Select All";
strings_["console_show_daemon_output"] = "Show daemon output";
strings_["console_show_errors_only"] = "Show errors only";
strings_["console_show_rpc_ref"] = "Show RPC command reference";
strings_["console_showing_lines"] = "Showing %zu of %zu lines";
strings_["console_starting_node"] = "Starting node...";
strings_["console_status_error"] = "Error";
strings_["console_status_running"] = "Running";
strings_["console_status_starting"] = "Starting";
strings_["console_status_stopped"] = "Stopped";
strings_["console_status_stopping"] = "Stopping";
strings_["console_status_unknown"] = "Unknown";
strings_["console_tab_completion"] = "Tab for completion";
strings_["console_type_help"] = "Type 'help' for available commands";
strings_["console_welcome"] = "Welcome to ObsidianDragon Console";
strings_["console_zoom_in"] = "Zoom in";
strings_["console_zoom_out"] = "Zoom out";
// --- Export All Keys Dialog ---
strings_["export_keys_btn"] = "Export Keys";
strings_["export_keys_danger"] = "DANGER: This will export ALL private keys from your wallet! Anyone with access to this file can steal your funds. Store it securely and delete after use.";
strings_["export_keys_include_t"] = "Include T-addresses (transparent)";
strings_["export_keys_include_z"] = "Include Z-addresses (shielded)";
strings_["export_keys_options"] = "Export options:";
strings_["export_keys_success"] = "Keys exported successfully";
strings_["export_keys_title"] = "Export All Private Keys";
// --- Export Transactions Dialog ---
strings_["export_tx_count"] = "Export %zu transactions to CSV file.";
strings_["export_tx_file_fail"] = "Failed to create CSV file";
strings_["export_tx_none"] = "No transactions to export";
strings_["export_tx_success"] = "Transactions exported successfully";
strings_["export_tx_title"] = "Export Transactions to CSV";
// --- Import Key Dialog ---
strings_["import_key_btn"] = "Import Key(s)";
strings_["import_key_formats"] = "Supported key formats:";
strings_["import_key_full_rescan"] = "(0 = full rescan)";
strings_["import_key_label"] = "Private Key(s):";
strings_["import_key_no_valid"] = "No valid keys found in input";
strings_["import_key_rescan"] = "Rescan blockchain after import";
strings_["import_key_start_height"] = "Start height:";
strings_["import_key_success"] = "Keys imported successfully";
strings_["import_key_t_format"] = "T-address WIF private keys";
strings_["import_key_title"] = "Import Private Key";
strings_["import_key_tooltip"] = "Enter one or more private keys, one per line.\nSupports both z-address and t-address keys.\nLines starting with # are treated as comments.";
strings_["import_key_warning"] = "Warning: Never share your private keys! Importing keys from untrusted sources can compromise your wallet.";
strings_["import_key_z_format"] = "Z-address spending keys (secret-extended-key-...)";
// --- Key Export Dialog ---
strings_["key_export_fetching"] = "Fetching key from wallet...";
strings_["key_export_private_key"] = "Private Key:";
strings_["key_export_private_warning"] = "Keep this key SECRET! Anyone with this key can spend your funds. Never share it online or with untrusted parties.";
strings_["key_export_reveal"] = "Reveal Key";
strings_["key_export_viewing_key"] = "Viewing Key:";
strings_["key_export_viewing_warning"] = "This viewing key allows others to see your incoming transactions and balance, but NOT spend your funds. Share only with trusted parties.";
// --- Market Tab ---
strings_["market_12h"] = "12h";
strings_["market_18h"] = "18h";
strings_["market_24h"] = "24h";
strings_["market_24h_volume"] = "24H VOLUME";
strings_["market_6h"] = "6h";
strings_["market_attribution"] = "Price data from NonKYC";
strings_["market_btc_price"] = "BTC PRICE";
strings_["market_no_history"] = "No price history available";
strings_["market_no_price"] = "No price data";
strings_["market_now"] = "Now";
strings_["market_pct_shielded"] = "%.0f%% Shielded";
strings_["market_portfolio"] = "PORTFOLIO";
strings_["market_price_unavailable"] = "Price data unavailable";
strings_["market_refresh_price"] = "Refresh price data";
strings_["market_trade_on"] = "Trade on %s";
// --- Mining Tab ---
strings_["mining_active"] = "Active";
strings_["mining_address_copied"] = "Mining address copied";
strings_["mining_all_time"] = "All Time";
strings_["mining_already_saved"] = "Pool URL already saved";
strings_["mining_block_copied"] = "Block hash copied";
strings_["mining_chart_1m_ago"] = "1m ago";
strings_["mining_chart_5m_ago"] = "5m ago";
strings_["mining_chart_now"] = "Now";
strings_["mining_chart_start"] = "Start";
strings_["mining_click"] = "Click";
strings_["mining_click_copy_address"] = "Click to copy address";
strings_["mining_click_copy_block"] = "Click to copy block hash";
strings_["mining_click_copy_difficulty"] = "Click to copy difficulty";
strings_["mining_connected"] = "Connected";
strings_["mining_connecting"] = "Connecting...";
strings_["mining_difficulty_copied"] = "Difficulty copied";
strings_["mining_est_block"] = "Est. Block";
strings_["mining_est_daily"] = "Est. Daily";
strings_["mining_filter_all"] = "All";
strings_["mining_filter_tip_all"] = "Show all earnings";
strings_["mining_filter_tip_pool"] = "Show pool earnings only";
strings_["mining_filter_tip_solo"] = "Show solo earnings only";
strings_["mining_idle_off_tooltip"] = "Enable idle mining";
strings_["mining_idle_on_tooltip"] = "Disable idle mining";
strings_["mining_local_hashrate"] = "Local Hashrate";
strings_["mining_mine"] = "Mine";
strings_["mining_mining_addr"] = "Mining Addr";
strings_["mining_network"] = "Network";
strings_["mining_no_blocks_yet"] = "No blocks found yet";
strings_["mining_no_payouts_yet"] = "No pool payouts yet";
strings_["mining_no_saved_addresses"] = "No saved addresses";
strings_["mining_no_saved_pools"] = "No saved pools";
strings_["mining_open_in_explorer"] = "Open in explorer";
strings_["mining_payout_address"] = "Payout Address";
strings_["mining_payout_tooltip"] = "Address to receive mining rewards";
strings_["mining_pool"] = "Pool";
strings_["mining_pool_hashrate"] = "Pool Hashrate";
strings_["mining_pool_url"] = "Pool URL";
strings_["mining_recent_blocks"] = "RECENT BLOCKS";
strings_["mining_recent_payouts"] = "RECENT POOL PAYOUTS";
strings_["mining_remove"] = "Remove";
strings_["mining_reset_defaults"] = "Reset Defaults";
strings_["mining_save_payout_address"] = "Save payout address";
strings_["mining_save_pool_url"] = "Save pool URL";
strings_["mining_saved_addresses"] = "Saved Addresses:";
strings_["mining_saved_pools"] = "Saved Pools:";
strings_["mining_shares"] = "Shares";
strings_["mining_show_chart"] = "Chart";
strings_["mining_show_log"] = "Log";
strings_["mining_solo"] = "Solo";
strings_["mining_starting"] = "Starting...";
strings_["mining_starting_tooltip"] = "Miner is starting...";
strings_["mining_stop"] = "Stop";
strings_["mining_stop_solo_for_pool"] = "Stop solo mining before starting pool mining";
strings_["mining_stop_solo_for_pool_settings"] = "Stop solo mining to change pool settings";
strings_["mining_stopping"] = "Stopping...";
strings_["mining_stopping_tooltip"] = "Miner is stopping...";
strings_["mining_syncing_tooltip"] = "Blockchain is syncing...";
strings_["mining_to_save"] = "to save";
strings_["mining_today"] = "Today";
strings_["mining_uptime"] = "Uptime";
strings_["mining_yesterday"] = "Yesterday";
// --- Peers Tab ---
strings_["peers_avg_ping"] = "Avg Ping";
strings_["peers_ban_24h"] = "Ban Peer 24h";
strings_["peers_ban_score"] = "Ban Score: %d";
strings_["peers_banned"] = "Banned";
strings_["peers_banned_count"] = "Banned: %d";
strings_["peers_best_block"] = "Best Block";
strings_["peers_blockchain"] = "BLOCKCHAIN";
strings_["peers_blocks"] = "Blocks";
strings_["peers_blocks_left"] = "%d blocks left";
strings_["peers_clear_all_bans"] = "Clear All Bans";
strings_["peers_click_copy"] = "Click to copy";
strings_["peers_connected"] = "Connected";
strings_["peers_connected_count"] = "Connected: %d";
strings_["peers_copy_ip"] = "Copy IP";
strings_["peers_dir_in"] = "In";
strings_["peers_dir_out"] = "Out";
strings_["peers_hash_copied"] = "Hash copied";
strings_["peers_hashrate"] = "Hashrate";
strings_["peers_in_out"] = "In/Out";
strings_["peers_longest"] = "Longest";
strings_["peers_longest_chain"] = "Longest Chain";
strings_["peers_memory"] = "Memory";
strings_["peers_no_banned"] = "No banned peers";
strings_["peers_no_connected"] = "No connected peers";
strings_["peers_no_tls"] = "No TLS";
strings_["peers_notarized"] = "Notarized";
strings_["peers_p2p_port"] = "P2P Port";
strings_["peers_protocol"] = "Protocol";
strings_["peers_received"] = "Received";
strings_["peers_refresh"] = "Refresh";
strings_["peers_refresh_tooltip"] = "Refresh peer list";
strings_["peers_refreshing"] = "Refreshing...";
strings_["peers_sent"] = "Sent";
strings_["peers_tt_id"] = "ID: %d";
strings_["peers_tt_received"] = "Received: %s";
strings_["peers_tt_sent"] = "Sent: %s";
strings_["peers_tt_services"] = "Services: %s";
strings_["peers_tt_start_height"] = "Start Height: %d";
strings_["peers_tt_synced"] = "Synced H/B: %d/%d";
strings_["peers_tt_tls_cipher"] = "TLS: %s";
strings_["peers_unban"] = "Unban";
strings_["peers_upper"] = "PEERS";
strings_["peers_version"] = "Version";
// --- QR Popup Dialog ---
strings_["qr_failed"] = "Failed to generate QR code";
strings_["qr_title"] = "QR Code";
// --- Receive Tab ---
strings_["click_copy_address"] = "Click to copy address";
strings_["click_copy_uri"] = "Click to copy URI";
strings_["failed_create_shielded"] = "Failed to create shielded address";
strings_["failed_create_transparent"] = "Failed to create transparent address";
strings_["new_shielded_created"] = "New shielded address created";
strings_["new_transparent_created"] = "New transparent address created";
strings_["payment_request_copied"] = "Payment request copied";
strings_["payment_uri_copied"] = "Payment URI copied";
// --- Request Payment Dialog ---
strings_["request_amount"] = "Amount (optional):";
strings_["request_copy_uri"] = "Copy URI";
strings_["request_description"] = "Generate a payment request that others can scan or copy. The QR code contains your address and optional amount/memo.";
strings_["request_label"] = "Label (optional):";
strings_["request_memo"] = "Memo (optional):";
strings_["request_payment_uri"] = "Payment URI:";
strings_["request_receive_address"] = "Receive Address:";
strings_["request_select_address"] = "Select address...";
strings_["request_shielded_addrs"] = "-- Shielded Addresses --";
strings_["request_title"] = "Request Payment";
strings_["request_transparent_addrs"] = "-- Transparent Addresses --";
strings_["request_uri_copied"] = "Payment URI copied to clipboard";
// --- Send Tab ---
strings_["send_amount"] = "Amount";
strings_["send_amount_details"] = "AMOUNT DETAILS";
strings_["send_amount_upper"] = "AMOUNT";
strings_["send_clear_fields"] = "Clear all form fields?";
strings_["send_copy_error"] = "Copy Error";
strings_["send_dismiss"] = "Dismiss";
strings_["send_error_copied"] = "Error copied to clipboard";
strings_["send_error_prefix"] = "Error: %s";
strings_["send_exceeds_available"] = "Exceeds available (%.8f)";
strings_["send_fee"] = "Fee";
strings_["send_fee_high"] = "High";
strings_["send_fee_low"] = "Low";
strings_["send_fee_normal"] = "Normal";
strings_["send_form_restored"] = "Form restored";
strings_["send_go_to_receive"] = "Go to Receive";
strings_["send_keep"] = "Keep";
strings_["send_network_fee"] = "NETWORK FEE";
strings_["send_no_balance"] = "No balance";
strings_["send_no_recent"] = "No recent sends";
strings_["send_recent_sends"] = "RECENT SENDS";
strings_["send_recipient"] = "RECIPIENT";
strings_["send_select_source"] = "Select a source address...";
strings_["send_sending_from"] = "SENDING FROM";
strings_["send_submitting"] = "Submitting transaction...";
strings_["send_switch_to_receive"] = "Switch to Receive to get your address and start receiving funds.";
strings_["send_tooltip_enter_amount"] = "Enter an amount to send";
strings_["send_tooltip_exceeds_balance"] = "Amount exceeds available balance";
strings_["send_tooltip_in_progress"] = "Transaction already in progress";
strings_["send_tooltip_invalid_address"] = "Enter a valid recipient address";
strings_["send_tooltip_not_connected"] = "Not connected to daemon";
strings_["send_tooltip_select_source"] = "Select a source address first";
strings_["send_tooltip_syncing"] = "Wait for blockchain to sync";
strings_["send_total"] = "Total";
strings_["send_tx_failed"] = "Transaction failed";
strings_["send_tx_sent"] = "Transaction sent!";
strings_["send_tx_success"] = "Transaction sent successfully!";
strings_["send_txid_copied"] = "TxID copied to clipboard";
strings_["send_txid_label"] = "TxID: %s";
strings_["send_valid_shielded"] = "Valid shielded address";
strings_["send_valid_transparent"] = "Valid transparent address";
strings_["send_wallet_empty"] = "Your wallet is empty";
strings_["send_yes_clear"] = "Yes, Clear";
// --- Shield Dialog ---
strings_["shield_check_status"] = "Check Status";
strings_["shield_completed"] = "Operation completed successfully!";
strings_["shield_description"] = "Shield your mining rewards by sending coinbase outputs from transparent addresses to a shielded address. This improves privacy by hiding your mining income.";
strings_["shield_from_address"] = "From Address:";
strings_["shield_funds"] = "Shield Funds";
strings_["shield_in_progress"] = "Operation in progress...";
strings_["shield_max_utxos"] = "Max UTXOs per operation";
strings_["shield_merge_done"] = "Shield/merge completed!";
strings_["shield_select_z"] = "Select z-address...";
strings_["shield_started"] = "Shield operation started";
strings_["shield_title"] = "Shield Coinbase Rewards";
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_["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";
strings_["merge_title"] = "Merge to Address";
// --- Transaction Details Dialog ---
strings_["tx_confirmations"] = "%d confirmations";
strings_["tx_details_title"] = "Transaction Details";
strings_["tx_from_address"] = "From Address:";
strings_["tx_id_label"] = "Transaction ID:";
strings_["tx_immature"] = "IMMATURE";
strings_["tx_mined"] = "MINED";
strings_["tx_received"] = "RECEIVED";
strings_["tx_sent"] = "SENT";
strings_["tx_to_address"] = "To Address:";
strings_["tx_view_explorer"] = "View on Explorer";
// --- Validate Address Dialog ---
strings_["validate_btn"] = "Validate";
strings_["validate_description"] = "Enter a DragonX address to check if it's valid and whether it belongs to this wallet.";
strings_["validate_invalid"] = "INVALID";
strings_["validate_is_mine"] = "This wallet owns this address";
strings_["validate_not_mine"] = "Not owned by this wallet";
strings_["validate_ownership"] = "Ownership:";
strings_["validate_results"] = "Results:";
strings_["validate_shielded_type"] = "Shielded (z-address)";
strings_["validate_status"] = "Status:";
strings_["validate_title"] = "Validate Address";
strings_["validate_transparent_type"] = "Transparent (t-address)";
strings_["validate_type"] = "Type:";
strings_["validate_valid"] = "VALID";
// Misc dialog/tab strings
strings_["ram_wallet_gb"] = "Wallet: %.1f GB";
strings_["ram_wallet_mb"] = "Wallet: %.0f MB";
strings_["ram_daemon_gb"] = "Daemon: %.1f GB (%s)";
strings_["ram_daemon_mb"] = "Daemon: %.0f MB (%s)";
strings_["ram_system_gb"] = "System: %.1f / %.0f GB";
strings_["shield_operation_id"] = "Operation ID: %s";
strings_["peers_peer_label"] = "Peer: %s";
strings_["error_format"] = "Error: %s";
strings_["key_export_click_retrieve"] = "Click to retrieve the key from your wallet";
strings_["key_export_viewing_keys_zonly"] = "Viewing keys are only available for shielded (z) addresses";
strings_["backup_source"] = "Source: %s";
strings_["export_keys_progress"] = "Exporting %d/%d...";
strings_["import_key_progress"] = "Importing %d/%d...";
strings_["click_to_copy"] = "Click to copy";
strings_["block_hash_copied"] = "Block hash copied";
}
const char* I18n::translate(const char* key) const

View File

@@ -57,6 +57,7 @@ public:
private:
I18n();
void loadBuiltinEnglish();
std::string current_locale_ = "en";
std::unordered_map<std::string, std::string> strings_;