diff --git a/CLAUDE.md b/CLAUDE.md index f17348d..661014e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -89,6 +89,14 @@ Settings → **NODE & SECURITY → DAEMON BINARY** has a **"Check for updates… **Signature verification is enforced** (`kDaemonRequireSignature = true` in `src/util/daemon_updater.h`), checked against `kDaemonSignaturePublicKeyBase64`. **Consequence for releases:** every `dragonx` release MUST ship a detached `.sig` per platform archive or the in-app updater refuses it (as of v1.0.2 the releases publish SHA-256 but **no** signatures yet — sign + upload them to enable in-app updates). To cut a release: `scripts/sign-daemon-release.sh sign dragonx--{linux-amd64,macos,win64}.zip` (OpenSSL-based) and upload each `.sig` next to its `.zip`. The signing **secret key stays offline** (gitignored `*.ed25519.key`; this repo's is `dragonx-daemon.ed25519.key`); only the base64 public key is pinned. To rotate: `scripts/sign-daemon-release.sh keygen` and update `kDaemonSignaturePublicKeyBase64`. The generic SHA-256 / ed25519 primitives are shared with the miner updater (`util::sha256Hex` / `util::verifyXmrigSignature`). +## Seed phrase & migrate-to-seed (full node) + +Full-node wallets are **BIP39-mnemonic-backed** and can **migrate a legacy (non-mnemonic) wallet into a seed wallet**. All of this **requires the `hd-transparent-keys`/`dev` daemon** (`z_exportmnemonic` + `-usemnemonic`); the older bundled binary lacks those RPCs, so these features degrade gracefully (chat falls back to a `z_exportkey` identity; the backup screen shows a "legacy wallet" note). The daemon source is vendored at `external/dragonx/` (build with its own `./build.sh`); deploy the built `dragonxd`/`dragonx-cli`/`dragonx-tx` into the wallet's daemon dir (`build/*/bin`) or via the daemon updater. + +- **New wallets get a phrase.** `EmbeddedDaemon::getChainParams()` always passes `-usemnemonic=1`. The daemon reads it **only inside `GenerateNewSeed()` when a wallet has no seed yet**, so it is inert on existing wallets (safe to pass unconditionally) and makes every fresh wallet mnemonic-backed. +- **Back up seed phrase.** Settings → Backup & Data → "Seed phrase" opens `renderSeedBackupDialog` (`App::exportSeedPhrase` → `z_exportmnemonic`, wiped via `sodium_memzero`). A one-time nudge (`maybeRemindSeedBackup`, settings flag `seed_backup_reminded`) reminds mnemonic-wallet users to back up. +- **Migrate-to-seed** (`showSeedMigrationDialog` / `renderSeedMigrationDialog`, state machine `SeedMigrationStep`). **Phase 1 — create:** `daemon::SeedWalletCreator` runs a **second, isolated `dragonxd`** on its own port + throwaway datadir (`/seed-migrate/DRAGONX`, basename MUST be the acname; `-usemnemonic=1 -connect=0`; RPC is plaintext http, not TLS), mints a mnemonic wallet, exports its seed + a sweep-target z-address, then stops. Uses the one-shot `EmbeddedDaemon::setNextStartOverride` + `setSkipPortCheck`. **Phase 2 — sweep + adopt:** `z_mergetoaddress ["ANY_TADDR","ANY_ZADDR"]` sweeps all funds to the new address; a **Confirming gate** (`pollSweepStatus`) only allows adopt once the sweep tx is **mined (≥1 conf) AND the legacy balance is ~0** (offering a remainder re-sweep); adopt (`beginAdoptSeedWallet`, background) stops the daemon, moves `wallet.dat` aside to a **timestamped `.bak` (never deleted, restored on failure)**, installs the new wallet, and restarts with `-rescan`. Fund-moving code — **two rounds of adversarial review + a live mainnet run** gate it; the pending stage persists (`seed_migration_*` settings) so a restart resumes at sweep/confirm. + ## Versioning The version has a **single source of truth**: `project(... VERSION 1.2.0 ...)` plus `DRAGONX_VERSION_SUFFIX` in `CMakeLists.txt`. CMake generates `build/.../generated/dragonx_generated_version.h` from `src/config/version.h.in`. Do not hand-edit generated version output or hardcode version strings — bump the `project()` version in `CMakeLists.txt`. diff --git a/res/fonts/NotoSansCJK-Subset.ttf b/res/fonts/NotoSansCJK-Subset.ttf index 403b797..e264caf 100644 Binary files a/res/fonts/NotoSansCJK-Subset.ttf and b/res/fonts/NotoSansCJK-Subset.ttf differ diff --git a/res/lang/de.json b/res/lang/de.json index 7600fcb..d4278c9 100644 --- a/res/lang/de.json +++ b/res/lang/de.json @@ -383,6 +383,36 @@ "merge_funds": "Gelder zusammenführen", "merge_started": "Zusammenführung gestartet", "merge_title": "An Adresse zusammenführen", + "mig_adopt": "Dies zu meiner Wallet machen", + "mig_adopting": "Ihre neue Wallet wird installiert und neu gescannt…", + "mig_backed_up": "Ich habe meine Wiederherstellungsphrase aufgeschrieben", + "mig_balance": "Aktuelles Wallet-Guthaben: %.8f DRGX (abzüglich einer kleinen Gebühr)", + "mig_confirming": "Es wird auf die Bestätigung der Übertragung in der Blockchain gewartet, bevor die Wallet gewechselt wird — dies garantiert, dass Ihre Gelder tatsächlich verschoben wurden.", + "mig_confs": "Übertragungsbestätigungen: %d", + "mig_continue_sweep": "Weiter zur Übertragung", + "mig_copy_seed": "Phrase kopieren", + "mig_create": "Seed-Wallet erstellen", + "mig_discard": "Migration verwerfen", + "mig_done": "Migration abgeschlossen. Ihre Wallet ist nun durch Ihre Wiederherstellungsphrase gesichert.", + "mig_done_btn": "Fertig", + "mig_done_detail": "Der Daemon führt einen Neuscan durch, um Ihre Gelder anzuzeigen — das kann einige Minuten dauern. Ihre vorherige Wallet wurde als .bak im Datenordner gespeichert.", + "mig_intro": "Dies erstellt eine brandneue Wallet, die durch eine 24-Wort-Wiederherstellungsphrase gesichert ist, in einem isolierten Knoten, damit Sie Ihre Gelder dorthin übertragen können. Ihre aktuelle Wallet wird NICHT verändert und in diesem Schritt werden KEINE Gelder verschoben — Sie sichern zunächst die neue Wiederherstellungsphrase und übertragen Ihre Gelder dann in einem separaten, bestätigten Schritt.", + "mig_later": "Später", + "mig_receive_addr": "Empfangsadresse der neuen Wallet:", + "mig_remainder": "Einige Gelder befinden sich noch in Ihrer alten Wallet (zu viele Eingänge für eine einzelne Transaktion) — übertragen Sie den Rest, bevor Sie wechseln.", + "mig_remaining": "Verbleibend in alter Wallet: %.8f DRGX", + "mig_seed_warning": "Schreiben Sie diese 24 Wörter der Reihe nach auf und bewahren Sie sie offline auf. Sie sind die einzige Sicherung Ihrer neuen Wallet — wenn Sie sie verlieren, sind die migrierten Gelder für immer verloren.", + "mig_step1_done": "Schritt 1 von 2 abgeschlossen — Ihre Gelder wurden noch NICHT verschoben. Sie in diese neue Wallet zu übertragen ist der nächste Schritt.", + "mig_sweep_all": "Alle Gelder übertragen", + "mig_sweep_intro": "Übertragen Sie nun alle Gelder aus Ihrer aktuellen Wallet in die neue Seed-Wallet. Dies sendet eine einzelne Transaktion an die Adresse der neuen Wallet; Ihre Wiederherstellungsphrase (bereits gesichert) kontrolliert die Gelder von nun an.", + "mig_sweep_remaining": "Rest übertragen", + "mig_sweeping": "Ihre Gelder werden in die neue Wallet übertragen…", + "mig_title": "Zu einer Seed-Wallet migrieren", + "mig_to": "An: ", + "mig_txid": "txid: ", + "mig_unlock_first": "Entsperren Sie zuerst Ihre Wallet, um daraus auszugeben.", + "mig_waiting_mine": "Es wird darauf gewartet, dass die Übertragungstransaktion geschürft wird…", + "mig_working": "Ihre neue Seed-Wallet wird in einem isolierten Knoten erstellt — das kann eine Minute dauern. Ihre Haupt-Wallet läuft weiter.", "mine_when_idle": "Im Leerlauf minen", "mined": "gemined", "mined_filter": "Gemined", @@ -655,6 +685,7 @@ "seed_backup_saved": "Gespeichert unter ", "seed_backup_title": "Wiederherstellungsphrase sichern", "seed_backup_warning": "Schreiben Sie sie der Reihe nach auf, bewahren Sie sie offline auf und teilen oder fotografieren Sie sie niemals. Wenn Sie sie verlieren, können Ihre Gelder nicht wiederhergestellt werden.", + "seed_migrate_button": "Zu Seed-Wallet migrieren…", "select_address": "Adresse auswählen...", "select_receiving_address": "Empfangsadresse auswählen...", "select_source_address": "Quelladresse auswählen...", @@ -904,6 +935,7 @@ "tt_scan_themes": "Nach neuen Themes suchen.\\nTheme-Ordner ablegen in:\\n%s", "tt_scanline": "CRT-Scanlinieneffekt in der Konsole", "tt_seed_backup": "Die 24-Wort-Wiederherstellungsphrase Ihrer Wallet anzeigen und sichern", + "tt_seed_migrate": "Eine neue Wallet mit Wiederherstellungsphrase erstellen und Ihre Gelder dorthin übertragen", "tt_set_pin": "Eine 4-8-stellige PIN für schnelles Entsperren festlegen", "tt_shield_mining": "Transparente Mining-Belohnungen an eine geschirmte Adresse verschieben", "tt_simple_bg": "Einen einfachen Verlauf für den Hintergrund verwenden\\nHotkey: Ctrl+Up", diff --git a/res/lang/es.json b/res/lang/es.json index 7fb3da9..77401a0 100644 --- a/res/lang/es.json +++ b/res/lang/es.json @@ -383,6 +383,36 @@ "merge_funds": "Fusionar Fondos", "merge_started": "Operación de fusión iniciada", "merge_title": "Fusionar a Dirección", + "mig_adopt": "Hacer que esta sea mi cartera", + "mig_adopting": "Instalando tu nueva cartera y reescaneando…", + "mig_backed_up": "He anotado mi frase de recuperación", + "mig_balance": "Saldo de la cartera actual: %.8f DRGX (menos una pequeña comisión)", + "mig_confirming": "Esperando a que el barrido se confirme en la cadena antes de cambiar de cartera: esto garantiza que tus fondos realmente se han movido.", + "mig_confs": "Confirmaciones del barrido: %d", + "mig_continue_sweep": "Continuar al barrido", + "mig_copy_seed": "Copiar frase", + "mig_create": "Crear cartera con frase", + "mig_discard": "Descartar migración", + "mig_done": "Migración completada. Tu cartera ahora está respaldada por tu frase de recuperación.", + "mig_done_btn": "Listo", + "mig_done_detail": "El daemon está reescaneando para mostrar tus fondos: esto puede tardar unos minutos. Tu cartera anterior se guardó como un .bak en la carpeta de datos.", + "mig_intro": "Esto crea una cartera totalmente nueva respaldada por una frase de recuperación de 24 palabras, en un nodo aislado, para que puedas trasladar tus fondos a ella. Tu cartera actual NO se modifica y NO se mueve ningún fondo en este paso: primero respaldarás la nueva frase de recuperación y luego barrerás tus fondos hacia ella en un paso aparte y confirmado.", + "mig_later": "Más tarde", + "mig_receive_addr": "Dirección de recepción de la nueva cartera:", + "mig_remainder": "Aún quedan algunos fondos en tu cartera antigua (demasiadas entradas para una sola transacción): barre el resto antes de cambiar.", + "mig_remaining": "Restante en la cartera antigua: %.8f DRGX", + "mig_seed_warning": "Anota estas 24 palabras en orden y guárdalas sin conexión. Son el único respaldo de tu nueva cartera: si las pierdes, los fondos que migres se perderán para siempre.", + "mig_step1_done": "Paso 1 de 2 completado: tus fondos AÚN NO se han movido. Barrerlos hacia esta nueva cartera es el siguiente paso.", + "mig_sweep_all": "Barrer todos los fondos", + "mig_sweep_intro": "Ahora barre todos los fondos de tu cartera actual hacia la nueva cartera con frase de recuperación. Esto envía una única transacción a la dirección de la nueva cartera; a partir de ahora, tu frase de recuperación (ya respaldada) controla los fondos.", + "mig_sweep_remaining": "Barrer el resto", + "mig_sweeping": "Barriendo tus fondos hacia la nueva cartera…", + "mig_title": "Migrar a una cartera con frase de recuperación", + "mig_to": "Para: ", + "mig_txid": "txid: ", + "mig_unlock_first": "Desbloquea primero tu cartera para poder gastar desde ella.", + "mig_waiting_mine": "Esperando a que se mine la transacción de barrido…", + "mig_working": "Creando tu nueva cartera con frase de recuperación en un nodo aislado: esto puede tardar un minuto. Tu cartera principal sigue funcionando.", "mine_when_idle": "Minar en reposo", "mined": "minado", "mined_filter": "Minado", @@ -655,6 +685,7 @@ "seed_backup_saved": "Guardado en ", "seed_backup_title": "Respaldar frase de recuperación", "seed_backup_warning": "Anótalas en orden, guárdalas sin conexión y nunca las compartas ni las fotografíes. Si las pierdes, tus fondos no se podrán recuperar.", + "seed_migrate_button": "Migrar a una cartera con frase…", "select_address": "Seleccionar dirección...", "select_receiving_address": "Seleccionar dirección de recepción...", "select_source_address": "Seleccionar dirección de origen...", @@ -904,6 +935,7 @@ "tt_scan_themes": "Buscar nuevos temas.\\nColoque carpetas de temas en:\\n%s", "tt_scanline": "Efecto de líneas de escaneo CRT en la consola", "tt_seed_backup": "Muestra y respalda la frase de recuperación de 24 palabras de tu cartera", + "tt_seed_migrate": "Crea una nueva cartera con frase de recuperación y traslada tus fondos a ella", "tt_set_pin": "Establecer un PIN de 4-8 dígitos para desbloqueo rápido", "tt_shield_mining": "Mover recompensas de minería transparentes a una dirección blindada", "tt_simple_bg": "Usar un gradiente simple para el fondo\\nAtajo: Ctrl+Up", diff --git a/res/lang/fr.json b/res/lang/fr.json index c6974ae..1e82233 100644 --- a/res/lang/fr.json +++ b/res/lang/fr.json @@ -383,6 +383,36 @@ "merge_funds": "Fusionner les fonds", "merge_started": "Opération de fusion démarrée", "merge_title": "Fusionner vers une adresse", + "mig_adopt": "Faire de ceci mon portefeuille", + "mig_adopting": "Installation de votre nouveau portefeuille et rescan en cours…", + "mig_backed_up": "J'ai noté ma phrase de récupération", + "mig_balance": "Solde du portefeuille actuel : %.8f DRGX (moins de faibles frais)", + "mig_confirming": "Attente de la confirmation du balayage sur la chaîne avant de changer de portefeuille — cela garantit que vos fonds ont bien bougé.", + "mig_confs": "Confirmations du balayage : %d", + "mig_continue_sweep": "Continuer vers le balayage", + "mig_copy_seed": "Copier la phrase", + "mig_create": "Créer le portefeuille à phrase", + "mig_discard": "Abandonner la migration", + "mig_done": "Migration terminée. Votre portefeuille est désormais protégé par votre phrase de récupération.", + "mig_done_btn": "Terminé", + "mig_done_detail": "Le daemon effectue un rescan pour afficher vos fonds — cela peut prendre quelques minutes. Votre portefeuille précédent a été enregistré sous forme de fichier .bak dans le dossier de données.", + "mig_intro": "Ceci crée un tout nouveau portefeuille protégé par une phrase de récupération de 24 mots, dans un nœud isolé, afin que vous puissiez y transférer vos fonds. Votre portefeuille actuel n'est PAS modifié et AUCUN fonds ne bouge à cette étape — vous sauvegarderez d'abord la nouvelle phrase, puis vous y balaierez vos fonds lors d'une étape distincte et confirmée.", + "mig_later": "Plus tard", + "mig_receive_addr": "Adresse de réception du nouveau portefeuille :", + "mig_remainder": "Certains fonds sont encore dans votre ancien portefeuille (trop d'entrées pour une seule transaction) — balayez le reste avant de changer.", + "mig_remaining": "Restant dans l'ancien portefeuille : %.8f DRGX", + "mig_seed_warning": "Notez ces 24 mots dans l'ordre et conservez-les hors ligne. Ils constituent l'unique sauvegarde de votre nouveau portefeuille — si vous les perdez, les fonds que vous migrez sont perdus à jamais.", + "mig_step1_done": "Étape 1 sur 2 terminée — vos fonds n'ont PAS encore bougé. Les balayer vers ce nouveau portefeuille est l'étape suivante.", + "mig_sweep_all": "Balayer tous les fonds", + "mig_sweep_intro": "Balayez maintenant tous les fonds de votre portefeuille actuel vers le nouveau portefeuille à phrase. Ceci envoie une seule transaction vers l'adresse du nouveau portefeuille ; votre phrase de récupération (déjà sauvegardée) contrôle les fonds à partir de maintenant.", + "mig_sweep_remaining": "Balayer le reste", + "mig_sweeping": "Balayage de vos fonds vers le nouveau portefeuille…", + "mig_title": "Migrer vers un portefeuille à phrase de récupération", + "mig_to": "Vers : ", + "mig_txid": "txid : ", + "mig_unlock_first": "Déverrouillez d'abord votre portefeuille pour y dépenser des fonds.", + "mig_waiting_mine": "Attente du minage de la transaction de balayage…", + "mig_working": "Création de votre nouveau portefeuille à phrase dans un nœud isolé — cela peut prendre une minute. Votre portefeuille principal continue de fonctionner.", "mine_when_idle": "Miner au repos", "mined": "miné", "mined_filter": "Miné", @@ -655,6 +685,7 @@ "seed_backup_saved": "Enregistré dans ", "seed_backup_title": "Sauvegarder la phrase de récupération", "seed_backup_warning": "Notez-les dans l'ordre, conservez-les hors ligne, et ne les partagez ni ne les photographiez jamais. Si vous les perdez, vos fonds ne pourront pas être récupérés.", + "seed_migrate_button": "Migrer vers un portefeuille à phrase…", "select_address": "Sélectionner une adresse...", "select_receiving_address": "Sélectionner une adresse de réception...", "select_source_address": "Sélectionner une adresse source...", @@ -904,6 +935,7 @@ "tt_scan_themes": "Rechercher de nouveaux thèmes.\\nPlacez les dossiers de thèmes dans :\\n%s", "tt_scanline": "Effet de lignes de balayage CRT dans la console", "tt_seed_backup": "Afficher et sauvegarder la phrase de récupération de 24 mots de votre portefeuille", + "tt_seed_migrate": "Créer un nouveau portefeuille à phrase de récupération et y transférer vos fonds", "tt_set_pin": "Définir un PIN de 4-8 chiffres pour un déverrouillage rapide", "tt_shield_mining": "Déplacer les récompenses de minage transparentes vers une adresse blindée", "tt_simple_bg": "Utiliser un dégradé simple pour l'arrière-plan\\nRaccourci : Ctrl+Up", diff --git a/res/lang/ja.json b/res/lang/ja.json index f01a096..2380b4b 100644 --- a/res/lang/ja.json +++ b/res/lang/ja.json @@ -383,6 +383,36 @@ "merge_funds": "資金を統合", "merge_started": "統合操作を開始しました", "merge_title": "アドレスに統合", + "mig_adopt": "これを自分のウォレットにする", + "mig_adopting": "新しいウォレットをインストールして再スキャン中…", + "mig_backed_up": "シードフレーズを書き写しました", + "mig_balance": "現在のウォレット残高:%.8f DRGX(少額の手数料を除く)", + "mig_confirming": "ウォレットを切り替える前に、スイープがオンチェーンで確認されるのを待っています — これにより資金が実際に移動したことが保証されます。", + "mig_confs": "スイープの確認数:%d", + "mig_continue_sweep": "スイープに進む", + "mig_copy_seed": "シードをコピー", + "mig_create": "シードウォレットを作成", + "mig_discard": "移行を破棄", + "mig_done": "移行が完了しました。ウォレットはシードフレーズで保護されるようになりました。", + "mig_done_btn": "完了", + "mig_done_detail": "デーモンが資金を表示するために再スキャンしています — 数分かかる場合があります。以前のウォレットはデータフォルダに .bak として保存されました。", + "mig_intro": "これは24単語のシードフレーズで保護された新規ウォレットを隔離されたノード内に作成し、資金をそこへ移動できるようにします。現在のウォレットには一切変更を加えず、このステップでは資金は移動しません — まず新しいシードをバックアップし、その後、別の確定ステップとして資金をスイープします。", + "mig_later": "後で", + "mig_receive_addr": "新しいウォレットの受信アドレス:", + "mig_remainder": "一部の資金がまだ旧ウォレットに残っています(1回のトランザクションには入力が多すぎます) — 切り替える前に残りをスイープしてください。", + "mig_remaining": "旧ウォレットの残り:%.8f DRGX", + "mig_seed_warning": "これら24単語を順番どおりに書き写し、オフラインで保管してください。これは新しいウォレットの唯一のバックアップです — 紛失すると、移行した資金は永久に失われます。", + "mig_step1_done": "2ステップ中1ステップが完了 — 資金はまだ移動していません。この新しいウォレットへ資金をスイープするのが次のステップです。", + "mig_sweep_all": "すべての資金をスイープ", + "mig_sweep_intro": "次に、現在のウォレットからすべての資金を新しいシードウォレットへスイープします。これは新しいウォレットのアドレスへ1件のトランザクションを送信します。これ以降は(バックアップ済みの)シードフレーズが資金を管理します。", + "mig_sweep_remaining": "残りをスイープ", + "mig_sweeping": "新しいウォレットへ資金をスイープ中…", + "mig_title": "シードウォレットへ移行", + "mig_to": "宛先: ", + "mig_txid": "txid: ", + "mig_unlock_first": "送金するには、まずウォレットのロックを解除してください。", + "mig_waiting_mine": "スイープトランザクションがマイニングされるのを待っています…", + "mig_working": "隔離されたノード内に新しいシードウォレットを作成中です — 数分かかる場合があります。メインウォレットは動作を続けます。", "mine_when_idle": "アイドル時にマイニング", "mined": "採掘済み", "mined_filter": "採掘済み", @@ -655,6 +685,7 @@ "seed_backup_saved": "保存先: ", "seed_backup_title": "シードフレーズをバックアップ", "seed_backup_warning": "順番どおりに書き写し、オフラインで保管してください。決して共有や撮影をしないでください。紛失すると資金を復元できません。", + "seed_migrate_button": "シードウォレットへ移行…", "select_address": "アドレスを選択...", "select_receiving_address": "受信アドレスを選択...", "select_source_address": "送信元アドレスを選択...", @@ -904,6 +935,7 @@ "tt_scan_themes": "新しいテーマをスキャン。\\nテーマフォルダーをここに配置:\\n%s", "tt_scanline": "コンソールでの CRT スキャンライン効果", "tt_seed_backup": "ウォレットの24単語の復元シードフレーズを表示してバックアップします", + "tt_seed_migrate": "新しいシードフレーズウォレットを作成し、資金をそこへ移動します", "tt_set_pin": "クイックアンロック用の 4-8 桁 PIN を設定", "tt_shield_mining": "透明マイニング報酬をシールドアドレスに移動", "tt_simple_bg": "背景にシンプルなグラデーションを使用\\nホットキー:Ctrl+Up", diff --git a/res/lang/ko.json b/res/lang/ko.json index cc080dd..454b65c 100644 --- a/res/lang/ko.json +++ b/res/lang/ko.json @@ -383,6 +383,36 @@ "merge_funds": "자금 통합", "merge_started": "통합 작업이 시작되었습니다", "merge_title": "주소로 통합", + "mig_adopt": "이 지갑을 내 지갑으로 사용", + "mig_adopting": "새 지갑을 설치하고 재스캔하는 중…", + "mig_backed_up": "시드 문구를 적어 두었습니다", + "mig_balance": "현재 지갑 잔액: %.8f DRGX (소액 수수료 제외)", + "mig_confirming": "지갑을 전환하기 전에 쓸어 담기가 온체인에서 확인되기를 기다리는 중입니다 — 이는 자금이 실제로 이동했음을 보장합니다.", + "mig_confs": "쓸어 담기 확인 수: %d", + "mig_continue_sweep": "쓸어 담기로 계속", + "mig_copy_seed": "시드 복사", + "mig_create": "시드 지갑 생성", + "mig_discard": "이전 취소", + "mig_done": "이전이 완료되었습니다. 이제 지갑이 시드 문구로 백업됩니다.", + "mig_done_btn": "완료", + "mig_done_detail": "데몬이 자금을 표시하기 위해 재스캔하는 중입니다 — 몇 분 정도 걸릴 수 있습니다. 이전 지갑은 데이터 폴더에 .bak 파일로 저장되었습니다.", + "mig_intro": "24단어 시드 문구로 백업되는 완전히 새로운 지갑을 격리된 노드에 생성하여 자금을 그곳으로 옮길 수 있습니다. 현재 지갑은 그대로 유지되며 이 단계에서는 어떤 자금도 이동하지 않습니다 — 먼저 새 시드를 백업한 다음, 별도의 확인된 단계로 자금을 그곳에 쓸어 담습니다.", + "mig_later": "나중에", + "mig_receive_addr": "새 지갑 수신 주소:", + "mig_remainder": "일부 자금이 아직 이전 지갑에 남아 있습니다 (한 거래에 담기에는 입력이 너무 많음) — 전환하기 전에 나머지를 쓸어 담으세요.", + "mig_remaining": "이전 지갑에 남은 잔액: %.8f DRGX", + "mig_seed_warning": "이 24개의 단어를 순서대로 종이에 적어 오프라인으로 보관하세요. 이 단어들은 새 지갑의 유일한 백업입니다 — 잃어버리면 이전한 자금을 영원히 복구할 수 없습니다.", + "mig_step1_done": "2단계 중 1단계 완료 — 아직 자금이 이동하지 않았습니다. 이 새 지갑으로 자금을 쓸어 담는 것이 다음 단계입니다.", + "mig_sweep_all": "모든 자금 쓸어 담기", + "mig_sweep_intro": "이제 현재 지갑의 모든 자금을 새 시드 지갑으로 쓸어 담습니다. 새 지갑 주소로 단일 거래를 전송하며, 이후로는 (이미 백업한) 시드 문구가 자금을 관리합니다.", + "mig_sweep_remaining": "나머지 쓸어 담기", + "mig_sweeping": "새 지갑으로 자금을 쓸어 담는 중…", + "mig_title": "시드 지갑으로 이전", + "mig_to": "받는 곳: ", + "mig_txid": "txid: ", + "mig_unlock_first": "지갑에서 자금을 전송하려면 먼저 잠금을 해제하세요.", + "mig_waiting_mine": "쓸어 담기 거래가 채굴되기를 기다리는 중…", + "mig_working": "격리된 노드에 새 시드 지갑을 생성하는 중입니다 — 1분 정도 걸릴 수 있습니다. 메인 지갑은 계속 실행됩니다.", "mine_when_idle": "유휴 시 채굴", "mined": "채굴됨", "mined_filter": "채굴됨", @@ -655,6 +685,7 @@ "seed_backup_saved": "저장됨: ", "seed_backup_title": "시드 문구 백업", "seed_backup_warning": "순서대로 종이에 적어 오프라인으로 보관하고, 절대 공유하거나 사진으로 찍지 마세요. 이 단어들을 잃어버리면 자금을 복구할 수 없습니다.", + "seed_migrate_button": "시드 지갑으로 이전…", "select_address": "주소 선택...", "select_receiving_address": "수신 주소 선택...", "select_source_address": "보낼 주소 선택...", @@ -904,6 +935,7 @@ "tt_scan_themes": "새 테마 검색.\\n테마 폴더를 여기에 배치:\\n%s", "tt_scanline": "콘솔에서 CRT 스캔라인 효과", "tt_seed_backup": "지갑의 24단어 복구 시드 문구를 표시하고 백업합니다", + "tt_seed_migrate": "새 시드 문구 지갑을 만들고 자금을 그곳으로 옮깁니다", "tt_set_pin": "빠른 잠금 해제를 위한 4-8자리 PIN 설정", "tt_shield_mining": "투명 채굴 보상을 차폐 주소로 이동", "tt_simple_bg": "배경에 단순 그라데이션 사용\\n단축키: Ctrl+Up", diff --git a/res/lang/pt.json b/res/lang/pt.json index bc3a905..0acb31d 100644 --- a/res/lang/pt.json +++ b/res/lang/pt.json @@ -383,6 +383,36 @@ "merge_funds": "Fundir Fundos", "merge_started": "Operação de fusão iniciada", "merge_title": "Fundir para Endereço", + "mig_adopt": "Tornar esta minha carteira", + "mig_adopting": "Instalando sua nova carteira e reescaneando…", + "mig_backed_up": "Anotei minha frase de recuperação", + "mig_balance": "Saldo da carteira atual: %.8f DRGX (menos uma pequena taxa)", + "mig_confirming": "Aguardando a varredura ser confirmada na blockchain antes de trocar de carteira — isso garante que seus fundos realmente foram movidos.", + "mig_confs": "Confirmações da varredura: %d", + "mig_continue_sweep": "Continuar para a varredura", + "mig_copy_seed": "Copiar frase de recuperação", + "mig_create": "Criar carteira semente", + "mig_discard": "Descartar migração", + "mig_done": "Migração concluída. Sua carteira agora é protegida pela sua frase de recuperação.", + "mig_done_btn": "Concluído", + "mig_done_detail": "O daemon está reescaneando para exibir seus fundos — isso pode levar alguns minutos. Sua carteira anterior foi salva como um arquivo .bak na pasta de dados.", + "mig_intro": "Isso cria uma carteira totalmente nova, protegida por uma frase de recuperação de 24 palavras, em um nó isolado, para que você possa mover seus fundos para ela. Sua carteira atual NÃO é alterada e NENHUM fundo é movido nesta etapa — primeiro você fará o backup da nova frase de recuperação e, em seguida, varrerá seus fundos para ela como uma etapa separada e confirmada.", + "mig_later": "Depois", + "mig_receive_addr": "Endereço de recebimento da nova carteira:", + "mig_remainder": "Alguns fundos ainda estão na sua carteira antiga (entradas demais para uma única transação) — varra o restante antes de trocar.", + "mig_remaining": "Restante na carteira antiga: %.8f DRGX", + "mig_seed_warning": "Anote estas 24 palavras em ordem e guarde-as offline. Elas são o único backup da sua nova carteira — se você as perder, os fundos que migrar estarão perdidos para sempre.", + "mig_step1_done": "Etapa 1 de 2 concluída — seus fundos AINDA NÃO foram movidos. Varrê-los para esta nova carteira é a próxima etapa.", + "mig_sweep_all": "Varrer todos os fundos", + "mig_sweep_intro": "Agora varra todos os fundos da sua carteira atual para a nova carteira semente. Isso envia uma única transação para o endereço da nova carteira; sua frase de recuperação (já salva em backup) controla os fundos daqui em diante.", + "mig_sweep_remaining": "Varrer o restante", + "mig_sweeping": "Varrendo seus fundos para a nova carteira…", + "mig_title": "Migrar para uma carteira semente", + "mig_to": "Para: ", + "mig_txid": "txid: ", + "mig_unlock_first": "Desbloqueie sua carteira primeiro para gastar a partir dela.", + "mig_waiting_mine": "Aguardando a transação de varredura ser minerada…", + "mig_working": "Criando sua nova carteira semente em um nó isolado — isso pode levar um minuto. Sua carteira principal continua em execução.", "mine_when_idle": "Minerar quando ocioso", "mined": "minerado", "mined_filter": "Minerado", @@ -655,6 +685,7 @@ "seed_backup_saved": "Salvo em ", "seed_backup_title": "Backup da frase de recuperação", "seed_backup_warning": "Anote-as em ordem, guarde-as offline e nunca as compartilhe ou fotografe. Se você as perder, seus fundos não poderão ser recuperados.", + "seed_migrate_button": "Migrar para carteira semente…", "select_address": "Selecionar endereço...", "select_receiving_address": "Selecionar endereço de recebimento...", "select_source_address": "Selecionar endereço de origem...", @@ -904,6 +935,7 @@ "tt_scan_themes": "Procurar novos temas.\\nColoque pastas de temas em:\\n%s", "tt_scanline": "Efeito de linhas de varredura CRT no console", "tt_seed_backup": "Mostrar e fazer backup da frase de recuperação de 24 palavras da sua carteira", + "tt_seed_migrate": "Criar uma nova carteira com frase de recuperação e mover seus fundos para ela", "tt_set_pin": "Definir um PIN de 4-8 dígitos para desbloqueio rápido", "tt_shield_mining": "Mover recompensas de mineração transparentes para um endereço blindado", "tt_simple_bg": "Usar um gradiente simples para o fundo\\nAtalho: Ctrl+Up", diff --git a/res/lang/ru.json b/res/lang/ru.json index 3d4efbd..3492d93 100644 --- a/res/lang/ru.json +++ b/res/lang/ru.json @@ -383,6 +383,36 @@ "merge_funds": "Объединить средства", "merge_started": "Операция объединения начата", "merge_title": "Объединить на адрес", + "mig_adopt": "Сделать это моим кошельком", + "mig_adopting": "Установка вашего нового кошелька и пересканирование…", + "mig_backed_up": "Я записал свою сид-фразу", + "mig_balance": "Баланс текущего кошелька: %.8f DRGX (за вычетом небольшой комиссии)", + "mig_confirming": "Ожидание подтверждения перевода в сети перед переключением кошельков — это гарантирует, что ваши средства действительно перемещены.", + "mig_confs": "Подтверждения перевода: %d", + "mig_continue_sweep": "Перейти к переводу", + "mig_copy_seed": "Копировать сид-фразу", + "mig_create": "Создать сид-кошелёк", + "mig_discard": "Отменить миграцию", + "mig_done": "Миграция завершена. Ваш кошелёк теперь защищён вашей сид-фразой.", + "mig_done_btn": "Готово", + "mig_done_detail": "Демон выполняет пересканирование, чтобы показать ваши средства — это может занять несколько минут. Ваш предыдущий кошелёк сохранён как .bak в папке с данными.", + "mig_intro": "Это создаёт совершенно новый кошелёк, защищённый сид-фразой из 24 слов, в изолированном узле, чтобы вы могли перевести в него свои средства. Ваш текущий кошелёк НЕ затрагивается, и на этом шаге НИКАКИЕ средства не перемещаются — сначала вы сделаете резервную копию новой сид-фразы, а затем отдельным, подтверждённым шагом переведёте в неё свои средства.", + "mig_later": "Позже", + "mig_receive_addr": "Адрес получения нового кошелька:", + "mig_remainder": "Часть средств всё ещё находится в вашем старом кошельке (слишком много входов для одной транзакции) — переведите остаток перед переключением.", + "mig_remaining": "Осталось в старом кошельке: %.8f DRGX", + "mig_seed_warning": "Запишите эти 24 слова по порядку и храните их офлайн. Это единственная резервная копия вашего нового кошелька — если вы их потеряете, средства, которые вы перенесёте, будут утрачены навсегда.", + "mig_step1_done": "Шаг 1 из 2 завершён — ваши средства пока НЕ перемещены. Следующий шаг — перевод их в этот новый кошелёк.", + "mig_sweep_all": "Перевести все средства", + "mig_sweep_intro": "Теперь переведите все средства из вашего текущего кошелька в новый сид-кошелёк. Это отправит одну транзакцию на адрес нового кошелька; ваша сид-фраза (уже сохранённая в резервной копии) с этого момента управляет средствами.", + "mig_sweep_remaining": "Перевести остаток", + "mig_sweeping": "Перевод ваших средств в новый кошелёк…", + "mig_title": "Переход на сид-кошелёк", + "mig_to": "Кому: ", + "mig_txid": "txid: ", + "mig_unlock_first": "Сначала разблокируйте кошелёк, чтобы тратить с него.", + "mig_waiting_mine": "Ожидание включения транзакции перевода в блок…", + "mig_working": "Создание вашего нового сид-кошелька в изолированном узле — это может занять минуту. Ваш основной кошелёк продолжает работать.", "mine_when_idle": "Майнить в простое", "mined": "добыто", "mined_filter": "Добытые", @@ -655,6 +685,7 @@ "seed_backup_saved": "Сохранено в ", "seed_backup_title": "Резервная копия сид-фразы", "seed_backup_warning": "Запишите их по порядку, храните офлайн и никогда не делитесь ими и не фотографируйте их. Если вы их потеряете, ваши средства не удастся восстановить.", + "seed_migrate_button": "Перейти на сид-кошелёк…", "select_address": "Выбрать адрес...", "select_receiving_address": "Выбрать адрес получения...", "select_source_address": "Выбрать адрес-источник...", @@ -904,6 +935,7 @@ "tt_scan_themes": "Поиск новых тем.\\nРазместите папки тем в:\\n%s", "tt_scanline": "Эффект развёртки ЭЛТ в консоли", "tt_seed_backup": "Показать и создать резервную копию сид-фразы восстановления вашего кошелька из 24 слов", + "tt_seed_migrate": "Создать новый кошелёк с сид-фразой и перевести в него ваши средства", "tt_set_pin": "Установить 4-8-значный PIN для быстрой разблокировки", "tt_shield_mining": "Перевести прозрачные вознаграждения за майнинг на экранированный адрес", "tt_simple_bg": "Использовать простой градиент для фона\\nГорячая клавиша: Ctrl+Up", diff --git a/res/lang/zh.json b/res/lang/zh.json index 793b67d..0e562f9 100644 --- a/res/lang/zh.json +++ b/res/lang/zh.json @@ -383,6 +383,36 @@ "merge_funds": "合并资金", "merge_started": "合并操作已开始", "merge_title": "合并到地址", + "mig_adopt": "将其设为我的钱包", + "mig_adopting": "正在安装您的新钱包并重新扫描…", + "mig_backed_up": "我已抄写下我的助记词", + "mig_balance": "当前钱包余额:%.8f DRGX(扣除少量手续费)", + "mig_confirming": "正在等待此次扫入在链上确认,然后再切换钱包——这可确保您的资金确实已经转移。", + "mig_confs": "扫入确认数:%d", + "mig_continue_sweep": "继续扫入", + "mig_copy_seed": "复制助记词", + "mig_create": "创建助记词钱包", + "mig_discard": "放弃迁移", + "mig_done": "迁移完成。您的钱包现在由您的助记词支持。", + "mig_done_btn": "完成", + "mig_done_detail": "守护进程正在重新扫描以显示您的资金——这可能需要几分钟。您之前的钱包已作为 .bak 保存在数据文件夹中。", + "mig_intro": "这会在一个隔离的节点中创建一个由 24 词助记词支持的全新钱包,以便您将资金转入其中。您当前的钱包不会受到影响,本步骤也不会转移任何资金——您将先备份新助记词,然后再作为单独的、经确认的步骤把资金扫入其中。", + "mig_later": "稍后", + "mig_receive_addr": "新钱包接收地址:", + "mig_remainder": "您的旧钱包中仍有部分资金(一笔交易的输入过多)——请在切换前扫入剩余部分。", + "mig_remaining": "旧钱包中剩余:%.8f DRGX", + "mig_seed_warning": "请按顺序将这 24 个词抄写下来并离线保存。它们是您新钱包唯一的备份——一旦丢失,您迁移的资金将永久无法恢复。", + "mig_step1_done": "2 步中的第 1 步已完成——您的资金尚未转移。将它们扫入这个新钱包是下一步。", + "mig_sweep_all": "扫入全部资金", + "mig_sweep_intro": "现在将您当前钱包中的所有资金扫入新的助记词钱包。这会向新钱包的地址发送一笔交易;从此以后由您的助记词(已备份)控制这些资金。", + "mig_sweep_remaining": "扫入剩余部分", + "mig_sweeping": "正在将您的资金扫入新钱包…", + "mig_title": "迁移到助记词钱包", + "mig_to": "至:", + "mig_txid": "txid: ", + "mig_unlock_first": "请先解锁您的钱包才能从中花费。", + "mig_waiting_mine": "正在等待扫入交易被打包…", + "mig_working": "正在隔离的节点中创建您的新助记词钱包——这可能需要一分钟。您的主钱包将继续运行。", "mine_when_idle": "空闲时挖矿", "mined": "已挖得", "mined_filter": "已挖得", @@ -655,6 +685,7 @@ "seed_backup_saved": "已保存到 ", "seed_backup_title": "备份助记词", "seed_backup_warning": "请按顺序将它们抄写下来,离线保存,切勿分享或拍照。一旦丢失,您的资金将无法恢复。", + "seed_migrate_button": "迁移到助记词钱包…", "select_address": "选择地址...", "select_receiving_address": "选择接收地址...", "select_source_address": "选择来源地址...", @@ -904,6 +935,7 @@ "tt_scan_themes": "扫描新主题。\\n将主题文件夹放在:\\n%s", "tt_scanline": "控制台中的 CRT 扫描线效果", "tt_seed_backup": "显示并备份您钱包的 24 词恢复助记词", + "tt_seed_migrate": "创建一个新的助记词钱包并将您的资金转入其中", "tt_set_pin": "设置 4-8 位 PIN 以快速解锁", "tt_shield_mining": "将透明挖矿奖励转移到屏蔽地址", "tt_simple_bg": "使用简单渐变作为背景\\n快捷键:Ctrl+Up", diff --git a/src/app.cpp b/src/app.cpp index d56a979..f7d6a39 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -3072,7 +3072,7 @@ void App::renderSeedMigrationDialog() || seed_migration_step_ == SeedMigrationStep::Sweeping || seed_migration_step_ == SeedMigrationStep::Adopting; - if (!ui::material::BeginOverlayDialog("Migrate to a seed wallet", &show_seed_migration_, 580.0f, 0.94f)) { + if (!ui::material::BeginOverlayDialog(TR("mig_title"), &show_seed_migration_, 580.0f, 0.94f)) { if (!busy) wipeSeed(); return; } @@ -3081,75 +3081,68 @@ void App::renderSeedMigrationDialog() // the post-EndOverlayDialog wipe below. if (!show_seed_migration_ && busy) show_seed_migration_ = true; - ui::material::Type().text(ui::material::TypeStyle::H6, "Migrate to a seed wallet"); + const ImVec4 kMedium = ImGui::ColorConvertU32ToFloat4(ui::material::OnSurfaceMedium()); + ui::material::Type().text(ui::material::TypeStyle::H6, TR("mig_title")); ImGui::Dummy(ImVec2(0, ui::Layout::spacingSm())); switch (seed_migration_step_) { case SeedMigrationStep::Intro: - ImGui::TextWrapped( - "This creates a brand-new wallet backed by a 24-word seed phrase, in an isolated node, " - "so you can move your funds into it. Your current wallet is NOT touched and NO funds " - "move in this step — you'll back up the new seed first, then sweep your funds into it " - "as a separate, confirmed step."); + ImGui::TextWrapped("%s", TR("mig_intro")); ImGui::Spacing(); ImGui::Separator(); - if (ui::material::StyledButton("Create seed wallet", ImVec2(180, 0))) + if (ui::material::StyledButton(TR("mig_create"), ImVec2(180, 0))) beginCreateSeedWallet(); ImGui::SameLine(); - if (ui::material::StyledButton("Cancel", ImVec2(120, 0))) + if (ui::material::StyledButton(TR("cancel"), ImVec2(120, 0))) close(); break; case SeedMigrationStep::Working: - ImGui::TextWrapped("Creating your new seed wallet in an isolated node — this can take a " - "minute. Your main wallet keeps running."); + ImGui::TextWrapped("%s", TR("mig_working")); ImGui::Spacing(); if (!seed_migration_status_.empty()) - ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(ui::material::OnSurfaceMedium()), "%s", seed_migration_status_.c_str()); + ImGui::TextColored(kMedium, "%s", seed_migration_status_.c_str()); break; case SeedMigrationStep::ShowSeed: { ImGui::PushStyleColor(ImGuiCol_Text, ui::material::Error()); - ImGui::TextWrapped("Write these 24 words down in order and store them offline. They are the " - "only backup of your new wallet — if you lose them, the funds you migrate " - "are gone forever."); + ImGui::TextWrapped("%s", TR("mig_seed_warning")); ImGui::PopStyleColor(); ImGui::Spacing(); ui::RenderSeedWordGrid(ui::SplitSeedWords(seed_migration_seed_)); ImGui::Spacing(); - ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(ui::material::OnSurfaceMedium()), "New wallet receive address:"); + ImGui::TextColored(kMedium, "%s", TR("mig_receive_addr")); ImGui::TextWrapped("%s", seed_migration_dest_.c_str()); ImGui::Spacing(); - if (ui::material::StyledButton("Copy seed", ImVec2(120, 0))) + if (ui::material::StyledButton(TR("mig_copy_seed"), ImVec2(120, 0))) copySecretToClipboard(seed_migration_seed_); ImGui::SameLine(); - if (ui::material::StyledButton("Save to file", ImVec2(130, 0))) { + if (ui::material::StyledButton(TR("seed_backup_save"), ImVec2(130, 0))) { std::string path = util::Platform::getConfigDir() + "/dragonx-seed-wallet-backup.txt"; std::string content = seed_migration_seed_ + "\nAddress: " + seed_migration_dest_ + "\n"; const bool ok = util::Platform::writeFileAtomically(path, content, /*restrict=*/true); sodium_memzero(&content[0], content.size()); - seed_migration_status_ = (ok ? "Saved to " : "Could not write ") + path; + seed_migration_status_ = std::string(ok ? TR("seed_backup_saved") : TR("seed_backup_save_failed")) + path; } if (!seed_migration_status_.empty()) { ImGui::TextColored(ImVec4(0.3f, 0.8f, 0.3f, 1.0f), "%s", seed_migration_status_.c_str()); } ImGui::Spacing(); - ImGui::Checkbox("I've written down my seed phrase", &seed_migration_backed_up_); + ImGui::Checkbox(TR("mig_backed_up"), &seed_migration_backed_up_); ImGui::Spacing(); ImGui::PushStyleColor(ImGuiCol_Text, ui::material::OnSurfaceMedium()); - ImGui::TextWrapped("Step 1 of 2 complete — your funds have NOT moved yet. Sweeping them into " - "this new wallet is the next step."); + ImGui::TextWrapped("%s", TR("mig_step1_done")); ImGui::PopStyleColor(); ImGui::Separator(); if (!seed_migration_backed_up_) ImGui::BeginDisabled(); - if (ui::material::StyledButton("Continue to sweep", ImVec2(170, 0))) { + if (ui::material::StyledButton(TR("mig_continue_sweep"), ImVec2(170, 0))) { wipeSeed(); // the sweep/adopt steps only use the address, never the seed itself seed_migration_step_ = SeedMigrationStep::Sweep; refreshSeedMigrationBalance(); } if (!seed_migration_backed_up_) ImGui::EndDisabled(); ImGui::SameLine(); - if (ui::material::StyledButton("Discard migration", ImVec2(160, 0))) { + if (ui::material::StyledButton(TR("mig_discard"), ImVec2(160, 0))) { // Throw away the isolated new wallet + clear the pending state. if (!seed_migration_temp_dir_.empty()) { std::error_code ec; @@ -3168,18 +3161,16 @@ void App::renderSeedMigrationDialog() break; } - case SeedMigrationStep::Sweep: - ImGui::TextWrapped("Now sweep all funds from your current wallet into the new seed wallet. " - "This sends a single transaction to the new wallet's address; your seed " - "phrase (already backed up) controls the funds from here on."); + case SeedMigrationStep::Sweep: { + ImGui::TextWrapped("%s", TR("mig_sweep_intro")); ImGui::Spacing(); - ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(ui::material::OnSurfaceMedium()), - "Current wallet balance: %.8f DRGX (minus a small fee)", seed_migration_balance_); - ImGui::TextWrapped("To: %s", seed_migration_dest_.c_str()); + char balbuf[96]; snprintf(balbuf, sizeof(balbuf), TR("mig_balance"), seed_migration_balance_); + ImGui::TextColored(kMedium, "%s", balbuf); + ImGui::TextWrapped("%s%s", TR("mig_to"), seed_migration_dest_.c_str()); if (state_.isLocked()) { ImGui::Spacing(); ImGui::PushStyleColor(ImGuiCol_Text, ui::material::Error()); - ImGui::TextWrapped("Unlock your wallet first to spend from it."); + ImGui::TextWrapped("%s", TR("mig_unlock_first")); ImGui::PopStyleColor(); } ImGui::Spacing(); @@ -3187,80 +3178,77 @@ void App::renderSeedMigrationDialog() { const bool canSweep = !state_.isLocked() && seed_migration_balance_ > 0.0; if (!canSweep) ImGui::BeginDisabled(); - if (ui::material::StyledButton("Sweep all funds", ImVec2(170, 0))) + if (ui::material::StyledButton(TR("mig_sweep_all"), ImVec2(170, 0))) beginSweepToSeedWallet(); if (!canSweep) ImGui::EndDisabled(); } ImGui::SameLine(); - if (ui::material::StyledButton("Refresh", ImVec2(110, 0))) + if (ui::material::StyledButton(TR("refresh"), ImVec2(110, 0))) refreshSeedMigrationBalance(); ImGui::SameLine(); - if (ui::material::StyledButton("Later", ImVec2(100, 0))) + if (ui::material::StyledButton(TR("mig_later"), ImVec2(100, 0))) close(); // pending state persists; resumes here next time break; + } case SeedMigrationStep::Sweeping: - ImGui::TextWrapped("Sweeping your funds into the new wallet…"); + ImGui::TextWrapped("%s", TR("mig_sweeping")); ImGui::Spacing(); if (!seed_migration_status_.empty()) - ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(ui::material::OnSurfaceMedium()), - "%s", seed_migration_status_.c_str()); + ImGui::TextColored(kMedium, "%s", seed_migration_status_.c_str()); break; case SeedMigrationStep::Confirming: { - const ImVec4 medium = ImGui::ColorConvertU32ToFloat4(ui::material::OnSurfaceMedium()); const double dust = DRAGONX_DEFAULT_FEE; // treat <= one fee as "empty" const bool confirmed = seed_migration_sweep_confs_ >= 1; const bool legacyEmpty = seed_migration_legacy_remaining_ >= 0.0 && seed_migration_legacy_remaining_ <= dust; - ImGui::TextWrapped("Waiting for the sweep to confirm on-chain before switching wallets — " - "this guarantees your funds have actually moved."); + ImGui::TextWrapped("%s", TR("mig_confirming")); ImGui::Spacing(); - ImGui::TextColored(medium, "Sweep confirmations: %d", seed_migration_sweep_confs_); + char cbuf[64]; snprintf(cbuf, sizeof(cbuf), TR("mig_confs"), seed_migration_sweep_confs_); + ImGui::TextColored(kMedium, "%s", cbuf); if (!seed_migration_sweep_txid_.empty()) - ImGui::TextColored(medium, "txid: %s", seed_migration_sweep_txid_.c_str()); - if (seed_migration_legacy_remaining_ >= 0.0) - ImGui::TextColored(medium, "Remaining in old wallet: %.8f DRGX", - seed_migration_legacy_remaining_); + ImGui::TextColored(kMedium, "%s%s", TR("mig_txid"), seed_migration_sweep_txid_.c_str()); + if (seed_migration_legacy_remaining_ >= 0.0) { + char rbuf[96]; snprintf(rbuf, sizeof(rbuf), TR("mig_remaining"), seed_migration_legacy_remaining_); + ImGui::TextColored(kMedium, "%s", rbuf); + } ImGui::Spacing(); ImGui::Separator(); if (confirmed && legacyEmpty) { - if (ui::material::StyledButton("Make this my wallet", ImVec2(180, 0))) + if (ui::material::StyledButton(TR("mig_adopt"), ImVec2(180, 0))) beginAdoptSeedWallet(); } else if (confirmed && !legacyEmpty) { ImGui::PushStyleColor(ImGuiCol_Text, ui::material::Error()); - ImGui::TextWrapped("Some funds are still in your old wallet (too many inputs for one " - "transaction) — sweep the remainder before switching."); + ImGui::TextWrapped("%s", TR("mig_remainder")); ImGui::PopStyleColor(); - if (ui::material::StyledButton("Sweep remaining", ImVec2(180, 0))) + if (ui::material::StyledButton(TR("mig_sweep_remaining"), ImVec2(180, 0))) beginSweepToSeedWallet(); } else { - ImGui::TextColored(medium, "Waiting for the sweep transaction to be mined…"); + ImGui::TextColored(kMedium, "%s", TR("mig_waiting_mine")); } ImGui::SameLine(); - if (ui::material::StyledButton("Refresh", ImVec2(110, 0))) + if (ui::material::StyledButton(TR("refresh"), ImVec2(110, 0))) pollSweepStatus(); ImGui::SameLine(); - if (ui::material::StyledButton("Later", ImVec2(100, 0))) + if (ui::material::StyledButton(TR("mig_later"), ImVec2(100, 0))) close(); // pending state + txid persist; resumes here next time break; } case SeedMigrationStep::Adopting: - ImGui::TextWrapped("Installing your new wallet and rescanning…"); + ImGui::TextWrapped("%s", TR("mig_adopting")); ImGui::Spacing(); if (!seed_migration_status_.empty()) - ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(ui::material::OnSurfaceMedium()), - "%s", seed_migration_status_.c_str()); + ImGui::TextColored(kMedium, "%s", seed_migration_status_.c_str()); break; case SeedMigrationStep::Done: ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.3f, 0.8f, 0.3f, 1.0f)); - ImGui::TextWrapped("Migration complete. Your wallet is now backed by your seed phrase."); + ImGui::TextWrapped("%s", TR("mig_done")); ImGui::PopStyleColor(); ImGui::Spacing(); - ImGui::TextWrapped("The daemon is rescanning to show your funds — this can take a few " - "minutes. Your previous wallet was saved as a .bak in the data folder."); + ImGui::TextWrapped("%s", TR("mig_done_detail")); if (!seed_migration_status_.empty()) { // a non-fatal warning (e.g. the daemon didn't restart) ImGui::Spacing(); ImGui::PushStyleColor(ImGuiCol_Text, ui::material::Error()); @@ -3269,7 +3257,7 @@ void App::renderSeedMigrationDialog() } ImGui::Spacing(); ImGui::Separator(); - if (ui::material::StyledButton("Done", ImVec2(120, 0))) + if (ui::material::StyledButton(TR("mig_done_btn"), ImVec2(120, 0))) close(); break; @@ -3279,7 +3267,7 @@ void App::renderSeedMigrationDialog() ImGui::PopStyleColor(); ImGui::Spacing(); ImGui::Separator(); - if (ui::material::StyledButton("Close", ImVec2(120, 0))) + if (ui::material::StyledButton(TR("close"), ImVec2(120, 0))) close(); break; } diff --git a/src/util/i18n.cpp b/src/util/i18n.cpp index 16caf60..81e2d84 100644 --- a/src/util/i18n.cpp +++ b/src/util/i18n.cpp @@ -251,6 +251,37 @@ void I18n::loadBuiltinEnglish() strings_["seed_backup_reminder"] = "Your wallet has a 24-word recovery seed phrase. Back it up now in Settings → Node & Security."; strings_["seed_migrate_button"] = "Migrate to seed…"; strings_["tt_seed_migrate"] = "Create a new seed-phrase wallet and move your funds into it"; + // Migrate-to-seed modal + strings_["mig_title"] = "Migrate to a seed wallet"; + strings_["mig_intro"] = "This creates a brand-new wallet backed by a 24-word seed phrase, in an isolated node, so you can move your funds into it. Your current wallet is NOT touched and NO funds move in this step — you'll back up the new seed first, then sweep your funds into it as a separate, confirmed step."; + strings_["mig_create"] = "Create seed wallet"; + strings_["mig_working"] = "Creating your new seed wallet in an isolated node — this can take a minute. Your main wallet keeps running."; + strings_["mig_seed_warning"] = "Write these 24 words down in order and store them offline. They are the only backup of your new wallet — if you lose them, the funds you migrate are gone forever."; + strings_["mig_receive_addr"] = "New wallet receive address:"; + strings_["mig_copy_seed"] = "Copy seed"; + strings_["mig_backed_up"] = "I've written down my seed phrase"; + strings_["mig_step1_done"] = "Step 1 of 2 complete — your funds have NOT moved yet. Sweeping them into this new wallet is the next step."; + strings_["mig_continue_sweep"] = "Continue to sweep"; + strings_["mig_discard"] = "Discard migration"; + strings_["mig_sweep_intro"] = "Now sweep all funds from your current wallet into the new seed wallet. This sends a single transaction to the new wallet's address; your seed phrase (already backed up) controls the funds from here on."; + strings_["mig_balance"] = "Current wallet balance: %.8f DRGX (minus a small fee)"; + strings_["mig_to"] = "To: "; + strings_["mig_unlock_first"] = "Unlock your wallet first to spend from it."; + strings_["mig_sweep_all"] = "Sweep all funds"; + strings_["mig_later"] = "Later"; + strings_["mig_sweeping"] = "Sweeping your funds into the new wallet…"; + strings_["mig_confirming"] = "Waiting for the sweep to confirm on-chain before switching wallets — this guarantees your funds have actually moved."; + strings_["mig_confs"] = "Sweep confirmations: %d"; + strings_["mig_txid"] = "txid: "; + strings_["mig_remaining"] = "Remaining in old wallet: %.8f DRGX"; + strings_["mig_adopt"] = "Make this my wallet"; + strings_["mig_remainder"] = "Some funds are still in your old wallet (too many inputs for one transaction) — sweep the remainder before switching."; + strings_["mig_sweep_remaining"] = "Sweep remaining"; + strings_["mig_waiting_mine"] = "Waiting for the sweep transaction to be mined…"; + strings_["mig_adopting"] = "Installing your new wallet and rescanning…"; + strings_["mig_done"] = "Migration complete. Your wallet is now backed by your seed phrase."; + strings_["mig_done_detail"] = "The daemon is rescanning to show your funds — this can take a few minutes. Your previous wallet was saved as a .bak in the data folder."; + strings_["mig_done_btn"] = "Done"; strings_["contacts_search_placeholder"] = "Search contacts..."; strings_["contacts_search_no_match"] = "No matching contacts"; strings_["address_book_confirm_delete"] = "Confirm delete?";