feat(i18n): add English source + 8-language translations for 193 UI strings

Adds the i18n source for 193 previously-hardcoded UI strings (the
security / PIN / lock flow, first-run seed-backup wizard, witness-rebuild
shutdown dialog, and balance / mining / explorer labels) so they can be
localized. The TR() call-site wrapping rides in the accompanying UI commit.

- 193 keys added to loadBuiltinEnglish() (the English source of truth),
  including one pre-existing missing key (copied_to_clipboard).
- Additive res/lang/{de,es,fr,ja,ko,pt,ru,zh}.json (+193 each); every
  translation's printf format-signature was validated against English
  (0 mismatches) so the runtime validator accepts them.
- Rebuilt res/fonts/NotoSansCJK-Subset.ttf to cover ~30 new Han/Hangul
  glyphs introduced by the zh/ja/ko translations (tofu-free).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-01 19:36:50 -05:00
parent 4492aa3425
commit ed675f90d8
10 changed files with 1925 additions and 0 deletions

View File

@@ -730,6 +730,7 @@ void I18n::loadBuiltinEnglish()
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_["stratum_host_section"] = "MINING POOL HOSTING";
strings_["stratum_host"] = "Host a mining pool (stratum)";
strings_["tt_stratum_host"] = "Run a RandomX stratum pool server on this node so other RandomX miners can point at this computer. Requires a v1.3.0+ node and a daemon restart to apply.";
strings_["stratum_host_hint"] = "Miners connect to this computer on port 22769 (RPC port + 1000) with a RandomX stratum miner. Restart the daemon to apply.";
@@ -1540,6 +1541,175 @@ void I18n::loadBuiltinEnglish()
strings_["about_version"] = "Version:";
strings_["about_website"] = "Website";
// --- Help & FAQ ---
strings_["faq"] = "FAQ";
strings_["faq_title"] = "Help & FAQ";
strings_["faq_intro"] = "Answers about your wallet and the DragonX node. Search, or browse by topic below.";
strings_["faq_search_hint"] = "Search the FAQ\xE2\x80\xA6";
strings_["faq_open_tooltip"] = "Help & FAQ";
strings_["faq_no_results"] = "No results. Try a different search term.";
strings_["faq_group_wallet"] = "Wallet";
strings_["faq_group_daemon"] = "Daemon";
// Wallet subcategory titles
strings_["faq_w_gs_title"] = "Getting Started";
strings_["faq_w_addr_title"] = "Addresses & Privacy";
strings_["faq_w_send_title"] = "Sending & Receiving";
strings_["faq_w_bal_title"] = "Balance & Sync";
strings_["faq_w_sec_title"] = "Security & Encryption";
strings_["faq_w_seed_title"] = "Seed Phrase & Backup";
strings_["faq_w_chat_title"] = "Chat & Contacts";
strings_["faq_w_set_title"] = "Settings & Appearance";
// Daemon subcategory titles
strings_["faq_d_node_title"] = "The Full Node";
strings_["faq_d_sync_title"] = "Sync & Blockchain";
strings_["faq_d_mgmt_title"] = "Node Management";
strings_["faq_d_upd_title"] = "Updating the Node";
strings_["faq_d_mine_title"] = "Mining & Pools";
strings_["faq_d_net_title"] = "Peers & Network";
strings_["faq_d_perf_title"] = "Storage & Performance";
strings_["faq_d_trbl_title"] = "Troubleshooting";
// Wallet > Getting Started
strings_["faq_w_gs_1_q"] = "What is ObsidianDragon?";
strings_["faq_w_gs_1_a"] = "ObsidianDragon is a full-node wallet for DragonX (DRGX). It manages your coins and, on the desktop build, runs a DragonX full node (the daemon) in the background so your wallet verifies the blockchain itself instead of trusting a third-party server.\n\nThink of it as two parts working together: the wallet (keys, balances, sending) and the node (the blockchain and network). The questions here are split the same way \xE2\x80\x94 see the Wallet and Daemon tabs above.";
strings_["faq_w_gs_2_q"] = "How do I create a new wallet?";
strings_["faq_w_gs_2_a"] = "On first launch the setup wizard creates a wallet for you automatically. New wallets are backed by a secret recovery phrase (a list of words). Write that phrase down and keep it offline \xE2\x80\x94 it is the only way to restore your funds if this computer is lost.\n\nYou can review or back up the phrase any time from Settings > Backup & Data > Seed phrase.";
strings_["faq_w_gs_3_q"] = "How do I restore a wallet I already have?";
strings_["faq_w_gs_3_a"] = "Use the seed-phrase restore flow if you have a recovery phrase, or copy an existing wallet.dat file into the wallet's data directory before launch.\n\nAfter restoring, the node re-scans the blockchain to find your past transactions, so your balance and history may take a while to appear the first time.";
strings_["faq_w_gs_4_q"] = "What does the first-run setup do?";
strings_["faq_w_gs_4_a"] = "The wizard lets you pick an appearance/theme, optionally download a bootstrap to speed up the initial blockchain sync, and set up encryption and a PIN. You can skip any step and change all of these later in Settings.";
// Wallet > Addresses & Privacy
strings_["faq_w_addr_1_q"] = "What's the difference between transparent and shielded addresses?";
strings_["faq_w_addr_1_a"] = "Transparent addresses (they start with R or t) work like most coins: the amounts and addresses are public on the blockchain.\n\nShielded addresses (z-addresses, starting with zs) use zero-knowledge cryptography \xE2\x80\x94 the amount, sender, and receiver are encrypted on-chain. Balances held in shielded addresses are private.";
strings_["faq_w_addr_2_q"] = "Which address type should I use?";
strings_["faq_w_addr_2_a"] = "Prefer shielded (z) addresses whenever possible \xE2\x80\x94 they keep your balance and payment history private. DragonX is a privacy coin and shielded is the default for received funds.\n\nUse a transparent address only when a service you interact with cannot handle shielded addresses.";
strings_["faq_w_addr_3_q"] = "Should I reuse an address or make a new one?";
strings_["faq_w_addr_3_a"] = "For shielded addresses, reuse is fine and does not leak history. For transparent addresses, using a fresh address per payment improves privacy. Create new addresses from the Receive tab.";
strings_["faq_w_addr_4_q"] = "What is 'shielding'?";
strings_["faq_w_addr_4_a"] = "Shielding moves coins from a transparent address into a shielded one, making them private. Newly mined coins arrive transparent and are shielded for you automatically.\n\nYou can also shield manually from the wallet; a shield is just a special transaction, so it takes a normal confirmation time to complete.";
// Wallet > Sending & Receiving
strings_["faq_w_send_1_q"] = "How do I send funds?";
strings_["faq_w_send_1_a"] = "Open the Send tab, paste the recipient's address, enter an amount, and confirm. If the wallet is encrypted you'll be asked to unlock it for the transaction.\n\nSends to shielded addresses are private; sends to transparent addresses are public.";
strings_["faq_w_send_2_q"] = "What fee do I pay?";
strings_["faq_w_send_2_a"] = "DragonX fees are very low and are set automatically. The fee is shown before you confirm. You do not normally need to change it.";
strings_["faq_w_send_3_q"] = "Can I attach a message to a payment?";
strings_["faq_w_send_3_a"] = "Yes \xE2\x80\x94 when sending to a shielded (z) address you can include an encrypted memo. Only the recipient can read it. Transparent addresses do not support memos.";
strings_["faq_w_send_4_q"] = "I sent a payment but it says pending \xE2\x80\x94 why?";
strings_["faq_w_send_4_a"] = "A transaction is 'pending' until it is mined into a block and gains confirmations. This usually takes a minute or two. Shielded transactions also need the node to be synced to build the proof.\n\nIf a send stays pending unusually long, check that the node is connected and synced (see the status bar at the bottom of the window).";
// Wallet > Balance & Sync
strings_["faq_w_bal_1_q"] = "Why is my balance 0 or not updating?";
strings_["faq_w_bal_1_a"] = "While the node is still syncing the blockchain, your balance is incomplete and may read 0 \xE2\x80\x94 the wallet hasn't scanned all of your transactions yet. It fills in once syncing finishes.\n\nWatch the status bar at the bottom: it shows the connection state and block height. Once the node is synced, your balance is accurate.";
strings_["faq_w_bal_2_q"] = "What are confirmations?";
strings_["faq_w_bal_2_a"] = "Each new block mined on top of the block containing your transaction adds one confirmation. More confirmations mean the payment is more firmly settled. Received funds become spendable after the first confirmation.";
strings_["faq_w_bal_3_q"] = "What's the difference between total and spendable balance?";
strings_["faq_w_bal_3_a"] = "Total includes funds that are still confirming or are temporarily locked (for example, coins in the middle of being shielded). Spendable is what you can send right now. They converge as transactions confirm.";
// Wallet > Security & Encryption
strings_["faq_w_sec_1_q"] = "How do I encrypt my wallet?";
strings_["faq_w_sec_1_a"] = "Open Settings > Node & Security and set a passphrase (the SECURITY section). Encryption protects your private keys on disk, so someone with access to the files still cannot spend your coins.\n\nChoose a strong passphrase and don't lose it \xE2\x80\x94 there is no way to recover an encrypted wallet without it.";
strings_["faq_w_sec_2_q"] = "What is the PIN / lock screen?";
strings_["faq_w_sec_2_a"] = "The PIN locks the app's screen so balances and actions are hidden when you step away. It's a convenience lock on top of encryption; you set it up during the wizard or in Settings > Node & Security (encrypt the wallet first).";
strings_["faq_w_sec_3_q"] = "I forgot my passphrase \xE2\x80\x94 can it be recovered?";
strings_["faq_w_sec_3_a"] = "No. Wallet encryption cannot be bypassed. If you still have your seed recovery phrase, you can restore the wallet from it into a fresh wallet and set a new passphrase. Without either the passphrase or the seed phrase, the funds cannot be recovered.";
// Wallet > Seed Phrase & Backup
strings_["faq_w_seed_1_q"] = "How do I back up my recovery phrase?";
strings_["faq_w_seed_1_a"] = "Go to Settings > Backup & Data > Seed phrase. Write the words down on paper in order and store them somewhere safe and offline. Anyone with the phrase can spend your coins, so never store it in a photo, email, or cloud note.";
strings_["faq_w_seed_2_q"] = "My wallet has no recovery phrase \xE2\x80\x94 can I add one?";
strings_["faq_w_seed_2_a"] = "Older (legacy) wallets weren't seed-based. The wallet can migrate a legacy wallet into a modern seed-backed one: it creates a new seed wallet and sweeps your funds into it. Look for 'Migrate to seed\xE2\x80\xA6' in Settings > Backup & Data. This feature needs the current daemon version.";
strings_["faq_w_seed_3_q"] = "How do I restore from my recovery phrase?";
strings_["faq_w_seed_3_a"] = "Use the seed-restore flow when setting up a wallet and enter your words in order. The node then re-scans the chain to rebuild your balance and history, which can take a while the first time.";
strings_["faq_w_seed_4_q"] = "Should I also back up wallet.dat?";
strings_["faq_w_seed_4_a"] = "Your seed phrase is the primary backup and is enough to restore everything. A copy of the wallet.dat file is a convenient secondary backup that also preserves labels and settings. Keep any backup offline and private.";
// Wallet > Chat & Contacts
strings_["faq_w_chat_1_q"] = "What is the Chat feature?";
strings_["faq_w_chat_1_a"] = "Chat is an encrypted, on-chain messenger built into the wallet. Messages are sent as private shielded memos, so only you and your contact can read them.";
strings_["faq_w_chat_2_q"] = "How does my chat identity work?";
strings_["faq_w_chat_2_a"] = "Your chat identity is derived from your wallet's recovery phrase, so it travels with your wallet \xE2\x80\x94 restore the wallet and your identity comes back. You don't create a separate account or password.";
strings_["faq_w_chat_3_q"] = "How do contacts work?";
strings_["faq_w_chat_3_a"] = "Add a contact by their address in the Contacts tab, optionally with a name and avatar. Contacts can be kept private to the current wallet or shared across all wallets you open on this computer.";
// Wallet > Settings & Appearance
strings_["faq_w_set_1_q"] = "How do I change the theme?";
strings_["faq_w_set_1_a"] = "Open Settings > Appearance to pick a theme and accent. Several light and dark skins are included, and effects like blur can be toggled off for lower-powered machines.";
strings_["faq_w_set_2_q"] = "Can I change the language?";
strings_["faq_w_set_2_a"] = "Yes \xE2\x80\x94 Settings > Appearance has a language selector. The wallet ships with several translations; anything not yet translated falls back to English.";
strings_["faq_w_set_3_q"] = "The text is too small (or too large) \xE2\x80\x94 can I scale it?";
strings_["faq_w_set_3_a"] = "Use the font-scale option in Settings > Appearance. It scales the whole interface, which is handy on high-resolution (HiDPI) displays where the app might otherwise render small.";
strings_["faq_w_set_4_q"] = "How do I show fiat prices?";
strings_["faq_w_set_4_a"] = "Enable price fetching in Settings. The wallet then shows an approximate fiat value alongside balances and can display a small market chart. Prices are informational only.";
// Daemon > The Full Node
strings_["faq_d_node_1_q"] = "What is the daemon (dragonxd)?";
strings_["faq_d_node_1_a"] = "The daemon, dragonxd, is the DragonX full node. It downloads and verifies the entire blockchain, relays transactions to the network, and answers the wallet's queries. Running your own node means you don't have to trust anyone else's server.";
strings_["faq_d_node_2_q"] = "Embedded vs external node \xE2\x80\x94 what's the difference?";
strings_["faq_d_node_2_a"] = "By default the wallet launches and manages its own bundled node (embedded) \xE2\x80\x94 you don't have to do anything. If you already run dragonxd yourself, the wallet can connect to that external node instead. The wallet detects which situation it's in and behaves accordingly.";
strings_["faq_d_node_3_q"] = "Why run a full node at all?";
strings_["faq_d_node_3_a"] = "A full node validates every rule of the blockchain independently, so your wallet trusts math instead of a third party. It also strengthens the network. The trade-off is disk space and an initial sync.";
// Daemon > Sync & Blockchain
strings_["faq_d_sync_1_q"] = "What does 'Processing blocks' at startup mean?";
strings_["faq_d_sync_1_a"] = "On launch the node loads and validates blocks before it can serve the wallet. The 'Processing blocks / Applying blocks to build the current chain state' screen is that warm-up. It's normal; the wallet becomes usable once the node finishes and reports its height.";
strings_["faq_d_sync_2_q"] = "What is 'Rebuilding witness cache'?";
strings_["faq_d_sync_2_a"] = "For your shielded funds the node keeps cryptographic 'witnesses' that let you spend privately. After certain restarts or updates it rebuilds this cache by re-scanning recent blocks. On a wallet with many transactions this can take several minutes and use extra memory.\n\nIt is not stuck \xE2\x80\x94 let it finish. Force-quitting in the middle just makes it restart the rebuild next time.";
strings_["faq_d_sync_3_q"] = "Why is syncing slow when I'm almost caught up?";
strings_["faq_d_sync_3_a"] = "Near the chain tip, work that scans your wallet (checking balances and notes) competes with the node for the same internal lock, which can slow down connecting the final blocks on a large wallet. Recent versions throttle that scanning so the node can catch up. Staying on a lighter tab (or just waiting) lets it finish faster.";
strings_["faq_d_sync_4_q"] = "How long does the initial sync take?";
strings_["faq_d_sync_4_a"] = "The first sync downloads and verifies the whole chain and can take a while depending on your connection and disk. You can speed it up dramatically by enabling the bootstrap download in the setup wizard, which fetches a recent verified copy of the chain data.";
// Daemon > Node Management
strings_["faq_d_mgmt_1_q"] = "How do I start or stop the node?";
strings_["faq_d_mgmt_1_a"] = "The embedded node starts automatically with the wallet and stops when appropriate, so you normally don't manage it by hand. Advanced controls (including restarting the daemon) live in Settings > Node & Security.";
strings_["faq_d_mgmt_2_q"] = "What does 'close external daemon on exit' do?";
strings_["faq_d_mgmt_2_a"] = "If you connect the wallet to a node you started yourself, this option decides whether closing the wallet also shuts that node down. Leave it off if you want your node to keep running after you close the wallet.";
strings_["faq_d_mgmt_3_q"] = "Where is the blockchain and wallet data stored?";
strings_["faq_d_mgmt_3_a"] = "Node and wallet data live in the DragonX data directory under your user profile (for example, in AppData on Windows or your home folder on Linux/macOS). The blockchain is the large part; keep enough free disk space for it to grow.";
// Daemon > Updating the Node
strings_["faq_d_upd_1_q"] = "How do I update the node?";
strings_["faq_d_upd_1_a"] = "Open Settings > Node & Security > Daemon binary and use 'Check for updates\xE2\x80\xA6'. The wallet downloads the latest verified node build and installs it; the new version takes effect the next time the daemon starts.";
strings_["faq_d_upd_2_q"] = "Can I install a specific node version?";
strings_["faq_d_upd_2_a"] = "Yes \xE2\x80\x94 the update dialog lists every release so you can pick a specific or older build. Be cautious downgrading: an older node may not accept blockchain data written by a newer one and could need a re-index.";
strings_["faq_d_upd_3_q"] = "Is the update safe?";
strings_["faq_d_upd_3_a"] = "Every downloaded node archive is verified against a checksum and a cryptographic signature before it's installed. If verification fails, the wallet refuses the update.";
// Daemon > Mining & Pools
strings_["faq_d_mine_1_q"] = "How do I mine DragonX?";
strings_["faq_d_mine_1_a"] = "The Mining tab lets you mine with your CPU. DragonX uses the RandomX algorithm, which is designed for regular processors. Set the number of threads and start \xE2\x80\x94 rewards accrue to your wallet.";
strings_["faq_d_mine_2_q"] = "Solo vs pool mining \xE2\x80\x94 which should I choose?";
strings_["faq_d_mine_2_a"] = "Solo mining sends rewards straight to you but pays only when you find a block, which is infrequent unless you have a lot of hashrate. Pool mining shares work with others for smaller, steadier payouts. The Mining tab supports both.";
strings_["faq_d_mine_3_q"] = "How do I update the miner?";
strings_["faq_d_mine_3_a"] = "The Mining tab's pool section has an 'Update miner\xE2\x80\xA6' button that downloads, verifies, and installs the latest optimized DragonX miner build. Like the node updater, each download is checksum- and signature-verified before install.";
strings_["faq_d_mine_4_q"] = "Can I host a mining pool?";
strings_["faq_d_mine_4_a"] = "The current node can run a built-in stratum server so other miners can point at your machine. There's a toggle for it under Settings > Node & Security. By default it only listens locally; exposing it to other computers requires opening it up deliberately.";
// Daemon > Peers & Network
strings_["faq_d_net_1_q"] = "The wallet shows no peers or connections \xE2\x80\x94 what's wrong?";
strings_["faq_d_net_1_a"] = "Right after launch the node needs a moment to find peers, so a brief '0 peers' is normal. If it persists, check your internet connection and that a firewall isn't blocking the node. The node finds peers automatically through built-in seeds.";
strings_["faq_d_net_2_q"] = "Is my connection to the network encrypted?";
strings_["faq_d_net_2_a"] = "Yes \xE2\x80\x94 DragonX nodes talk to each other over TLS, so peer connections are encrypted. The wallet also talks to its own node over a secure local channel.";
// Daemon > Storage & Performance
strings_["faq_d_perf_1_q"] = "How much disk does the node use, and can I tune memory?";
strings_["faq_d_perf_1_a"] = "The blockchain is the large item and grows over time, so keep several gigabytes free. The node uses a database cache for speed; the bundled defaults are tuned for typical machines. Advanced users can adjust the node's database cache by editing dbcache in its config file (DRAGONX.conf).";
strings_["faq_d_perf_2_q"] = "How do I make the initial sync faster?";
strings_["faq_d_perf_2_a"] = "Enable the bootstrap download (offered in the setup wizard) to fetch a recent, verified copy of the chain instead of validating every block from scratch. A fast disk (SSD) also helps a lot.";
// Daemon > Troubleshooting
strings_["faq_d_trbl_1_q"] = "The node seems stuck on 'Activating best chain' \xE2\x80\x94 is it frozen?";
strings_["faq_d_trbl_1_a"] = "Usually not. On a large wallet the node can spend several minutes rebuilding shielded witnesses or applying blocks, during which it looks paused and may be slow to answer. Give it time \xE2\x80\x94 the debug log (Settings) shows steady progress if it's working.\n\nAvoid force-quitting during this phase; it restarts the work from scratch next launch.";
strings_["faq_d_trbl_2_q"] = "What is 'degraded mode'?";
strings_["faq_d_trbl_2_a"] = "If a wallet file is recovered but part of its key data is missing, the node may open it in a limited 'degraded' mode where it can't derive new addresses or shield funds. The safest fix is to restore from your seed recovery phrase into a fresh wallet.";
strings_["faq_d_trbl_3_q"] = "When should I re-index or re-scan?";
strings_["faq_d_trbl_3_a"] = "A re-scan makes the wallet re-read the chain to rediscover your transactions (useful after importing keys). A re-index rebuilds the node's blockchain database and is only needed if that database is corrupted or incompatible after a version change. Both can take a while; start them from Settings > Node & Security.";
strings_["faq_d_trbl_4_q"] = "The node is using a lot of memory \xE2\x80\x94 is that normal?";
strings_["faq_d_trbl_4_a"] = "Memory use spikes during heavy work like a witness rebuild or an initial sync, then drops back down once it finishes. Sustained high memory at idle is unusual \xE2\x80\x94 restarting the wallet clears it. On a low-RAM machine, make sure other memory-heavy apps aren't competing.";
// --- Address Book Dialog ---
strings_["address_book_add"] = "Add Address";
strings_["address_book_add_new"] = "Add New";
@@ -2354,6 +2524,217 @@ void I18n::loadBuiltinEnglish()
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";
// ---- i18n audit 2026-09: wrap previously-hardcoded UI strings ----
// app_security.cpp — encryption / PIN / lock flow
strings_["sec_restart_daemon_for_encryption"] = "Please restart your daemon for encryption to take effect.";
strings_["sec_encrypting_wallet"] = "Encrypting wallet...";
strings_["sec_wallet_encrypted_restarting_daemon"] = "Wallet encrypted. Restarting daemon...";
strings_["sec_wallet_encrypted_successfully"] = "Wallet encrypted successfully";
strings_["sec_encryption_failed_prefix"] = "Encryption failed: ";
strings_["sec_wallet_encrypted_and_pin_set"] = "Wallet encrypted & PIN set";
strings_["sec_wallet_encrypted_but_pin_vault_failed"] = "Wallet encrypted but PIN vault failed";
strings_["sec_couldnt_lock_wallet"] = "Couldn't lock the wallet — it is still unlocked. Check the daemon connection.";
strings_["sec_changing_passphrase"] = "Changing passphrase...";
strings_["sec_passphrase_changed_successfully"] = "Passphrase changed successfully";
strings_["sec_failed_prefix"] = "Failed: ";
strings_["sec_encryption_did_not_complete"] = "Wallet encryption did not complete — your wallet is NOT encrypted. Open Settings to finish encrypting it.";
strings_["sec_wallet_locked_title"] = "Wallet Locked";
strings_["sec_too_many_attempts_wait"] = "Too many attempts. Wait %.0f seconds...";
strings_["sec_mode_passphrase"] = " Passphrase";
strings_["sec_use_passphrase_instead"] = "Use passphrase instead";
strings_["sec_use_pin_instead"] = "Use PIN instead";
strings_["sec_unlocking_fmt"] = "Unlocking%s";
strings_["sec_unlock_button"] = "Unlock";
strings_["sec_not_connected_to_daemon"] = "Not connected to daemon";
strings_["sec_unlock_failed_prefix"] = "Unlock failed: ";
strings_["sec_incorrect_passphrase_decrypt"] = "Incorrect passphrase";
strings_["sec_importing_keys_rescanning"] = "Importing keys & rescanning blockchain — wallet is usable while this runs";
strings_["sec_encrypted_backup_suffix"] = "\nEncrypted backup: wallet.dat.encrypted.bak";
strings_["sec_wallet_decrypted_all_keys_imported"] = "Wallet decrypted successfully! All keys imported.";
strings_["sec_total_elapsed_fmt"] = "Total elapsed: %dm %02ds";
strings_["sec_verifying_passphrase"] = "Verifying passphrase...";
strings_["sec_incorrect_passphrase_pin_setup"] = "Incorrect passphrase";
strings_["sec_pin_set_successfully"] = "PIN set successfully";
strings_["sec_failed_to_create_vault"] = "Failed to create vault";
strings_["sec_not_connected_to_daemon_pin"] = "Not connected to daemon";
strings_["sec_changing_pin"] = "Changing PIN...";
strings_["sec_pin_changed_successfully"] = "PIN changed successfully";
strings_["sec_incorrect_current_pin"] = "Incorrect current PIN";
strings_["sec_internal_error_change_pin"] = "Internal error";
strings_["sec_verifying_pin"] = "Verifying PIN...";
strings_["sec_pin_removed"] = "PIN removed";
strings_["sec_incorrect_pin_remove"] = "Incorrect PIN";
strings_["sec_internal_error_remove_pin"] = "Internal error";
// app.cpp — wizard, seed backup, shutdown, daemon/miner lifecycle
strings_["appx_creating_your_wallet"] = "Creating your wallet…";
strings_["appx_create_failed_prefix"] = "Create failed: ";
strings_["appx_back_up_seed_phrase_title"] = "Back up your seed phrase";
strings_["appx_seed_backup_warning"] = "These 24 words are the ONLY way to restore your wallet. Write them down in order, store them offline, and never share them. If you lose them, your funds are gone forever.";
strings_["appx_birthday_block_height"] = "Birthday (block height): %llu — back this up too.";
strings_["appx_ive_written_it_down"] = "I've written it down";
strings_["appx_copy"] = "Copy";
strings_["appx_skip_anyway"] = "Skip anyway";
strings_["appx_skip"] = "Skip";
strings_["appx_seed_not_backed_up_warning"] = "You have not backed up your seed — funds could be lost. Skip anyway?";
strings_["appx_confirm_your_backup"] = "Confirm your backup";
strings_["appx_tap_words_in_order"] = "Tap the words in the correct order to confirm you saved them.";
strings_["appx_progress_n_of_n"] = "Progress: %d / %d";
strings_["appx_not_next_word"] = " — that's not the next word";
strings_["appx_done"] = "Done";
strings_["appx_wallet_created_and_backed_up"] = "Wallet created and backed up.";
strings_["appx_back"] = "Back";
strings_["appx_restoring_your_wallet"] = "Restoring your wallet…";
strings_["appx_recovery_phrase_word_count"] = "Recovery phrase should be 24 words — you have %d.";
strings_["appx_could_not_start_restore"] = "Could not start restore";
strings_["appx_node_rebuilding_witness_cache"] = "Node is rebuilding its witness cache";
strings_["appx_stopping_node_discards_rebuild"] = "Stopping the node now discards the in-progress rebuild and restarts it (several minutes) the next time you open the wallet. You can keep the node running instead.";
strings_["appx_keep_node_running_and_quit"] = "Keep node running & quit";
strings_["appx_stop_anyway_and_quit"] = "Stop anyway & quit";
strings_["appx_cancel"] = "Cancel";
strings_["appx_last_used_wallet_not_found_prefix"] = "Your last-used wallet file (";
strings_["appx_last_used_wallet_not_found_suffix"] = ") was not found — opened the default wallet instead. If you moved it, restore it and switch back from the wallet list.";
strings_["appx_wallet_open_failed_prefix"] = "Wallet open failed: ";
strings_["appx_blockchain_rescan_complete"] = "Blockchain rescan complete";
strings_["appx_miner_stopped_unexpectedly"] = "Miner stopped unexpectedly.";
strings_["appx_miner_stopped_prefix"] = "Miner stopped: ";
strings_["appx_pool_miner_connected_and_hashing"] = "Pool miner connected and hashing.";
strings_["appx_bootstrap_complete_reconciling"] = "Bootstrap complete — reconciling your wallet with the new chain data.";
strings_["appx_blockchain_data_deleted"] = "Blockchain data deleted (%d items). The daemon is restarting to re-sync from the network.";
strings_["appx_invalid_payment_uri_prefix"] = "Invalid payment URI: ";
strings_["appx_payment_request_loaded"] = "Payment request loaded";
strings_["appx_fullnode_lifecycle_unavailable_lite"] = "Full-node lifecycle actions are unavailable in lite build";
strings_["appx_blockchain_maintenance_in_progress"] = "A blockchain maintenance operation is already in progress.";
strings_["appx_node_busy_restarting"] = "The node is busy restarting — try again in a moment.";
strings_["appx_restarting_daemon_rescan_flag"] = "Restarting daemon with -rescan flag...";
strings_["appx_restarting_daemon_zapwallettxes"] = "Restarting daemon with -zapwallettxes=2 (wallet repair)...";
strings_["appx_no_bundled_daemon_to_install"] = "This build has no bundled daemon to install";
strings_["appx_no_embedded_daemon_to_install"] = "This build has no embedded daemon to install";
strings_["appx_daemon_reinstall_in_progress"] = "The daemon reinstall is already in progress.";
strings_["appx_installing_bundled_daemon"] = "Installing bundled daemon — the node will stop, update, and restart...";
strings_["appx_stopping_daemon_deleting_blockchain"] = "Stopping daemon and deleting blockchain data...";
strings_["appx_stopping_pool_miner"] = "Stopping pool miner...";
strings_["appx_disconnecting"] = "Disconnecting...";
strings_["appx_sending_stop_command_to_daemon"] = "Sending stop command to daemon...";
strings_["appx_cleaning_up"] = "Cleaning up...";
strings_["appx_shutdown_complete"] = "Shutdown complete";
strings_["appx_n_seconds"] = "%d seconds";
strings_["appx_n_min_n_sec"] = "%d min %d sec";
strings_["appx_still_status_prefix"] = "Still \"";
strings_["appx_still_status_suffix"] = "\" — force quitting now may corrupt chain data.";
strings_["appx_rebuilding_witness_cache_blocks_left"] = "Rebuilding witness cache %.0f%% — %d blocks left";
strings_["appx_rebuilding_witness_cache_pct"] = "Rebuilding witness cache %.0f%%";
strings_["appx_setting_initial_sapling_witnesses"] = "Setting initial Sapling witnesses %.0f%%";
strings_["appx_rebuilding_sapling_note_witnesses"] = "Rebuilding Sapling note witnesses…";
strings_["appx_syncing_pct_block_n_of_n"] = "Syncing %.1f%% — Block %d / %d";
strings_["appx_last_block_n"] = "Last block: %d";
strings_["appx_encrypting_wallet"] = "Encrypting wallet...";
strings_["appx_waiting_for_daemon_to_encrypt_wallet"] = "Waiting for daemon to encrypt wallet...";
strings_["appx_daemon_error"] = "Daemon Error";
strings_["appx_use_settings_restart_daemon_hint"] = "Use Settings > Restart Daemon to try again";
strings_["appx_copied_clipboard_autoclears"] = "Copied — clipboard auto-clears in 45s";
strings_["appx_dragonxd_output"] = "dragonxd output";
strings_["appx_theme_prefix"] = "Theme: ";
strings_["appx_low_spec_mode_enabled"] = "Low-spec mode enabled";
strings_["appx_low_spec_mode_disabled"] = "Low-spec mode disabled";
strings_["appx_theme_effects_enabled"] = "Theme effects enabled";
strings_["appx_theme_effects_disabled"] = "Theme effects disabled";
strings_["appx_simple_background_enabled"] = "Simple background enabled";
strings_["appx_simple_background_disabled"] = "Simple background disabled";
// balance_tab.cpp
strings_["baltab_shielded_amount"] = "Shielded %.8f";
strings_["baltab_transparent_amount"] = "Transparent %.8f";
strings_["baltab_market_price_4dp"] = "Market: $%.4f";
strings_["baltab_market_price_8dp"] = "Market: $%.8f";
strings_["baltab_pct_of_total_zaddr"] = "%.0f%% of total · %d Z-addr";
strings_["baltab_t_addresses_count"] = "%d T-addresses";
strings_["baltab_pct_change_24h"] = "%s%.1f%% 24h";
strings_["baltab_total_balance"] = "Total Balance";
strings_["baltab_shielded"] = "Shielded";
strings_["baltab_transparent"] = "Transparent";
strings_["baltab_market"] = "Market";
// settings_window.cpp
strings_["swin_invalid_suffix"] = " (invalid)";
strings_["swin_theme_list_refreshed"] = "Theme list refreshed";
strings_["swin_connection_successful"] = "Connection successful!\ndragonxd version: ";
strings_["swin_connection_failed"] = "Connection failed: ";
strings_["swin_rpc_client_not_initialized"] = "RPC client not initialized";
strings_["swin_rescan_started_from_block"] = "Rescan started from block ";
strings_["swin_rescan_to"] = " to ";
strings_["swin_rescan_failed"] = "Rescan failed: ";
strings_["swin_ztx_history_cleared"] = "Z-transaction history cleared";
strings_["swin_no_history_file_found"] = "No history file found";
strings_["swin_settings_saved"] = "Settings saved";
// settings_page.cpp / explorer_tab.cpp / block_info_dialog.cpp
strings_["grpa_tab_appearance"] = "Appearance";
strings_["grpa_tab_wallet"] = "Wallet";
strings_["grpa_tab_backup_data"] = "Backup & Data";
strings_["grpa_tab_node_security"] = "Node & Security";
strings_["grpa_tab_explorer"] = "Explorer";
strings_["grpa_tab_chat"] = "Chat";
strings_["grpa_tab_about"] = "About";
strings_["grpa_enter_private_key_to_import"] = "Enter a private key to import.";
strings_["grpa_invalid_suffix"] = " (invalid)";
strings_["grpa_seed_demo_chat"] = "Seed demo chat";
strings_["grpa_dbg_addrman"] = "Peer address tracking and management";
strings_["grpa_dbg_alert"] = "Alert system messages";
strings_["grpa_dbg_bench"] = "Benchmark timings for operations";
strings_["grpa_dbg_coindb"] = "Coin database read/write operations";
strings_["grpa_dbg_db"] = "Berkeley DB operations";
strings_["grpa_dbg_estimatefee"] = "Fee estimation algorithm";
strings_["grpa_dbg_http"] = "HTTP RPC server activity";
strings_["grpa_dbg_libevent"] = "Libevent networking library";
strings_["grpa_dbg_lock"] = "Lock contention debugging";
strings_["grpa_dbg_mempool"] = "Transaction memory pool activity";
strings_["grpa_dbg_net"] = "Network connections and messages";
strings_["grpa_dbg_paymentdisclosure"] = "Payment disclosure protocol";
strings_["grpa_dbg_pow"] = "Proof-of-work mining activity";
strings_["grpa_dbg_proxy"] = "SOCKS5 proxy connections";
strings_["grpa_dbg_prune"] = "Block pruning operations";
strings_["grpa_dbg_rand"] = "Random number generation";
strings_["grpa_dbg_reindex"] = "Blockchain reindexing progress";
strings_["grpa_dbg_rpc"] = "RPC command processing";
strings_["grpa_dbg_selectcoins"] = "Coin selection for transactions";
strings_["grpa_dbg_tor"] = "Tor integration and circuit info";
strings_["grpa_dbg_zmq"] = "ZeroMQ notification system";
strings_["grpa_dbg_zrpc"] = "Shielded (z-addr) RPC operations";
strings_["grpa_sec_ago"] = "%lld sec ago";
strings_["grpa_min_ago"] = "%lld min ago";
strings_["grpa_hr_ago"] = "%lld hr ago";
strings_["grpa_days_ago"] = "%lld days ago";
strings_["grpa_showing_first_100_of"] = "... showing first 100 of %d";
strings_["grpa_error_prefix"] = "Error: ";
strings_["grpa_invalid_response_from_daemon"] = "Invalid response from daemon";
strings_["grpa_current_block_paren"] = "(Current: %d)";
strings_["grpa_unexpected_getblockhash_result"] = "unexpected getblockhash result";
// receive / chat / send / transaction_details
strings_["grpb_new_badge_suffix"] = " [NEW]";
strings_["grpb_tooltip_address_balance"] = "%s\nBalance: %.8f %s%s";
strings_["grpb_selected_suffix"] = "\n(selected)";
strings_["grpb_preview_msg_payment_through"] = "Did the payment go through? 🙂";
strings_["grpb_preview_msg_yep_confirmed"] = "Yep — just confirmed ✅";
strings_["grpb_preview_msg_sending_rest"] = "Sending the rest now 👍";
strings_["grpb_max"] = "Max";
strings_["grpb_undo_clear"] = "Undo Clear";
strings_["grpb_copy"] = "Copy";
// bootstrap / mining_* / key_export
strings_["grpc_bootstrap_not_initialized"] = "Bootstrap not initialized";
strings_["grpc_bootstrap_failed"] = "Bootstrap failed";
strings_["grpc_na"] = "N/A";
strings_["grpc_key_not_available"] = "Key not available for this address";
strings_["grpc_benchmark_takes_secs"] = "Benchmark takes ~%ds and interrupts mining. Click again to start.";
strings_["grpc_hashrate_fee"] = "%s %s%% fee";
strings_["grpc_benchmark_inconclusive"] = "Benchmark inconclusive: no hashrate samples were recorded. Check the pool connection and try again.";
// misc pre-existing missing keys
strings_["copied_to_clipboard"] = "Copied to clipboard";
}
const char* I18n::translate(const char* key) const