6 Commits

Author SHA1 Message Date
e66f2b6c8c feat(wallet): migrate-to-seed, Phase 2 — sweep + adopt (fund-safety gated)
Second half of "migrate a legacy wallet to a seed wallet": sweep all funds
into the new seed wallet, then adopt it as the primary wallet.

- Sweep (beginSweepToSeedWallet): z_mergetoaddress ["ANY_TADDR","ANY_ZADDR"]
  -> the new wallet's z-address, at the default fee, limits 0,0. The opid is
  tracked via the existing send-callback pipeline; the txid is persisted.
- Confirming gate (fund-safety): after the sweep, pollSweepStatus() polls the
  tx confirmations + legacy balance. "Make this my wallet" only unlocks once
  the sweep is MINED (>= 1 conf) AND the old wallet is empty — so wallet.dat is
  never swapped while the funds could still bounce back or a remainder is left.
  A too-big-for-one-tx remainder offers a "Sweep remaining" re-sweep.
- Adopt (beginAdoptSeedWallet, background): stop daemon -> move legacy
  wallet.dat to a timestamped .bak (never deleted; restored on failure) ->
  install the new wallet -> restart with -rescan. Exception-safe;
  daemon_restarting_ gates tryConnect + is always cleared; skips the restart
  while shutting down; beginShutdown joins the task first.
- Resume: a pending migration reopens at Sweep, or at Confirming if the sweep
  txid is already recorded (re-derived from the chain) — never re-sweeps blind.
- Secret hygiene: the seed is wiped leaving ShowSeed, on any modal dismiss
  (detected after BeginOverlayDialog), and in App::~App() (same fix applied to
  the seed-backup dialog).

Built both variants; tests + hygiene pass. Two rounds of parallel adversarial
review (12 findings fixed, then a clean re-verify) gate this fund-moving code.
The migration modal uses English literals (as renderBackupDialog does); it gets
translated once the flow is finalized. Live sweep test against a funded wallet
is the next step.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 15:04:40 -05:00
7ee20bb497 fix(wallet): connect the isolated seed node over plaintext RPC + add smoke
The seed-wallet creator forced TLS on its RPC client, but the DRAGONX RPC is
plaintext HTTP on localhost (-tls=only applies to P2P, not the RPC; the main
GUI's conf has no rpctls key and connects over http too). Forcing https made
every connect fail with "SSL connect error", so the isolated create never
completed. Connect without TLS, matching the main daemon path.

Also add an env-gated (DRAGONX_SEED_CREATE_SMOKE=1) headless smoke in main()
that runs SeedWalletCreator::create() before GUI init and prints
ok/word-count/address (never the seed words) — used to validate the full C++
creator path without the GUI. Harmless in normal runs.

Validated end-to-end against the hd-transparent-keys (v1.0.3-dc45e7d9)
daemon: ok=1, words=24, a shielded z-address returned, temp datadir cleaned up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 14:17:00 -05:00
718cb82c13 feat(wallet): migrate-to-seed, Phase 1 — isolated seed-wallet creation
First, fund-safe step of "migrate a legacy wallet to a seed wallet": mint a
brand-new BIP39 mnemonic wallet in an ISOLATED throwaway datadir so the user
can later sweep funds into it. No funds move and the real wallet.dat / main
daemon are never touched — the isolated node runs concurrently on its own port.

- EmbeddedDaemon: one-shot isolated-datadir override (setNextStartOverride)
  consumed on the next start(); a skip-default-port-check for an isolated
  instance beside the main daemon; and a tcpPortInUse() probe. The datadir's
  basename must be the assetchain name (DRAGONX) and the daemon reads
  <datadir>/DRAGONX.conf itself, so no -conf is passed (both learned from
  live testing against the hd-transparent-keys daemon).
- SeedWalletCreator (src/daemon): picks a free port, writes a throwaway conf,
  starts an isolated dragonxd with -usemnemonic=1 -connect=0, waits for RPC,
  calls z_exportmnemonic + z_getnewaddress (the sweep target), stops it, and
  keeps/scrubs the temp datadir. Off-thread; the seed is wiped after use.
- App: beginCreateSeedWallet (background) -> pumpSeedMigration (main-thread
  handoff) -> renderSeedMigrationDialog (Intro -> Working -> Show seed ->
  Error), reusing the seed_display grid + clipboard auto-clear.
- Settings: "Migrate to seed…" button (full-node gated) + persisted pending
  migration state (dest address + temp datadir) for Phase 2 to adopt.

Validated end-to-end against the hd-transparent-keys daemon: the isolated
node comes up in ~4s and returns a 24-word mnemonic + a shielded z-address.
Requires that daemon (the bundled Jun-28 build lacks z_exportmnemonic). The
migration modal uses English literals for now (as renderBackupDialog does);
the whole flow gets translated once Phase 2 finalizes it. Phase 2 (sweep +
adopt) is next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 12:53:36 -05:00
403e145b30 feat(wallet): give new full-node wallets a BIP39 seed phrase + backup UI
New full-node wallets now get a real 24-word recovery phrase, and users can
reveal/back it up from Settings.

- Pass -usemnemonic=1 to dragonxd. 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 freshly-created
  wallet mnemonic-backed — its phrase is then exportable via z_exportmnemonic
  and portable to SDXLite/ObsidianDragonLite. (Existing/legacy wallets are
  unaffected and keep using the chat identity's z_exportkey fallback.)
- App::exportSeedPhrase() wraps z_exportmnemonic on the RPC worker with
  sodium_memzero wiping on every path; it flags the daemon's "not derived
  from a mnemonic" error as a legacy wallet rather than a failure.
- New "Back up seed phrase" modal (Settings -> Backup & Data, full-node
  gated): reveals the phrase in a numbered word grid, copy (45s clipboard
  auto-clear) + save-to-file (0600), wipes the secret on every close path
  incl. dismiss-mid-fetch. Shared ui/windows/seed_display.h grid helper.
- One-time nudge (settings flag seed_backup_reminded) toasts mnemonic-wallet
  users to back up their phrase; legacy wallets are not nagged.
- 15 new strings translated into all 8 languages (additive, 957->972 keys);
  CJK subset font rebuilt for the new glyphs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 10:49:03 -05:00
036199a011 chore(i18n): retire the stale per-language gen_<lang>.py generators
Each scripts/gen_<lang>.py held a hardcoded `translations` dict that it
wrote over res/lang/<lang>.json wholesale. Those dicts had drifted ~285
keys behind the committed JSONs (keys were added directly to the JSONs
over time), so running any generator silently truncated a language file —
a live regression trap. Nothing invokes them (not build.sh, CMake, or CI),
and the JSONs are now the maintained source of truth, so the generators are
pure duplication plus a footgun.

Retire all eight. The additive, non-destructive scripts/add_missing_
translations.py remains the i18n helper, and CLAUDE.md now documents the
"edit the JSONs directly and additively" workflow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 01:07:55 -05:00
715cfd622e fix(ui): handle lite-only NavPage cases in tracePageName switch
tracePageName()'s switch over ui::NavPage was missing the two lite-only
tab values (LiteConsole, LiteNetwork), producing -Wswitch warnings in the
lite build. Add both, tracing them to the same labels as their full-node
siblings ("Console tab" / "Network tab") — exactly one of each pair shows
per variant. Trace-string only; no behaviour change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 01:04:35 -05:00
32 changed files with 1290 additions and 5194 deletions

View File

@@ -98,5 +98,5 @@ The version has a **single source of truth**: `project(... VERSION 1.2.0 ...)` p
- **C++17.** Match the surrounding code's style per file.
- **Icons:** use the Material Design icon font defines (`ICON_MD_*`); never raw Unicode glyphs.
- **UI layout values** belong in `res/themes/ui.toml`, read via `schema::UI()` — do not hardcode pixel sizes/offsets in code.
- **i18n:** user-facing strings are translated via `src/util/i18n`; translation JSON lives in `res/lang/` (`de`, `es`, `fr`, `ja`, `ko`, `pt`, `ru`, `zh`, English fallback in code). Translation/font helper scripts are in `scripts/` (`gen_*.py`, CJK subset tooling).
- **i18n:** user-facing strings are translated via `src/util/i18n`; the English source of truth is the `strings_[...]` map in `src/util/i18n.cpp`, and the per-language translations live as the **source of truth** in `res/lang/` (`de`, `es`, `fr`, `ja`, `ko`, `pt`, `ru`, `zh`). **Edit those JSONs directly and additively** — write with `json.dump(..., indent=4, sort_keys=True, ensure_ascii=False)`; never bulk-regenerate/overwrite a whole file (that path silently dropped ~285 keys/language before). `scripts/add_missing_translations.py` back-fills only the keys missing from a JSON (non-destructive), and `scripts/build_cjk_subset.py` rebuilds the CJK subset font (`res/fonts/NotoSansCJK-Subset.ttf`) after new CJK glyphs are added.
- **Commits:** the history uses Conventional Commits (`feat(scope): …`, `fix(scope): …`). PRs target `master`.

View File

@@ -503,6 +503,7 @@ set(APP_SOURCES
src/util/texture_loader.cpp
src/util/noise_texture.cpp
src/daemon/embedded_daemon.cpp
src/daemon/seed_wallet_creator.cpp
src/daemon/daemon_controller.cpp
src/daemon/lifecycle_adapters.cpp
src/daemon/xmrig_manager.cpp
@@ -634,6 +635,7 @@ set(APP_HEADERS
src/util/payment_uri.h
src/util/secure_vault.h
src/daemon/embedded_daemon.h
src/daemon/seed_wallet_creator.h
src/daemon/daemon_controller.h
src/daemon/lifecycle_adapters.h
src/daemon/xmrig_manager.h

Binary file not shown.

View File

@@ -641,6 +641,20 @@
"sb_warming_up": "Aufwärmen...",
"search_placeholder": "Suchen...",
"security": "SICHERHEIT",
"seed_backup_button": "Wiederherstellungsphrase",
"seed_backup_close": "Schließen",
"seed_backup_copy": "Kopieren",
"seed_backup_intro": "Diese Wörter sind die Master-Sicherung Ihrer Wallet. Wer sie besitzt, kontrolliert Ihre Gelder.",
"seed_backup_load_failed": "Die Wiederherstellungsphrase konnte nicht geladen werden.",
"seed_backup_loading": "Ihre Wiederherstellungsphrase wird geladen…",
"seed_backup_locked": "Entsperren Sie Ihre Wallet, um ihre Wiederherstellungsphrase anzuzeigen.",
"seed_backup_none": "Diese Wallet ist älter als Wiederherstellungsphrasen und hat daher keine 24-Wort-Phrase. Sichern Sie sie stattdessen mit „Sicherung...“ oder durch den Export Ihrer privaten Schlüssel.",
"seed_backup_reminder": "Ihre Wallet hat eine 24-Wort-Wiederherstellungsphrase. Sichern Sie sie jetzt unter Einstellungen → Node & Sicherheit.",
"seed_backup_save": "In Datei speichern…",
"seed_backup_save_failed": "Konnte nicht schreiben ",
"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.",
"select_address": "Adresse auswählen...",
"select_receiving_address": "Empfangsadresse auswählen...",
"select_source_address": "Quelladresse auswählen...",
@@ -889,6 +903,7 @@
"tt_save_ztx": "Z-Adresse-Transaktionsverlauf lokal für schnelleres Laden speichern",
"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_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",

View File

@@ -641,6 +641,20 @@
"sb_warming_up": "Calentando...",
"search_placeholder": "Buscar...",
"security": "SEGURIDAD",
"seed_backup_button": "Frase de recuperación",
"seed_backup_close": "Cerrar",
"seed_backup_copy": "Copiar",
"seed_backup_intro": "Estas palabras son el respaldo maestro de tu cartera. Cualquiera que las tenga controla tus fondos.",
"seed_backup_load_failed": "No se pudo cargar la frase de recuperación.",
"seed_backup_loading": "Cargando tu frase de recuperación…",
"seed_backup_locked": "Desbloquea tu cartera para revelar su frase de recuperación.",
"seed_backup_none": "Esta cartera es anterior a las frases de recuperación, por lo que no tiene una frase de 24 palabras. Respáldala con «Respaldo...» o exportando tus claves privadas en su lugar.",
"seed_backup_reminder": "Tu cartera tiene una frase de recuperación de 24 palabras. Respáldala ahora en Configuración → Nodo y Seguridad.",
"seed_backup_save": "Guardar en archivo…",
"seed_backup_save_failed": "No se pudo escribir ",
"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.",
"select_address": "Seleccionar dirección...",
"select_receiving_address": "Seleccionar dirección de recepción...",
"select_source_address": "Seleccionar dirección de origen...",
@@ -889,6 +903,7 @@
"tt_save_ztx": "Almacenar historial de transacciones de z-address localmente para carga más rápida",
"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_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",

View File

@@ -641,6 +641,20 @@
"sb_warming_up": "Démarrage...",
"search_placeholder": "Rechercher...",
"security": "SÉCURITÉ",
"seed_backup_button": "Phrase de récupération",
"seed_backup_close": "Fermer",
"seed_backup_copy": "Copier",
"seed_backup_intro": "Ces mots sont la sauvegarde principale de votre portefeuille. Quiconque les possède contrôle vos fonds.",
"seed_backup_load_failed": "Impossible de charger la phrase de récupération.",
"seed_backup_loading": "Chargement de votre phrase de récupération…",
"seed_backup_locked": "Déverrouillez votre portefeuille pour révéler sa phrase de récupération.",
"seed_backup_none": "Ce portefeuille est antérieur aux phrases de récupération, il n'a donc pas de phrase de 24 mots. Sauvegardez-le plutôt avec « Sauvegarde » ou en exportant vos clés privées.",
"seed_backup_reminder": "Votre portefeuille possède une phrase de récupération de 24 mots. Sauvegardez-la maintenant dans Paramètres → Nœud et sécurité.",
"seed_backup_save": "Enregistrer dans un fichier…",
"seed_backup_save_failed": "Impossible d'écrire ",
"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.",
"select_address": "Sélectionner une adresse...",
"select_receiving_address": "Sélectionner une adresse de réception...",
"select_source_address": "Sélectionner une adresse source...",
@@ -889,6 +903,7 @@
"tt_save_ztx": "Stocker l'historique des transactions z-address localement pour un chargement plus rapide",
"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_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",

View File

@@ -641,6 +641,20 @@
"sb_warming_up": "ウォームアップ中...",
"search_placeholder": "検索...",
"security": "セキュリティ",
"seed_backup_button": "シードフレーズ",
"seed_backup_close": "閉じる",
"seed_backup_copy": "コピー",
"seed_backup_intro": "これらの単語はウォレットのマスターバックアップです。これらを持つ人は誰でもあなたの資金を管理できます。",
"seed_backup_load_failed": "シードフレーズを読み込めませんでした。",
"seed_backup_loading": "シードフレーズを読み込み中...",
"seed_backup_locked": "シードフレーズを表示するにはウォレットのロックを解除してください。",
"seed_backup_none": "このウォレットはシードフレーズより前のものなので、24単語のフレーズはありません。代わりに「バックアップ...」で、または秘密鍵をエクスポートしてバックアップしてください。",
"seed_backup_reminder": "ウォレットには24単語の復元シードフレーズがあります。今すぐ 設定 → ノードとセキュリティ でバックアップしてください。",
"seed_backup_save": "ファイルに保存...",
"seed_backup_save_failed": "書き込めませんでした: ",
"seed_backup_saved": "保存先: ",
"seed_backup_title": "シードフレーズをバックアップ",
"seed_backup_warning": "順番どおりに書き写し、オフラインで保管してください。決して共有や撮影をしないでください。紛失すると資金を復元できません。",
"select_address": "アドレスを選択...",
"select_receiving_address": "受信アドレスを選択...",
"select_source_address": "送信元アドレスを選択...",
@@ -889,6 +903,7 @@
"tt_save_ztx": "z-address トランザクション履歴をローカルに保存して高速読み込み",
"tt_scan_themes": "新しいテーマをスキャン。\\nテーマフォルダーをここに配置\\n%s",
"tt_scanline": "コンソールでの CRT スキャンライン効果",
"tt_seed_backup": "ウォレットの24単語の復元シードフレーズを表示してバックアップします",
"tt_set_pin": "クイックアンロック用の 4-8 桁 PIN を設定",
"tt_shield_mining": "透明マイニング報酬をシールドアドレスに移動",
"tt_simple_bg": "背景にシンプルなグラデーションを使用\\nホットキーCtrl+Up",

View File

@@ -641,6 +641,20 @@
"sb_warming_up": "워밍업 중...",
"search_placeholder": "검색...",
"security": "보안",
"seed_backup_button": "시드 문구",
"seed_backup_close": "닫기",
"seed_backup_copy": "복사",
"seed_backup_intro": "이 단어들은 지갑의 마스터 백업입니다. 이 단어들을 가진 사람은 누구나 당신의 자금을 통제할 수 있습니다.",
"seed_backup_load_failed": "시드 문구를 불러올 수 없습니다.",
"seed_backup_loading": "시드 문구를 불러오는 중…",
"seed_backup_locked": "시드 문구를 표시하려면 지갑의 잠금을 해제하세요.",
"seed_backup_none": "이 지갑은 시드 문구 도입 이전에 만들어져 24단어 문구가 없습니다. 대신 \"백업...\"을 사용하거나 개인 키를 내보내 백업하세요.",
"seed_backup_reminder": "지갑에 24단어 복구 시드 문구가 있습니다. 지금 설정 → 노드 및 보안에서 백업하세요.",
"seed_backup_save": "파일로 저장…",
"seed_backup_save_failed": "쓸 수 없습니다: ",
"seed_backup_saved": "저장됨: ",
"seed_backup_title": "시드 문구 백업",
"seed_backup_warning": "순서대로 종이에 적어 오프라인으로 보관하고, 절대 공유하거나 사진으로 찍지 마세요. 이 단어들을 잃어버리면 자금을 복구할 수 없습니다.",
"select_address": "주소 선택...",
"select_receiving_address": "수신 주소 선택...",
"select_source_address": "보낼 주소 선택...",
@@ -889,6 +903,7 @@
"tt_save_ztx": "z-address 거래 기록을 로컬에 저장하여 빠른 로딩",
"tt_scan_themes": "새 테마 검색.\\n테마 폴더를 여기에 배치:\\n%s",
"tt_scanline": "콘솔에서 CRT 스캔라인 효과",
"tt_seed_backup": "지갑의 24단어 복구 시드 문구를 표시하고 백업합니다",
"tt_set_pin": "빠른 잠금 해제를 위한 4-8자리 PIN 설정",
"tt_shield_mining": "투명 채굴 보상을 차폐 주소로 이동",
"tt_simple_bg": "배경에 단순 그라데이션 사용\\n단축키: Ctrl+Up",

View File

@@ -641,6 +641,20 @@
"sb_warming_up": "Aquecendo...",
"search_placeholder": "Pesquisar...",
"security": "SEGURANÇA",
"seed_backup_button": "Frase de recuperação",
"seed_backup_close": "Fechar",
"seed_backup_copy": "Copiar",
"seed_backup_intro": "Estas palavras são o backup mestre da sua carteira. Qualquer pessoa que as tenha controla seus fundos.",
"seed_backup_load_failed": "Não foi possível carregar a frase de recuperação.",
"seed_backup_loading": "Carregando sua frase de recuperação…",
"seed_backup_locked": "Desbloqueie sua carteira para revelar sua frase de recuperação.",
"seed_backup_none": "Esta carteira é anterior às frases de recuperação, portanto não possui uma frase de 24 palavras. Faça o backup dela com \"Backup...\" ou exportando suas chaves privadas.",
"seed_backup_reminder": "Sua carteira tem uma frase de recuperação de 24 palavras. Faça o backup dela agora em Configurações → Nó e Segurança.",
"seed_backup_save": "Salvar em arquivo…",
"seed_backup_save_failed": "Não foi possível gravar ",
"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.",
"select_address": "Selecionar endereço...",
"select_receiving_address": "Selecionar endereço de recebimento...",
"select_source_address": "Selecionar endereço de origem...",
@@ -889,6 +903,7 @@
"tt_save_ztx": "Armazenar histórico de transações z-address localmente para carregamento mais rápido",
"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_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",

View File

@@ -641,6 +641,20 @@
"sb_warming_up": "Прогрев...",
"search_placeholder": "Поиск...",
"security": "БЕЗОПАСНОСТЬ",
"seed_backup_button": "Сид-фраза",
"seed_backup_close": "Закрыть",
"seed_backup_copy": "Копировать",
"seed_backup_intro": "Эти слова — главная резервная копия вашего кошелька. Любой, у кого они есть, управляет вашими средствами.",
"seed_backup_load_failed": "Не удалось загрузить сид-фразу.",
"seed_backup_loading": "Загрузка вашей сид-фразы…",
"seed_backup_locked": "Разблокируйте кошелёк, чтобы показать его сид-фразу.",
"seed_backup_none": "Этот кошелёк создан до появления сид-фраз, поэтому у него нет фразы из 24 слов. Создайте резервную копию с помощью «Резервная копия...» или вместо этого экспортируйте свои приватные ключи.",
"seed_backup_reminder": "У вашего кошелька есть сид-фраза восстановления из 24 слов. Создайте её резервную копию прямо сейчас в Настройки → Узел и безопасность.",
"seed_backup_save": "Сохранить в файл…",
"seed_backup_save_failed": "Не удалось записать ",
"seed_backup_saved": "Сохранено в ",
"seed_backup_title": "Резервная копия сид-фразы",
"seed_backup_warning": "Запишите их по порядку, храните офлайн и никогда не делитесь ими и не фотографируйте их. Если вы их потеряете, ваши средства не удастся восстановить.",
"select_address": "Выбрать адрес...",
"select_receiving_address": "Выбрать адрес получения...",
"select_source_address": "Выбрать адрес-источник...",
@@ -889,6 +903,7 @@
"tt_save_ztx": "Хранить историю транзакций z-адреса локально для более быстрой загрузки",
"tt_scan_themes": "Поиск новых тем.\\nРазместите папки тем в:\\n%s",
"tt_scanline": "Эффект развёртки ЭЛТ в консоли",
"tt_seed_backup": "Показать и создать резервную копию сид-фразы восстановления вашего кошелька из 24 слов",
"tt_set_pin": "Установить 4-8-значный PIN для быстрой разблокировки",
"tt_shield_mining": "Перевести прозрачные вознаграждения за майнинг на экранированный адрес",
"tt_simple_bg": "Использовать простой градиент для фона\\nГорячая клавиша: Ctrl+Up",

View File

@@ -641,6 +641,20 @@
"sb_warming_up": "正在预热...",
"search_placeholder": "搜索...",
"security": "安全",
"seed_backup_button": "助记词",
"seed_backup_close": "关闭",
"seed_backup_copy": "复制",
"seed_backup_intro": "这些词是您钱包的主备份。任何拥有它们的人都能控制您的资金。",
"seed_backup_load_failed": "无法加载助记词。",
"seed_backup_loading": "正在加载您的助记词…",
"seed_backup_locked": "解锁您的钱包以显示其助记词。",
"seed_backup_none": "此钱包早于助记词功能,因此没有 24 词助记词。请改用“备份钱包”或导出私钥来备份它。",
"seed_backup_reminder": "您的钱包有一个 24 词恢复助记词。请立即在“设置 → 节点与安全”中备份它。",
"seed_backup_save": "保存到文件…",
"seed_backup_save_failed": "无法写入 ",
"seed_backup_saved": "已保存到 ",
"seed_backup_title": "备份助记词",
"seed_backup_warning": "请按顺序将它们抄写下来,离线保存,切勿分享或拍照。一旦丢失,您的资金将无法恢复。",
"select_address": "选择地址...",
"select_receiving_address": "选择接收地址...",
"select_source_address": "选择来源地址...",
@@ -889,6 +903,7 @@
"tt_save_ztx": "将 z-address 交易历史存储在本地以加快加载速度",
"tt_scan_themes": "扫描新主题。\\n将主题文件夹放在\\n%s",
"tt_scanline": "控制台中的 CRT 扫描线效果",
"tt_seed_backup": "显示并备份您钱包的 24 词恢复助记词",
"tt_set_pin": "设置 4-8 位 PIN 以快速解锁",
"tt_shield_mining": "将透明挖矿奖励转移到屏蔽地址",
"tt_simple_bg": "使用简单渐变作为背景\\n快捷键Ctrl+Up",

View File

@@ -1,645 +0,0 @@
#!/usr/bin/env python3
"""Generate German (de) translations for ObsidianDragon wallet."""
import json, os
translations = {
"24h_change": "24h Änderung",
"24h_volume": "24h Volumen",
"about": "Über",
"about_block_explorer": "Block-Explorer",
"about_block_height": "Blockhöhe:",
"about_build_date": "Erstellungsdatum:",
"about_build_type": "Build-Typ:",
"about_chain": "Chain:",
"about_connections": "Verbindungen:",
"about_credits": "Danksagungen",
"about_daemon": "Daemon:",
"about_debug": "Debug",
"about_dragonx": "Über ObsidianDragon",
"about_edition": "ImGui Edition",
"about_github": "GitHub",
"about_imgui": "ImGui:",
"about_license": "Lizenz",
"about_license_text": "Diese Software wird unter der GNU General Public License v3 (GPLv3) veröffentlicht. Sie dürfen diese Software gemäß den Lizenzbedingungen frei verwenden, modifizieren und verbreiten.",
"about_peers_count": "%zu Peers",
"about_release": "Release",
"about_title": "Über ObsidianDragon",
"about_version": "Version:",
"about_website": "Webseite",
"acrylic": "Acryl",
"add": "Hinzufügen",
"address": "Adresse",
"address_book_add": "Adresse hinzufügen",
"address_book_add_new": "Neue hinzufügen",
"address_book_added": "Adresse zum Buch hinzugefügt",
"address_book_count": "%zu Adressen gespeichert",
"address_book_deleted": "Eintrag gelöscht",
"address_book_edit": "Adresse bearbeiten",
"address_book_empty": "Keine gespeicherten Adressen. Klicken Sie auf 'Neue hinzufügen', um eine hinzuzufügen.",
"address_book_exists": "Adresse existiert bereits im Buch",
"address_book_title": "Adressbuch",
"address_book_update_failed": "Aktualisierung fehlgeschlagen - Adresse könnte doppelt sein",
"address_book_updated": "Adresse aktualisiert",
"address_copied": "Adresse in Zwischenablage kopiert",
"address_details": "Adressdetails",
"address_label": "Adresse:",
"address_upper": "ADRESSE",
"address_url": "Adress-URL",
"addresses_appear_here": "Ihre Empfangsadressen erscheinen hier, sobald Sie verbunden sind.",
"advanced": "ERWEITERT",
"all_filter": "Alle",
"allow_custom_fees": "Benutzerdefinierte Gebühren erlauben",
"amount": "Betrag",
"amount_details": "BETRAGSDETAILS",
"amount_exceeds_balance": "Betrag übersteigt Guthaben",
"amount_label": "Betrag:",
"appearance": "ERSCHEINUNGSBILD",
"auto_shield": "Mining automatisch abschirmen",
"available": "Verfügbar",
"backup_backing_up": "Sicherung läuft...",
"backup_create": "Sicherung erstellen",
"backup_created": "Wallet-Sicherung erstellt",
"backup_data": "SICHERUNG & DATEN",
"backup_description": "Erstellen Sie eine Sicherung Ihrer wallet.dat-Datei. Diese Datei enthält alle Ihre privaten Schlüssel und den Transaktionsverlauf. Bewahren Sie die Sicherung an einem sicheren Ort auf.",
"backup_destination": "Sicherungsziel:",
"backup_tip_external": "Speichern Sie Sicherungen auf externen Laufwerken oder Cloud-Speicher",
"backup_tip_multiple": "Erstellen Sie mehrere Sicherungen an verschiedenen Orten",
"backup_tip_test": "Testen Sie regelmäßig die Wiederherstellung aus der Sicherung",
"backup_tips": "Tipps:",
"backup_title": "Wallet sichern",
"backup_wallet": "Wallet sichern...",
"backup_wallet_not_found": "Warnung: wallet.dat nicht am erwarteten Speicherort gefunden",
"balance": "Guthaben",
"balance_layout": "Guthaben-Layout",
"ban": "Sperren",
"banned_peers": "Gesperrte Peers",
"block": "Block",
"block_bits": "Bits:",
"block_click_next": "Klicken für nächsten Block",
"block_click_prev": "Klicken für vorherigen Block",
"block_explorer": "Block-Explorer",
"block_get_info": "Block-Info abrufen",
"block_hash": "Block-Hash:",
"block_height": "Blockhöhe:",
"block_info_title": "Block-Informationen",
"block_merkle_root": "Merkle-Root:",
"block_nav_next": "Weiter >>",
"block_nav_prev": "<< Zurück",
"block_next": "Nächster Block:",
"block_previous": "Vorheriger Block:",
"block_size": "Größe:",
"block_timestamp": "Zeitstempel:",
"block_transactions": "Transaktionen:",
"blockchain_syncing": "Blockchain synchronisiert (%.1f%%)... Guthaben könnten ungenau sein.",
"cancel": "Abbrechen",
"characters": "Zeichen",
"clear": "Leeren",
"clear_all_bans": "Alle Sperren aufheben",
"clear_form_confirm": "Alle Formularfelder leeren?",
"clear_request": "Anfrage leeren",
"click_copy_address": "Klicken zum Kopieren der Adresse",
"click_copy_uri": "Klicken zum Kopieren der URI",
"close": "Schließen",
"conf_count": "%d Best.",
"confirm_and_send": "Bestätigen & Senden",
"confirm_send": "Senden bestätigen",
"confirm_transaction": "Transaktion bestätigen",
"confirmations": "Bestätigungen",
"confirmations_display": "%d Bestätigungen | %s",
"confirmed": "Bestätigt",
"connected": "Verbunden",
"connected_peers": "Verbundene Peers",
"connecting": "Verbinde...",
"console": "Konsole",
"console_auto_scroll": "Automatisch scrollen",
"console_available_commands": "Verfügbare Befehle:",
"console_capturing_output": "Erfasse Daemon-Ausgabe...",
"console_clear": "Leeren",
"console_clear_console": "Konsole leeren",
"console_cleared": "Konsole geleert",
"console_click_commands": "Befehle oben klicken zum Einfügen",
"console_click_insert": "Klicken zum Einfügen",
"console_click_insert_params": "Klicken zum Einfügen mit Parametern",
"console_close": "Schließen",
"console_commands": "Befehle",
"console_common_rpc": "Häufige RPC-Befehle:",
"console_completions": "Vervollständigungen:",
"console_connected": "Verbunden mit Daemon",
"console_copy_all": "Alles kopieren",
"console_copy_selected": "Kopieren",
"console_daemon": "Daemon",
"console_daemon_error": "Daemon-Fehler!",
"console_daemon_started": "Daemon gestartet",
"console_daemon_stopped": "Daemon gestoppt",
"console_disconnected": "Vom Daemon getrennt",
"console_errors": "Fehler",
"console_filter_hint": "Ausgabe filtern...",
"console_help_clear": " clear - Konsole leeren",
"console_help_getbalance": " getbalance - Transparentes Guthaben anzeigen",
"console_help_getblockcount": " getblockcount - Aktuelle Blockhöhe anzeigen",
"console_help_getinfo": " getinfo - Knoteninformationen anzeigen",
"console_help_getmininginfo": " getmininginfo - Mining-Status anzeigen",
"console_help_getpeerinfo": " getpeerinfo - Verbundene Peers anzeigen",
"console_help_gettotalbalance": " gettotalbalance - Gesamtguthaben anzeigen",
"console_help_help": " help - Diese Hilfe anzeigen",
"console_help_setgenerate": " setgenerate - Mining steuern",
"console_help_stop": " stop - Daemon stoppen",
"console_line_count": "%zu Zeilen",
"console_new_lines": "%d neue Zeilen",
"console_no_daemon": "Kein Daemon",
"console_not_connected": "Fehler: Nicht mit Daemon verbunden",
"console_rpc_reference": "RPC-Befehlsreferenz",
"console_scanline": "Konsolen-Scanline",
"console_search_commands": "Befehle suchen...",
"console_select_all": "Alles auswählen",
"console_show_daemon_output": "Daemon-Ausgabe anzeigen",
"console_show_errors_only": "Nur Fehler anzeigen",
"console_show_rpc_ref": "RPC-Befehlsreferenz anzeigen",
"console_showing_lines": "Zeige %zu von %zu Zeilen",
"console_starting_node": "Knoten wird gestartet...",
"console_status_error": "Fehler",
"console_status_running": "Läuft",
"console_status_starting": "Startet",
"console_status_stopped": "Gestoppt",
"console_status_stopping": "Stoppt",
"console_status_unknown": "Unbekannt",
"console_tab_completion": "Tab zur Vervollständigung",
"console_type_help": "Geben Sie 'help' ein für verfügbare Befehle",
"console_welcome": "Willkommen bei ObsidianDragon Konsole",
"console_zoom_in": "Vergrößern",
"console_zoom_out": "Verkleinern",
"copy": "Kopieren",
"copy_address": "Vollständige Adresse kopieren",
"copy_error": "Fehler kopieren",
"copy_to_clipboard": "In Zwischenablage kopieren",
"copy_txid": "TxID kopieren",
"copy_uri": "URI kopieren",
"current_price": "Aktueller Preis",
"custom_fees": "Benutzerdefinierte Gebühren",
"dark": "Dunkel",
"date": "Datum",
"date_label": "Datum:",
"delete": "Löschen",
"difficulty": "Schwierigkeit",
"disconnected": "Getrennt",
"dismiss": "Verwerfen",
"display": "Anzeige",
"dragonx_green": "DragonX (Grün)",
"edit": "Bearbeiten",
"error": "Fehler",
"est_time_to_block": "Gesch. Zeit bis Block",
"exit": "Beenden",
"explorer": "EXPLORER",
"export": "Exportieren",
"export_csv": "CSV exportieren",
"export_keys_btn": "Schlüssel exportieren",
"export_keys_danger": "ACHTUNG: Dies exportiert ALLE privaten Schlüssel aus Ihrer Wallet! Jeder mit Zugriff auf diese Datei kann Ihre Gelder stehlen. Sicher aufbewahren und nach Gebrauch löschen.",
"export_keys_include_t": "T-Adressen einschließen (transparent)",
"export_keys_include_z": "Z-Adressen einschließen (abgeschirmt)",
"export_keys_options": "Export-Optionen:",
"export_keys_success": "Schlüssel erfolgreich exportiert",
"export_keys_title": "Alle privaten Schlüssel exportieren",
"export_private_key": "Privaten Schlüssel exportieren",
"export_tx_count": "%zu Transaktionen als CSV exportieren.",
"export_tx_file_fail": "CSV-Datei konnte nicht erstellt werden",
"export_tx_none": "Keine Transaktionen zum Exportieren",
"export_tx_success": "Transaktionen erfolgreich exportiert",
"export_tx_title": "Transaktionen als CSV exportieren",
"export_viewing_key": "Betrachtungsschlüssel exportieren",
"failed_create_shielded": "Abgeschirmte Adresse konnte nicht erstellt werden",
"failed_create_transparent": "Transparente Adresse konnte nicht erstellt werden",
"fee": "Gebühr",
"fee_high": "Hoch",
"fee_label": "Gebühr:",
"fee_low": "Niedrig",
"fee_normal": "Normal",
"fetch_prices": "Preise abrufen",
"file": "Datei",
"file_save_location": "Datei wird gespeichert in: ~/.config/ObsidianDragon/",
"font_scale": "Schriftgröße",
"from": "Von",
"from_upper": "VON",
"full_details": "Alle Details",
"general": "Allgemein",
"go_to_receive": "Zum Empfangen",
"height": "Höhe",
"help": "Hilfe",
"hide": "Ausblenden",
"history": "Verlauf",
"immature_type": "Unreif",
"import": "Importieren",
"import_key_btn": "Schlüssel importieren",
"import_key_formats": "Unterstützte Schlüsselformate:",
"import_key_full_rescan": "(0 = vollständiger Rescan)",
"import_key_label": "Privater Schlüssel:",
"import_key_no_valid": "Keine gültigen Schlüssel in der Eingabe gefunden",
"import_key_rescan": "Blockchain nach Import neu scannen",
"import_key_start_height": "Starthöhe:",
"import_key_success": "Schlüssel erfolgreich importiert",
"import_key_t_format": "T-Adresse WIF private Schlüssel",
"import_key_title": "Privaten Schlüssel importieren",
"import_key_tooltip": "Geben Sie einen oder mehrere private Schlüssel ein, einen pro Zeile.\nUnterstützt sowohl z-Adresse als auch t-Adresse Schlüssel.\nZeilen die mit # beginnen werden als Kommentare behandelt.",
"import_key_warning": "Warnung: Teilen Sie niemals Ihre privaten Schlüssel! Das Importieren von Schlüsseln aus nicht vertrauenswürdigen Quellen kann Ihr Wallet gefährden.",
"import_key_z_format": "Z-Adresse Ausgabeschlüssel (secret-extended-key-...)",
"import_private_key": "Privaten Schlüssel importieren...",
"invalid_address": "Ungültiges Adressformat",
"ip_address": "IP-Adresse",
"keep": "Behalten",
"keep_daemon": "Daemon weiterlaufen lassen",
"key_export_fetching": "Schlüssel wird aus Wallet abgerufen...",
"key_export_private_key": "Privater Schlüssel:",
"key_export_private_warning": "Halten Sie diesen Schlüssel GEHEIM! Jeder mit diesem Schlüssel kann Ihre Gelder ausgeben. Teilen Sie ihn niemals online oder mit nicht vertrauenswürdigen Parteien.",
"key_export_reveal": "Schlüssel anzeigen",
"key_export_viewing_key": "Betrachtungsschlüssel:",
"key_export_viewing_warning": "Dieser Betrachtungsschlüssel ermöglicht es anderen, Ihre eingehenden Transaktionen und Ihr Guthaben zu sehen, aber NICHT Ihre Gelder auszugeben. Teilen Sie ihn nur mit vertrauenswürdigen Parteien.",
"label": "Bezeichnung:",
"language": "Sprache",
"light": "Hell",
"loading": "Laden...",
"loading_addresses": "Adressen werden geladen...",
"local_hashrate": "Lokale Hashrate",
"low_spec_mode": "Energiesparmodus",
"market": "Markt",
"market_12h": "12h",
"market_18h": "18h",
"market_24h": "24h",
"market_24h_volume": "24H VOLUMEN",
"market_6h": "6h",
"market_attribution": "Preisdaten von NonKYC",
"market_btc_price": "BTC PREIS",
"market_cap": "Marktkapitalisierung",
"market_no_history": "Kein Preisverlauf verfügbar",
"market_no_price": "Keine Preisdaten",
"market_now": "Jetzt",
"market_pct_shielded": "%.0f%% Abgeschirmt",
"market_portfolio": "PORTFOLIO",
"market_price_unavailable": "Preisdaten nicht verfügbar",
"market_refresh_price": "Preisdaten aktualisieren",
"market_trade_on": "Handeln auf %s",
"mature": "Reif",
"max": "Max",
"memo": "Memo (optional, verschlüsselt)",
"memo_label": "Memo:",
"memo_optional": "MEMO (OPTIONAL)",
"memo_upper": "MEMO",
"memo_z_only": "Hinweis: Memos sind nur beim Senden an abgeschirmte (z) Adressen verfügbar",
"merge_description": "Mehrere UTXOs zu einer einzelnen abgeschirmten Adresse zusammenführen. Dies kann die Wallet-Größe reduzieren und die Privatsphäre verbessern.",
"merge_funds": "Gelder zusammenführen",
"merge_started": "Zusammenführung gestartet",
"merge_title": "An Adresse zusammenführen",
"mine_when_idle": "Im Leerlauf minen",
"mined": "gemined",
"mined_filter": "Gemined",
"mined_type": "Gemined",
"mined_upper": "GEMINED",
"miner_fee": "Miner-Gebühr",
"mining": "Mining",
"mining_active": "Aktiv",
"mining_address_copied": "Mining-Adresse kopiert",
"mining_all_time": "Gesamt",
"mining_already_saved": "Pool-URL bereits gespeichert",
"mining_block_copied": "Block-Hash kopiert",
"mining_chart_1m_ago": "vor 1m",
"mining_chart_5m_ago": "vor 5m",
"mining_chart_now": "Jetzt",
"mining_click": "Klicken",
"mining_click_copy_address": "Klicken zum Kopieren der Adresse",
"mining_click_copy_block": "Klicken zum Kopieren des Block-Hash",
"mining_click_copy_difficulty": "Klicken zum Kopieren der Schwierigkeit",
"mining_connected": "Verbunden",
"mining_connecting": "Verbinde...",
"mining_control": "Mining-Steuerung",
"mining_difficulty_copied": "Schwierigkeit kopiert",
"mining_est_block": "Gesch. Block",
"mining_est_daily": "Gesch. täglich",
"mining_filter_all": "Alle",
"mining_filter_tip_all": "Alle Einnahmen anzeigen",
"mining_filter_tip_pool": "Nur Pool-Einnahmen anzeigen",
"mining_filter_tip_solo": "Nur Solo-Einnahmen anzeigen",
"mining_idle_off_tooltip": "Leerlauf-Mining aktivieren",
"mining_idle_on_tooltip": "Leerlauf-Mining deaktivieren",
"mining_local_hashrate": "Lokale Hashrate",
"mining_mine": "Minen",
"mining_mining_addr": "Mining-Adr.",
"mining_network": "Netzwerk",
"mining_no_blocks_yet": "Noch keine Blöcke gefunden",
"mining_no_payouts_yet": "Noch keine Pool-Auszahlungen",
"mining_no_saved_addresses": "Keine gespeicherten Adressen",
"mining_no_saved_pools": "Keine gespeicherten Pools",
"mining_off": "Mining ist AUS",
"mining_on": "Mining ist AN",
"mining_open_in_explorer": "Im Explorer öffnen",
"mining_payout_address": "Auszahlungsadresse",
"mining_payout_tooltip": "Adresse für Mining-Belohnungen",
"mining_pool": "Pool",
"mining_pool_hashrate": "Pool-Hashrate",
"mining_pool_url": "Pool-URL",
"mining_recent_blocks": "LETZTE BLÖCKE",
"mining_recent_payouts": "LETZTE POOL-AUSZAHLUNGEN",
"mining_remove": "Entfernen",
"mining_reset_defaults": "Standardwerte zurücksetzen",
"mining_save_payout_address": "Auszahlungsadresse speichern",
"mining_save_pool_url": "Pool-URL speichern",
"mining_saved_addresses": "Gespeicherte Adressen:",
"mining_saved_pools": "Gespeicherte Pools:",
"mining_shares": "Shares",
"mining_show_chart": "Diagramm",
"mining_show_log": "Protokoll",
"mining_solo": "Solo",
"mining_starting": "Startet...",
"mining_starting_tooltip": "Miner startet...",
"mining_statistics": "Mining-Statistiken",
"mining_stop": "Stopp",
"mining_stop_solo_for_pool": "Solo-Mining stoppen bevor Pool-Mining gestartet wird",
"mining_stop_solo_for_pool_settings": "Solo-Mining stoppen um Pool-Einstellungen zu ändern",
"mining_stopping": "Stoppt...",
"mining_stopping_tooltip": "Miner stoppt...",
"mining_syncing_tooltip": "Blockchain synchronisiert...",
"mining_threads": "Mining-Threads",
"mining_to_save": "zum Speichern",
"mining_today": "Heute",
"mining_uptime": "Laufzeit",
"mining_yesterday": "Gestern",
"network": "Netzwerk",
"network_fee": "NETZWERKGEBÜHR",
"network_hashrate": "Netzwerk-Hashrate",
"new": "+ Neu",
"new_shielded_created": "Neue abgeschirmte Adresse erstellt",
"new_t_address": "Neue T-Adresse",
"new_t_transparent": "Neue t-Adresse (Transparent)",
"new_transparent_created": "Neue transparente Adresse erstellt",
"new_z_address": "Neue Z-Adresse",
"new_z_shielded": "Neue z-Adresse (Abgeschirmt)",
"no_addresses": "Keine Adressen gefunden. Erstellen Sie eine mit den Schaltflächen oben.",
"no_addresses_available": "Keine Adressen verfügbar",
"no_addresses_match": "Keine Adressen passen zum Filter",
"no_addresses_with_balance": "Keine Adressen mit Guthaben",
"no_matching": "Keine passenden Transaktionen",
"no_recent_receives": "Keine kürzlichen Empfänge",
"no_recent_sends": "Keine kürzlichen Sendungen",
"no_transactions": "Keine Transaktionen gefunden",
"node": "KNOTEN",
"node_security": "KNOTEN & SICHERHEIT",
"noise": "Rauschen",
"not_connected": "Nicht mit Daemon verbunden...",
"not_connected_to_daemon": "Nicht mit Daemon verbunden",
"notes": "Notizen",
"notes_optional": "Notizen (optional):",
"output_filename": "Ausgabedateiname:",
"overview": "Übersicht",
"paste": "Einfügen",
"paste_from_clipboard": "Aus Zwischenablage einfügen",
"pay_from": "Zahlen von",
"payment_request": "ZAHLUNGSANFRAGE",
"payment_request_copied": "Zahlungsanfrage kopiert",
"payment_uri_copied": "Zahlungs-URI kopiert",
"peers": "Peers",
"peers_avg_ping": "Durchschn. Ping",
"peers_ban_24h": "Peer 24h sperren",
"peers_ban_score": "Sperr-Score: %d",
"peers_banned": "Gesperrt",
"peers_banned_count": "Gesperrt: %d",
"peers_best_block": "Bester Block",
"peers_blockchain": "BLOCKCHAIN",
"peers_blocks": "Blöcke",
"peers_blocks_left": "%d Blöcke übrig",
"peers_clear_all_bans": "Alle Sperren aufheben",
"peers_click_copy": "Klicken zum Kopieren",
"peers_connected": "Verbunden",
"peers_connected_count": "Verbunden: %d",
"peers_copy_ip": "IP kopieren",
"peers_dir_in": "Ein",
"peers_dir_out": "Aus",
"peers_hash_copied": "Hash kopiert",
"peers_hashrate": "Hashrate",
"peers_in_out": "Ein/Aus",
"peers_longest": "Längste",
"peers_longest_chain": "Längste Chain",
"peers_memory": "Speicher",
"peers_no_banned": "Keine gesperrten Peers",
"peers_no_connected": "Keine verbundenen Peers",
"peers_no_tls": "Kein TLS",
"peers_notarized": "Notarisiert",
"peers_p2p_port": "P2P-Port",
"peers_protocol": "Protokoll",
"peers_received": "Empfangen",
"peers_refresh": "Aktualisieren",
"peers_refresh_tooltip": "Peer-Liste aktualisieren",
"peers_refreshing": "Aktualisiere...",
"peers_sent": "Gesendet",
"peers_tt_id": "ID: %d",
"peers_tt_received": "Empfangen: %s",
"peers_tt_sent": "Gesendet: %s",
"peers_tt_services": "Dienste: %s",
"peers_tt_start_height": "Starthöhe: %d",
"peers_tt_synced": "Synchronisiert H/B: %d/%d",
"peers_tt_tls_cipher": "TLS: %s",
"peers_unban": "Entsperren",
"peers_upper": "PEERS",
"peers_version": "Version",
"pending": "Ausstehend",
"ping": "Ping",
"price_chart": "Preisdiagramm",
"qr_code": "QR-Code",
"qr_failed": "QR-Code konnte nicht generiert werden",
"qr_title": "QR-Code",
"qr_unavailable": "QR nicht verfügbar",
"receive": "Empfangen",
"received": "empfangen",
"received_filter": "Empfangen",
"received_label": "Empfangen",
"received_upper": "EMPFANGEN",
"receiving_addresses": "Ihre Empfangsadressen",
"recent_received": "KÜRZLICH EMPFANGEN",
"recent_sends": "KÜRZLICH GESENDET",
"recipient": "EMPFÄNGER",
"recv_type": "Empf.",
"refresh": "Aktualisieren",
"refresh_now": "Jetzt aktualisieren",
"report_bug": "Fehler melden",
"request_amount": "Betrag (optional):",
"request_copy_uri": "URI kopieren",
"request_description": "Erstellen Sie eine Zahlungsanfrage, die andere scannen oder kopieren können. Der QR-Code enthält Ihre Adresse und optionalen Betrag/Memo.",
"request_label": "Bezeichnung (optional):",
"request_memo": "Memo (optional):",
"request_payment": "Zahlung anfordern",
"request_payment_uri": "Zahlungs-URI:",
"request_receive_address": "Empfangsadresse:",
"request_select_address": "Adresse auswählen...",
"request_shielded_addrs": "-- Abgeschirmte Adressen --",
"request_title": "Zahlung anfordern",
"request_transparent_addrs": "-- Transparente Adressen --",
"request_uri_copied": "Zahlungs-URI in Zwischenablage kopiert",
"rescan": "Neu scannen",
"reset_to_defaults": "Standardwerte zurücksetzen",
"review_send": "Senden prüfen",
"rpc_host": "RPC-Host",
"rpc_pass": "Passwort",
"rpc_port": "Port",
"rpc_user": "Benutzername",
"save": "Speichern",
"save_settings": "Einstellungen speichern",
"save_z_transactions": "Z-Tx in Tx-Liste speichern",
"search_placeholder": "Suchen...",
"security": "SICHERHEIT",
"select_address": "Adresse auswählen...",
"select_receiving_address": "Empfangsadresse auswählen...",
"select_source_address": "Quelladresse auswählen...",
"send": "Senden",
"send_amount": "Betrag",
"send_amount_details": "BETRAGSDETAILS",
"send_amount_upper": "BETRAG",
"send_clear_fields": "Alle Formularfelder leeren?",
"send_copy_error": "Fehler kopieren",
"send_dismiss": "Verwerfen",
"send_error_copied": "Fehler in Zwischenablage kopiert",
"send_error_prefix": "Fehler: %s",
"send_exceeds_available": "Übersteigt verfügbar (%.8f)",
"send_fee": "Gebühr",
"send_fee_high": "Hoch",
"send_fee_low": "Niedrig",
"send_fee_normal": "Normal",
"send_form_restored": "Formular wiederhergestellt",
"send_from_this_address": "Von dieser Adresse senden",
"send_go_to_receive": "Zum Empfangen",
"send_keep": "Behalten",
"send_network_fee": "NETZWERKGEBÜHR",
"send_no_balance": "Kein Guthaben",
"send_no_recent": "Keine kürzlichen Sendungen",
"send_recent_sends": "KÜRZLICH GESENDET",
"send_recipient": "EMPFÄNGER",
"send_select_source": "Quelladresse auswählen...",
"send_sending_from": "SENDEN VON",
"send_submitting": "Transaktion wird übermittelt...",
"send_switch_to_receive": "Wechseln Sie zu Empfangen, um Ihre Adresse zu erhalten und Gelder zu empfangen.",
"send_to": "Senden an",
"send_tooltip_enter_amount": "Geben Sie einen Betrag zum Senden ein",
"send_tooltip_exceeds_balance": "Betrag übersteigt verfügbares Guthaben",
"send_tooltip_in_progress": "Transaktion bereits in Bearbeitung",
"send_tooltip_invalid_address": "Geben Sie eine gültige Empfängeradresse ein",
"send_tooltip_not_connected": "Nicht mit Daemon verbunden",
"send_tooltip_select_source": "Wählen Sie zuerst eine Quelladresse",
"send_tooltip_syncing": "Warten Sie auf die Blockchain-Synchronisierung",
"send_total": "Gesamt",
"send_transaction": "Transaktion senden",
"send_tx_failed": "Transaktion fehlgeschlagen",
"send_tx_sent": "Transaktion gesendet!",
"send_tx_success": "Transaktion erfolgreich gesendet!",
"send_txid_copied": "TxID in Zwischenablage kopiert",
"send_txid_label": "TxID: %s",
"send_valid_shielded": "Gültige abgeschirmte Adresse",
"send_valid_transparent": "Gültige transparente Adresse",
"send_wallet_empty": "Ihre Wallet ist leer",
"send_yes_clear": "Ja, leeren",
"sending": "Transaktion wird gesendet",
"sending_from": "SENDEN VON",
"sent": "gesendet",
"sent_filter": "Gesendet",
"sent_type": "Gesendet",
"sent_upper": "GESENDET",
"settings": "Einstellungen",
"setup_wizard": "Einrichtungsassistent",
"share": "Teilen",
"shield_check_status": "Status prüfen",
"shield_completed": "Vorgang erfolgreich abgeschlossen!",
"shield_description": "Schirmen Sie Ihre Mining-Belohnungen ab, indem Sie Coinbase-Ausgaben von transparenten Adressen an eine abgeschirmte Adresse senden. Dies verbessert die Privatsphäre, indem Ihre Mining-Einkünfte verborgen werden.",
"shield_from_address": "Von Adresse:",
"shield_funds": "Gelder abschirmen",
"shield_in_progress": "Vorgang läuft...",
"shield_max_utxos": "Max. UTXOs pro Vorgang",
"shield_merge_done": "Abschirmung/Zusammenführung abgeschlossen!",
"shield_select_z": "z-Adresse auswählen...",
"shield_started": "Abschirmvorgang gestartet",
"shield_title": "Coinbase-Belohnungen abschirmen",
"shield_to_address": "An Adresse (Abgeschirmt):",
"shield_utxo_limit": "UTXO-Limit:",
"shield_wildcard_hint": "Verwenden Sie '*' um von allen transparenten Adressen abzuschirmen",
"shielded": "Abgeschirmt",
"shielded_to": "ABGESCHIRMT AN",
"shielded_type": "Abgeschirmt",
"show": "Anzeigen",
"show_qr_code": "QR-Code anzeigen",
"showing_transactions": "Zeige %d\xe2\x80\x93%d von %d Transaktionen (gesamt: %zu)",
"simple_background": "Einfacher Hintergrund",
"start_mining": "Mining starten",
"status": "Status",
"stop_external": "Externen Daemon stoppen",
"stop_mining": "Mining stoppen",
"submitting_transaction": "Transaktion wird übermittelt...",
"success": "Erfolg",
"summary": "Zusammenfassung",
"syncing": "Synchronisiere...",
"t_addresses": "T-Adressen",
"test_connection": "Testen",
"theme": "Design",
"theme_effects": "Design-Effekte",
"time_days_ago": "vor %d Tagen",
"time_hours_ago": "vor %d Stunden",
"time_minutes_ago": "vor %d Minuten",
"time_seconds_ago": "vor %d Sekunden",
"to": "An",
"to_upper": "AN",
"tools": "WERKZEUGE",
"total": "Gesamt",
"transaction_id": "TRANSAKTIONS-ID",
"transaction_sent": "Transaktion erfolgreich gesendet",
"transaction_sent_msg": "Transaktion gesendet!",
"transaction_url": "Transaktions-URL",
"transactions": "Transaktionen",
"transactions_upper": "TRANSAKTIONEN",
"transparent": "Transparent",
"tx_confirmations": "%d Bestätigungen",
"tx_details_title": "Transaktionsdetails",
"tx_from_address": "Von Adresse:",
"tx_id_label": "Transaktions-ID:",
"tx_immature": "UNREIF",
"tx_mined": "GEMINED",
"tx_received": "EMPFANGEN",
"tx_sent": "GESENDET",
"tx_to_address": "An Adresse:",
"tx_view_explorer": "Im Explorer anzeigen",
"txs_count": "%d Txs",
"type": "Typ",
"ui_opacity": "UI-Transparenz",
"unban": "Entsperren",
"unconfirmed": "Unbestätigt",
"undo_clear": "Leeren rückgängig",
"unknown": "Unbekannt",
"use_embedded_daemon": "Eingebetteten dragonxd verwenden",
"use_tor": "Tor verwenden",
"validate_btn": "Validieren",
"validate_description": "Geben Sie eine DragonX-Adresse ein, um zu prüfen, ob sie gültig ist und ob sie zu dieser Wallet gehört.",
"validate_invalid": "UNGÜLTIG",
"validate_is_mine": "Diese Wallet besitzt diese Adresse",
"validate_not_mine": "Nicht im Besitz dieser Wallet",
"validate_ownership": "Eigentum:",
"validate_results": "Ergebnisse:",
"validate_shielded_type": "Abgeschirmt (z-Adresse)",
"validate_status": "Status:",
"validate_title": "Adresse validieren",
"validate_transparent_type": "Transparent (t-Adresse)",
"validate_type": "Typ:",
"validate_valid": "GÜLTIG",
"validating": "Validiere...",
"verbose_logging": "Ausführliches Logging",
"version": "Version",
"view": "Ansicht",
"view_details": "Details anzeigen",
"view_on_explorer": "Im Explorer anzeigen",
"waiting_for_daemon": "Warte auf Daemon-Verbindung...",
"wallet": "WALLET",
"wallet_empty": "Ihre Wallet ist leer",
"wallet_empty_hint": "Wechseln Sie zu Empfangen, um Ihre Adresse zu erhalten und Gelder zu empfangen.",
"warning": "Warnung",
"warning_upper": "WARNUNG!",
"website": "Webseite",
"window_opacity": "Fenster-Transparenz",
"yes_clear": "Ja, leeren",
"your_addresses": "Ihre Adressen",
"z_addresses": "Z-Adressen",
}
out = os.path.join(os.path.dirname(__file__), "..", "res", "lang", "de.json")
with open(out, "w", encoding="utf-8") as f:
json.dump(translations, f, indent=4, ensure_ascii=False, sort_keys=True)
print(f"Wrote {len(translations)} German translations to {os.path.abspath(out)}")

View File

@@ -1,665 +0,0 @@
#!/usr/bin/env python3
"""Generate complete Spanish (es.json) translations for ObsidianDragon wallet."""
import json
es = {
# ---- Navigation & Tabs ----
"overview": "Resumen",
"balance": "Saldo",
"send": "Enviar",
"receive": "Recibir",
"transactions": "Transacciones",
"history": "Historial",
"mining": "Minería",
"peers": "Nodos",
"market": "Mercado",
"settings": "Configuración",
"console": "Consola",
"tools": "HERRAMIENTAS",
"advanced": "AVANZADO",
"network": "Red",
# ---- Settings sections ----
"appearance": "APARIENCIA",
"wallet": "CARTERA",
"node_security": "NODO Y SEGURIDAD",
"node": "NODO",
"security": "SEGURIDAD",
"explorer": "EXPLORADOR",
"about": "Acerca de",
"backup_data": "RESPALDO Y DATOS",
"general": "General",
# ---- Settings options ----
"balance_layout": "Diseño de Saldo",
"low_spec_mode": "Modo bajo rendimiento",
"simple_background": "Fondo simple",
"console_scanline": "Líneas de consola",
"theme_effects": "Efectos de tema",
"language": "Idioma",
"save_z_transactions": "Guardar Z-tx en lista",
"allow_custom_fees": "Permitir comisiones personalizadas",
"custom_fees": "Comisiones personalizadas",
"auto_shield": "Auto-proteger minería",
"fetch_prices": "Obtener precios",
"use_tor": "Usar Tor",
"font_scale": "Escala de fuente",
"keep_daemon": "Mantener daemon activo",
"stop_external": "Detener daemon externo",
"mine_when_idle": "Minar en reposo",
"verbose_logging": "Registro detallado",
"acrylic": "Acrílico",
"noise": "Ruido",
"ui_opacity": "Opacidad de UI",
"window_opacity": "Opacidad de ventana",
# ---- Settings buttons ----
"save_settings": "Guardar Configuración",
"reset_to_defaults": "Restablecer Valores",
"report_bug": "Reportar Error",
"website": "Sitio Web",
"setup_wizard": "Asistente de Configuración",
"rescan": "Re-escanear",
"test_connection": "Probar",
# ---- Settings fields ----
"rpc_host": "Host RPC",
"rpc_port": "Puerto",
"rpc_user": "Usuario",
"rpc_pass": "Contraseña",
"transaction_url": "URL de Transacción",
"address_url": "URL de Dirección",
"block_explorer": "Explorador de Bloques",
# ---- Common actions ----
"add": "Agregar",
"edit": "Editar",
"delete": "Eliminar",
"cancel": "Cancelar",
"close": "Cerrar",
"clear": "Limpiar",
"copy": "Copiar",
"paste": "Pegar",
"save": "Guardar",
"refresh": "Actualizar",
"export": "Exportar",
"import": "Importar",
"show": "Mostrar",
"hide": "Ocultar",
"share": "Compartir",
"confirm_and_send": "Confirmar y Enviar",
"confirm_send": "Confirmar Envío",
"confirm_transaction": "Confirmar Transacción",
"review_send": "Revisar Envío",
"copy_address": "Copiar Dirección Completa",
"copy_to_clipboard": "Copiar al Portapapeles",
"paste_from_clipboard": "Pegar del Portapapeles",
"copy_txid": "Copiar TxID",
"copy_uri": "Copiar URI",
"copy_error": "Copiar Error",
"search_placeholder": "Buscar...",
"exit": "Salir",
"help": "Ayuda",
"file": "Archivo",
"display": "Pantalla",
"new": "+ Nuevo",
"dismiss": "Descartar",
"keep": "Mantener",
"yes_clear": "Sí, Limpiar",
"undo_clear": "Deshacer Limpieza",
# ---- Common labels ----
"address": "Dirección",
"address_label": "Dirección:",
"amount": "Cantidad",
"amount_label": "Cantidad:",
"date": "Fecha",
"date_label": "Fecha:",
"fee": "Comisión",
"fee_label": "Comisión:",
"label": "Etiqueta:",
"memo": "Memo (opcional, encriptado)",
"memo_label": "Memo:",
"notes": "Notas",
"notes_optional": "Notas (opcional):",
"total": "Total",
"from": "Desde",
"to_upper": "PARA",
"from_upper": "DESDE",
"max": "Máximo",
"characters": "caracteres",
"ping": "Ping",
"height": "Altura",
"block": "Bloque",
"available": "Disponible",
"unknown": "Desconocido",
"loading": "Cargando...",
"validating": "Validando...",
"warning_upper": "¡ADVERTENCIA!",
"output_filename": "Nombre del archivo:",
"file_save_location": "El archivo se guardará en: ~/.config/ObsidianDragon/",
"light": "Claro",
"dark": "Oscuro",
# ---- Status ----
"connected": "Conectado",
"disconnected": "Desconectado",
"connecting": "Conectando...",
"confirmed": "Confirmada",
"confirmations": "Confirmaciones",
"not_connected_to_daemon": "No conectado al daemon",
"waiting_for_daemon": "Esperando conexión al daemon...",
"blockchain_syncing": "Sincronizando blockchain (%.1f%%)... Los saldos pueden ser inexactos.",
"error": "Error",
"success": "Éxito",
"warning": "Advertencia",
# ---- Time ----
"time_days_ago": "hace %d días",
"time_hours_ago": "hace %d horas",
"time_minutes_ago": "hace %d minutos",
"time_seconds_ago": "hace %d segundos",
# ---- Transaction types/filters ----
"sent_type": "Enviado",
"sent_filter": "Enviado",
"sent_upper": "ENVIADO",
"received_label": "Recibido",
"received_filter": "Recibido",
"received_upper": "RECIBIDO",
"mined_type": "Minado",
"mined_filter": "Minado",
"mined_upper": "MINADO",
"immature_type": "Inmaduro",
"mature": "Maduro",
"recv_type": "Recibido",
"all_filter": "Todos",
"shielded_type": "Protegido",
# ---- Balance / Overview ----
"address_upper": "DIRECCIÓN",
"address_details": "Detalles de Dirección",
"amount_details": "DETALLES DE CANTIDAD",
"transactions_upper": "TRANSACCIONES",
"addresses_appear_here": "Tus direcciones de recepción aparecerán aquí una vez conectado.",
"wallet_empty": "Tu cartera está vacía",
"wallet_empty_hint": "Cambia a Recibir para obtener tu dirección y empezar a recibir fondos.",
"loading_addresses": "Cargando direcciones...",
"no_addresses_match": "No hay direcciones que coincidan con el filtro",
"no_addresses_with_balance": "No hay direcciones con saldo",
"click_copy_address": "Clic para copiar dirección",
"click_copy_uri": "Clic para copiar URI",
"address_copied": "Dirección copiada al portapapeles",
"about_dragonx": "Acerca de DragonX",
"dragonx_green": "DragonX (Verde)",
# ---- Transactions tab ----
"no_transactions": "No se encontraron transacciones",
"no_matching": "No hay transacciones coincidentes",
"showing_transactions": "Mostrando %d\u2013%d de %d transacciones (total: %zu)",
"conf_count": "%d conf",
"confirmations_display": "%d confirmaciones | %s",
"txs_count": "%d txs",
"view_details": "Ver Detalles",
"full_details": "Detalles Completos",
"export_csv": "Exportar CSV",
"transaction_id": "ID DE TRANSACCIÓN",
# ---- Receive tab ----
"select_receiving_address": "Seleccionar dirección de recepción...",
"payment_request": "SOLICITUD DE PAGO",
"recent_received": "RECIBIDOS RECIENTES",
"no_recent_receives": "No hay recepciones recientes",
"qr_unavailable": "QR no disponible",
"clear_request": "Limpiar Solicitud",
"clear_form_confirm": "¿Limpiar todos los campos del formulario?",
"payment_request_copied": "Solicitud de pago copiada",
"payment_uri_copied": "URI de pago copiada",
"failed_create_shielded": "Error al crear dirección protegida",
"failed_create_transparent": "Error al crear dirección transparente",
"new_shielded_created": "Nueva dirección protegida creada",
"new_transparent_created": "Nueva dirección transparente creada",
# ---- Send tab ----
"send_sending_from": "ENVIANDO DESDE",
"send_select_source": "Seleccionar dirección de origen...",
"send_no_balance": "Sin saldo",
"send_recipient": "DESTINATARIO",
"send_amount_upper": "CANTIDAD",
"send_amount": "Cantidad",
"send_amount_details": "DETALLES DE CANTIDAD",
"send_fee": "Comisión",
"send_fee_low": "Baja",
"send_fee_normal": "Normal",
"send_fee_high": "Alta",
"send_network_fee": "COMISIÓN DE RED",
"send_total": "Total",
"send_recent_sends": "ENVÍOS RECIENTES",
"send_no_recent": "No hay envíos recientes",
"send_clear_fields": "¿Limpiar todos los campos del formulario?",
"send_yes_clear": "Sí, Limpiar",
"send_keep": "Mantener",
"send_form_restored": "Formulario restaurado",
"send_valid_shielded": "Dirección protegida válida",
"send_valid_transparent": "Dirección transparente válida",
"send_exceeds_available": "Excede disponible (%.8f)",
"send_submitting": "Enviando transacción...",
"send_tx_sent": "¡Transacción enviada!",
"send_tx_success": "¡Transacción enviada exitosamente!",
"send_tx_failed": "Error en la transacción",
"send_error_prefix": "Error: %s",
"send_error_copied": "Error copiado al portapapeles",
"send_copy_error": "Copiar Error",
"send_dismiss": "Descartar",
"send_txid_copied": "TxID copiado al portapapeles",
"send_txid_label": "TxID: %s",
"send_go_to_receive": "Ir a Recibir",
"send_wallet_empty": "Tu cartera está vacía",
"send_switch_to_receive": "Cambia a Recibir para obtener tu dirección y empezar a recibir fondos.",
"send_tooltip_select_source": "Selecciona una dirección de origen primero",
"send_tooltip_invalid_address": "Ingresa una dirección de destinatario válida",
"send_tooltip_enter_amount": "Ingresa una cantidad a enviar",
"send_tooltip_exceeds_balance": "La cantidad excede el saldo disponible",
"send_tooltip_not_connected": "No conectado al daemon",
"send_tooltip_syncing": "Espera a que se sincronice el blockchain",
"send_tooltip_in_progress": "Transacción ya en progreso",
"sending_from": "ENVIANDO DESDE",
"select_source_address": "Seleccionar dirección de origen...",
"recipient": "DESTINATARIO",
"memo_optional": "MEMO (OPCIONAL)",
"memo_upper": "MEMO",
"network_fee": "COMISIÓN DE RED",
"fee_low": "Baja",
"fee_normal": "Normal",
"fee_high": "Alta",
"recent_sends": "ENVÍOS RECIENTES",
"no_recent_sends": "No hay envíos recientes",
"shielded_to": "PROTEGIDA PARA",
"submitting_transaction": "Enviando transacción...",
"transaction_sent_msg": "¡Transacción enviada!",
"amount_exceeds_balance": "La cantidad excede el saldo",
# ---- Mining tab ----
"mining_solo": "Solo",
"mining_pool": "Pool",
"mining_pool_url": "URL del Pool",
"mining_pool_hashrate": "Hashrate del Pool",
"mining_local_hashrate": "Hashrate Local",
"mining_payout_address": "Dirección de Pago",
"mining_payout_tooltip": "Dirección para recibir recompensas de minería",
"mining_mine": "Minar",
"mining_stop": "Detener",
"mining_starting": "Iniciando...",
"mining_stopping": "Deteniendo...",
"mining_active": "Activo",
"mining_connected": "Conectado",
"mining_connecting": "Conectando...",
"mining_network": "Red",
"mining_shares": "Shares",
"mining_uptime": "Tiempo activo",
"mining_mining_addr": "Dir. Minería",
"mining_est_block": "Bloque Est.",
"mining_est_daily": "Diario Est.",
"mining_today": "Hoy",
"mining_yesterday": "Ayer",
"mining_all_time": "Todo el Tiempo",
"mining_recent_blocks": "BLOQUES RECIENTES",
"mining_recent_payouts": "PAGOS DE POOL RECIENTES",
"mining_no_blocks_yet": "Aún no se han encontrado bloques",
"mining_no_payouts_yet": "Aún no hay pagos del pool",
"mining_show_chart": "Gráfico",
"mining_show_log": "Registro",
"mining_chart_now": "Ahora",
"mining_chart_start": "Inicio",
"mining_chart_1m_ago": "hace 1m",
"mining_chart_5m_ago": "hace 5m",
"mining_save_pool_url": "Guardar URL del pool",
"mining_save_payout_address": "Guardar dirección de pago",
"mining_saved_pools": "Pools Guardados:",
"mining_saved_addresses": "Direcciones Guardadas:",
"mining_no_saved_pools": "No hay pools guardados",
"mining_no_saved_addresses": "No hay direcciones guardadas",
"mining_already_saved": "URL del pool ya guardada",
"mining_remove": "Eliminar",
"mining_reset_defaults": "Restablecer Valores",
"mining_click": "Clic",
"mining_to_save": "para guardar",
"mining_click_copy_address": "Clic para copiar dirección",
"mining_click_copy_block": "Clic para copiar hash de bloque",
"mining_click_copy_difficulty": "Clic para copiar dificultad",
"mining_address_copied": "Dirección de minería copiada",
"mining_block_copied": "Hash de bloque copiado",
"mining_difficulty_copied": "Dificultad copiada",
"mining_open_in_explorer": "Abrir en explorador",
"mining_starting_tooltip": "El minero está iniciando...",
"mining_stopping_tooltip": "El minero está deteniéndose...",
"mining_syncing_tooltip": "El blockchain está sincronizando...",
"mining_idle_on_tooltip": "Desactivar minería en reposo",
"mining_idle_off_tooltip": "Activar minería en reposo",
"mining_stop_solo_for_pool": "Detener minería solo antes de iniciar minería en pool",
"mining_stop_solo_for_pool_settings": "Detener minería solo para cambiar configuración del pool",
"mining_filter_all": "Todos",
"mining_filter_tip_all": "Mostrar todas las ganancias",
"mining_filter_tip_solo": "Mostrar solo ganancias solo",
"mining_filter_tip_pool": "Mostrar solo ganancias del pool",
"local_hashrate": "Tasa Hash Local",
"est_time_to_block": "Tiempo Est. al Bloque",
"difficulty": "Dificultad",
"current_price": "Precio Actual",
"market_cap": "Cap. de Mercado",
# ---- Peers tab ----
"peers_blockchain": "BLOCKCHAIN",
"peers_blocks": "Bloques",
"peers_connected": "Conectados",
"peers_connected_count": "Conectados: %d",
"peers_banned": "Bloqueados",
"peers_banned_count": "Bloqueados: %d",
"peers_upper": "NODOS",
"peers_avg_ping": "Ping Prom.",
"peers_best_block": "Mejor Bloque",
"peers_hashrate": "Hashrate",
"peers_longest": "Más Larga",
"peers_longest_chain": "Cadena Más Larga",
"peers_memory": "Memoria",
"peers_notarized": "Notarizado",
"peers_p2p_port": "Puerto P2P",
"peers_protocol": "Protocolo",
"peers_version": "Versión",
"peers_in_out": "Ent/Sal",
"peers_dir_in": "Ent",
"peers_dir_out": "Sal",
"peers_received": "Recibido",
"peers_sent": "Enviado",
"peers_refresh": "Actualizar",
"peers_refresh_tooltip": "Actualizar lista de nodos",
"peers_refreshing": "Actualizando...",
"peers_no_connected": "No hay nodos conectados",
"peers_no_banned": "No hay nodos bloqueados",
"peers_ban_24h": "Bloquear Nodo 24h",
"peers_unban": "Desbloquear",
"peers_clear_all_bans": "Limpiar Todos los Bloqueos",
"peers_copy_ip": "Copiar IP",
"peers_click_copy": "Clic para copiar",
"peers_hash_copied": "Hash copiado",
"peers_no_tls": "Sin TLS",
"peers_blocks_left": "%d bloques restantes",
"peers_ban_score": "Puntuación: %d",
"peers_tt_id": "ID: %d",
"peers_tt_sent": "Enviado: %s",
"peers_tt_received": "Recibido: %s",
"peers_tt_services": "Servicios: %s",
"peers_tt_start_height": "Altura Inicial: %d",
"peers_tt_synced": "Sinc H/B: %d/%d",
"peers_tt_tls_cipher": "TLS: %s",
"connected_peers": "Nodos Conectados",
"banned_peers": "Nodos Bloqueados",
"ban": "Bloquear",
"clear_all_bans": "Limpiar Todos los Bloqueos",
"ip_address": "Dirección IP",
# ---- Market tab ----
"market_btc_price": "PRECIO BTC",
"market_24h_volume": "VOLUMEN 24H",
"market_portfolio": "PORTAFOLIO",
"market_pct_shielded": "%.0f%% Protegido",
"market_attribution": "Datos de precios de NonKYC",
"market_no_price": "Sin datos de precio",
"market_no_history": "No hay historial de precios disponible",
"market_price_unavailable": "Datos de precio no disponibles",
"market_refresh_price": "Actualizar datos de precio",
"market_trade_on": "Operar en %s",
"market_now": "Ahora",
"market_6h": "6h",
"market_12h": "12h",
"market_18h": "18h",
"market_24h": "24h",
"24h_change": "Cambio 24h",
"24h_volume": "Volumen 24h",
# ---- Console tab ----
"console_welcome": "Bienvenido a la Consola de ObsidianDragon",
"console_type_help": "Escribe 'help' para ver los comandos disponibles",
"console_available_commands": "Comandos disponibles:",
"console_common_rpc": "Comandos RPC comunes:",
"console_rpc_reference": "Referencia de Comandos RPC",
"console_auto_scroll": "Auto-desplazamiento",
"console_clear": "Limpiar",
"console_clear_console": "Limpiar Consola",
"console_cleared": "Consola limpiada",
"console_commands": "Comandos",
"console_completions": "Completaciones:",
"console_tab_completion": "Tab para completar",
"console_connected": "Conectado al daemon",
"console_disconnected": "Desconectado del daemon",
"console_not_connected": "Error: No conectado al daemon",
"console_no_daemon": "Sin daemon",
"console_daemon": "Daemon",
"console_daemon_error": "¡Error del daemon!",
"console_daemon_started": "Daemon iniciado",
"console_daemon_stopped": "Daemon detenido",
"console_errors": "Errores",
"console_filter_hint": "Filtrar salida...",
"console_search_commands": "Buscar comandos...",
"console_copy_all": "Copiar Todo",
"console_copy_selected": "Copiar",
"console_select_all": "Seleccionar Todo",
"console_zoom_in": "Acercar",
"console_zoom_out": "Alejar",
"console_show_daemon_output": "Mostrar salida del daemon",
"console_show_errors_only": "Mostrar solo errores",
"console_show_rpc_ref": "Mostrar referencia de comandos RPC",
"console_capturing_output": "Capturando salida del daemon...",
"console_starting_node": "Iniciando nodo...",
"console_line_count": "%zu líneas",
"console_new_lines": "%d nuevas líneas",
"console_showing_lines": "Mostrando %zu de %zu líneas",
"console_click_commands": "Clic en los comandos de arriba para insertarlos",
"console_click_insert": "Clic para insertar",
"console_click_insert_params": "Clic para insertar con parámetros",
"console_close": "Cerrar",
"console_status_running": "Ejecutando",
"console_status_stopped": "Detenido",
"console_status_starting": "Iniciando",
"console_status_stopping": "Deteniendo",
"console_status_error": "Error",
"console_status_unknown": "Desconocido",
"console_help_help": " help - Mostrar este mensaje de ayuda",
"console_help_getinfo": " getinfo - Mostrar información del nodo",
"console_help_getblockcount": " getblockcount - Mostrar altura actual del bloque",
"console_help_getbalance": " getbalance - Mostrar saldo transparente",
"console_help_gettotalbalance": " gettotalbalance - Mostrar saldo total",
"console_help_getmininginfo": " getmininginfo - Mostrar estado de minería",
"console_help_getpeerinfo": " getpeerinfo - Mostrar nodos conectados",
"console_help_setgenerate": " setgenerate - Controlar minería",
"console_help_stop": " stop - Detener el daemon",
"console_help_clear": " clear - Limpiar la consola",
# ---- About dialog ----
"about_title": "Acerca de ObsidianDragon",
"about_edition": "Edición ImGui",
"about_version": "Versión:",
"about_imgui": "ImGui:",
"about_build_date": "Fecha de Compilación:",
"about_build_type": "Tipo de Compilación:",
"about_debug": "Depuración",
"about_release": "Producción",
"about_daemon": "Daemon:",
"about_chain": "Cadena:",
"about_block_height": "Altura de Bloque:",
"about_connections": "Conexiones:",
"about_peers_count": "%zu nodos",
"about_credits": "Créditos",
"about_license": "Licencia",
"about_license_text": "Este software se distribuye bajo la Licencia Pública General de GNU v3 (GPLv3). Usted es libre de usar, modificar y distribuir este software bajo los términos de la licencia.",
"about_website": "Sitio Web",
"about_github": "GitHub",
"about_block_explorer": "Explorador de Bloques",
# ---- Address Book dialog ----
"address_book_title": "Libreta de Direcciones",
"address_book_add_new": "Agregar Nueva",
"address_book_add": "Agregar Dirección",
"address_book_edit": "Editar Dirección",
"address_book_empty": "No hay direcciones guardadas. Haz clic en 'Agregar Nueva' para añadir una.",
"address_book_count": "%zu direcciones guardadas",
"address_book_deleted": "Entrada eliminada",
"address_book_added": "Dirección agregada a la libreta",
"address_book_exists": "La dirección ya existe en la libreta",
"address_book_updated": "Dirección actualizada",
"address_book_update_failed": "Error al actualizar - la dirección puede estar duplicada",
# ---- Backup dialog ----
"backup_title": "Respaldar Cartera",
"backup_description": "Crea un respaldo de tu archivo wallet.dat. Este archivo contiene todas tus claves privadas e historial de transacciones. Guarda el respaldo en un lugar seguro.",
"backup_destination": "Destino del respaldo:",
"backup_wallet_not_found": "Advertencia: wallet.dat no encontrado en la ubicación esperada",
"backup_create": "Crear Respaldo",
"backup_created": "Respaldo de cartera creado",
"backup_backing_up": "Respaldando...",
"backup_tips": "Consejos:",
"backup_tip_external": "Guarda respaldos en unidades externas o almacenamiento en la nube",
"backup_tip_multiple": "Crea múltiples respaldos en diferentes ubicaciones",
"backup_tip_test": "Prueba restaurar desde el respaldo periódicamente",
"backup_wallet": "Respaldar Cartera...",
# ---- Block Info dialog ----
"block_info_title": "Información del Bloque",
"block_height": "Altura del Bloque:",
"block_get_info": "Obtener Info del Bloque",
"block_hash": "Hash del Bloque:",
"block_timestamp": "Fecha y Hora:",
"block_transactions": "Transacciones:",
"block_size": "Tamaño:",
"block_bits": "Bits:",
"block_merkle_root": "Raíz Merkle:",
"block_previous": "Bloque Anterior:",
"block_next": "Bloque Siguiente:",
"block_click_prev": "Clic para ver bloque anterior",
"block_click_next": "Clic para ver bloque siguiente",
"block_nav_prev": "<< Anterior",
"block_nav_next": "Siguiente >>",
# ---- Export Keys dialog ----
"export_keys_title": "Exportar Todas las Claves Privadas",
"export_keys_danger": "PELIGRO: ¡Esto exportará TODAS las claves privadas de tu cartera! Cualquiera con acceso a este archivo puede robar tus fondos. Guárdalo de forma segura y elimínalo después de usar.",
"export_keys_options": "Opciones de exportación:",
"export_keys_include_z": "Incluir direcciones Z (protegidas)",
"export_keys_include_t": "Incluir direcciones T (transparentes)",
"export_keys_btn": "Exportar Claves",
"export_keys_success": "Claves exportadas exitosamente",
"export_private_key": "Exportar Clave Privada",
"export_viewing_key": "Exportar Clave de Vista",
# ---- Export Transactions dialog ----
"export_tx_title": "Exportar Transacciones a CSV",
"export_tx_count": "Exportar %zu transacciones a archivo CSV.",
"export_tx_none": "No hay transacciones para exportar",
"export_tx_file_fail": "Error al crear archivo CSV",
"export_tx_success": "Transacciones exportadas exitosamente",
# ---- Import Key dialog ----
"import_key_title": "Importar Clave Privada",
"import_key_warning": "Advertencia: ¡Nunca compartas tus claves privadas! Importar claves de fuentes no confiables puede comprometer tu cartera.",
"import_key_label": "Clave(s) Privada(s):",
"import_key_tooltip": "Ingresa una o más claves privadas, una por línea.\nSoporta claves de direcciones z y t.\nLas líneas que empiezan con # se tratan como comentarios.",
"import_key_btn": "Importar Clave(s)",
"import_key_no_valid": "No se encontraron claves válidas en la entrada",
"import_key_success": "Claves importadas exitosamente",
"import_key_rescan": "Re-escanear blockchain después de importar",
"import_key_start_height": "Altura inicial:",
"import_key_full_rescan": "(0 = re-escaneo completo)",
"import_key_formats": "Formatos de clave soportados:",
"import_key_z_format": "Claves de gasto de direcciones Z (secret-extended-key-...)",
"import_key_t_format": "Claves privadas WIF de direcciones T",
"import_private_key": "Importar Clave Privada...",
"invalid_address": "Formato de dirección inválido",
# ---- Key Export dialog ----
"key_export_private_key": "Clave Privada:",
"key_export_viewing_key": "Clave de Vista:",
"key_export_private_warning": "¡Mantén esta clave en SECRETO! Cualquiera con esta clave puede gastar tus fondos. Nunca la compartas en línea ni con personas no confiables.",
"key_export_viewing_warning": "Esta clave de vista permite a otros ver tus transacciones entrantes y saldo, pero NO gastar tus fondos. Comparte solo con personas de confianza.",
"key_export_fetching": "Obteniendo clave de la cartera...",
"key_export_reveal": "Revelar Clave",
# ---- QR dialog ----
"qr_title": "Código QR",
"qr_failed": "Error al generar código QR",
# ---- Request Payment dialog ----
"request_title": "Solicitar Pago",
"request_description": "Genera una solicitud de pago que otros pueden escanear o copiar. El código QR contiene tu dirección y cantidad/memo opcionales.",
"request_receive_address": "Dirección de Recepción:",
"request_select_address": "Seleccionar dirección...",
"request_shielded_addrs": "-- Direcciones Protegidas --",
"request_transparent_addrs": "-- Direcciones Transparentes --",
"request_amount": "Cantidad (opcional):",
"request_label": "Etiqueta (opcional):",
"request_memo": "Memo (opcional):",
"request_payment_uri": "URI de Pago:",
"request_copy_uri": "Copiar URI",
"request_uri_copied": "URI de pago copiada al portapapeles",
# ---- Shield dialog ----
"shield_title": "Proteger Recompensas de Coinbase",
"shield_description": "Protege tus recompensas de minería enviando salidas coinbase de direcciones transparentes a una dirección protegida. Esto mejora la privacidad ocultando tus ingresos de minería.",
"shield_from_address": "Dirección de Origen:",
"shield_wildcard_hint": "Usa '*' para proteger desde todas las direcciones transparentes",
"shield_to_address": "Dirección Destino (Protegida):",
"shield_select_z": "Seleccionar dirección z...",
"shield_utxo_limit": "Límite UTXO:",
"shield_max_utxos": "UTXOs máximos por operación",
"shield_funds": "Proteger Fondos",
"shield_started": "Operación de protección iniciada",
"shield_check_status": "Verificar Estado",
"shield_completed": "¡Operación completada exitosamente!",
"shield_merge_done": "¡Protección/fusión completada!",
"shield_in_progress": "Operación en progreso...",
"merge_title": "Fusionar a Dirección",
"merge_description": "Fusiona múltiples UTXOs en una sola dirección protegida. Esto puede ayudar a reducir el tamaño de la cartera y mejorar la privacidad.",
"merge_funds": "Fusionar Fondos",
"merge_started": "Operación de fusión iniciada",
# ---- Transaction Details dialog ----
"tx_details_title": "Detalles de Transacción",
"tx_received": "RECIBIDO",
"tx_sent": "ENVIADO",
"tx_mined": "MINADO",
"tx_immature": "INMADURO",
"tx_confirmations": "%d confirmaciones",
"tx_id_label": "ID de Transacción:",
"tx_to_address": "Dirección Destino:",
"tx_from_address": "Dirección Origen:",
"tx_view_explorer": "Ver en Explorador",
"pending": "Pendiente",
# ---- Validate Address dialog ----
"validate_title": "Validar Dirección",
"validate_description": "Ingresa una dirección DragonX para verificar si es válida y si pertenece a esta cartera.",
"validate_btn": "Validar",
"validate_results": "Resultados:",
"validate_status": "Estado:",
"validate_valid": "VÁLIDA",
"validate_invalid": "INVÁLIDA",
"validate_type": "Tipo:",
"validate_ownership": "Propiedad:",
"validate_is_mine": "Esta cartera es dueña de esta dirección",
"validate_not_mine": "No es propiedad de esta cartera",
"validate_shielded_type": "Protegida (dirección z)",
"validate_transparent_type": "Transparente (dirección t)",
# ---- Misc ----
"transaction_sent": "Transacción enviada exitosamente",
}
# Load existing to preserve anything we might have missed
import os
existing_path = os.path.join(os.path.dirname(__file__), '..', 'res', 'lang', 'es.json')
out_path = existing_path
with open(out_path, 'w', encoding='utf-8') as f:
json.dump(dict(sorted(es.items())), f, indent=4, ensure_ascii=False)
f.write('\n')
print(f"Wrote {len(es)} Spanish translations to {out_path}")

View File

@@ -1,646 +0,0 @@
#!/usr/bin/env python3
"""Generate French (fr) translations for ObsidianDragon wallet."""
import json, os
translations = {
"24h_change": "Variation 24h",
"24h_volume": "Volume 24h",
"about": "À propos",
"about_block_explorer": "Explorateur de blocs",
"about_block_height": "Hauteur de bloc :",
"about_build_date": "Date de compilation :",
"about_build_type": "Type de build :",
"about_chain": "Chaîne :",
"about_connections": "Connexions :",
"about_credits": "Crédits",
"about_daemon": "Daemon :",
"about_debug": "Débogage",
"about_dragonx": "À propos d'ObsidianDragon",
"about_edition": "Édition ImGui",
"about_github": "GitHub",
"about_imgui": "ImGui :",
"about_license": "Licence",
"about_license_text": "Ce logiciel est publié sous la licence publique générale GNU v3 (GPLv3). Vous êtes libre d'utiliser, de modifier et de distribuer ce logiciel selon les termes de la licence.",
"about_peers_count": "%zu pairs",
"about_release": "Version",
"about_title": "À propos d'ObsidianDragon",
"about_version": "Version :",
"about_website": "Site web",
"acrylic": "Acrylique",
"add": "Ajouter",
"address": "Adresse",
"address_book_add": "Ajouter une adresse",
"address_book_add_new": "Ajouter",
"address_book_added": "Adresse ajoutée au carnet",
"address_book_count": "%zu adresses enregistrées",
"address_book_deleted": "Entrée supprimée",
"address_book_edit": "Modifier l'adresse",
"address_book_empty": "Aucune adresse enregistrée. Cliquez sur 'Ajouter' pour en créer une.",
"address_book_exists": "L'adresse existe déjà dans le carnet",
"address_book_title": "Carnet d'adresses",
"address_book_update_failed": "Échec de la mise à jour - l'adresse est peut-être en double",
"address_book_updated": "Adresse mise à jour",
"address_copied": "Adresse copiée dans le presse-papiers",
"address_details": "Détails de l'adresse",
"address_label": "Adresse :",
"address_upper": "ADRESSE",
"address_url": "URL de l'adresse",
"addresses_appear_here": "Vos adresses de réception apparaîtront ici une fois connecté.",
"advanced": "AVANCÉ",
"all_filter": "Tout",
"allow_custom_fees": "Autoriser les frais personnalisés",
"amount": "Montant",
"amount_details": "DÉTAILS DU MONTANT",
"amount_exceeds_balance": "Le montant dépasse le solde",
"amount_label": "Montant :",
"appearance": "APPARENCE",
"auto_shield": "Auto-blindage du minage",
"available": "Disponible",
"backup_backing_up": "Sauvegarde en cours...",
"backup_create": "Créer une sauvegarde",
"backup_created": "Sauvegarde du portefeuille créée",
"backup_data": "SAUVEGARDE & DONNÉES",
"backup_description": "Créez une sauvegarde de votre fichier wallet.dat. Ce fichier contient toutes vos clés privées et l'historique des transactions. Conservez la sauvegarde dans un endroit sûr.",
"backup_destination": "Destination de sauvegarde :",
"backup_tip_external": "Stockez les sauvegardes sur des disques externes ou un stockage cloud",
"backup_tip_multiple": "Créez plusieurs sauvegardes à différents endroits",
"backup_tip_test": "Testez périodiquement la restauration à partir de la sauvegarde",
"backup_tips": "Conseils :",
"backup_title": "Sauvegarder le portefeuille",
"backup_wallet": "Sauvegarder le portefeuille...",
"backup_wallet_not_found": "Attention : wallet.dat introuvable à l'emplacement prévu",
"balance": "Solde",
"balance_layout": "Disposition du solde",
"ban": "Bannir",
"banned_peers": "Pairs bannis",
"block": "Bloc",
"block_bits": "Bits :",
"block_click_next": "Cliquez pour voir le bloc suivant",
"block_click_prev": "Cliquez pour voir le bloc précédent",
"block_explorer": "Explorateur de blocs",
"block_get_info": "Obtenir les infos du bloc",
"block_hash": "Hash du bloc :",
"block_height": "Hauteur du bloc :",
"block_info_title": "Informations sur le bloc",
"block_merkle_root": "Racine de Merkle :",
"block_nav_next": "Suivant >>",
"block_nav_prev": "<< Précédent",
"block_next": "Bloc suivant :",
"block_previous": "Bloc précédent :",
"block_size": "Taille :",
"block_timestamp": "Horodatage :",
"block_transactions": "Transactions :",
"blockchain_syncing": "Synchronisation de la blockchain (%.1f%%)... Les soldes peuvent être inexacts.",
"cancel": "Annuler",
"characters": "caractères",
"clear": "Effacer",
"clear_all_bans": "Lever tous les bannissements",
"clear_form_confirm": "Effacer tous les champs du formulaire ?",
"clear_request": "Effacer la demande",
"click_copy_address": "Cliquez pour copier l'adresse",
"click_copy_uri": "Cliquez pour copier l'URI",
"close": "Fermer",
"conf_count": "%d conf.",
"confirm_and_send": "Confirmer & Envoyer",
"confirm_send": "Confirmer l'envoi",
"confirm_transaction": "Confirmer la transaction",
"confirmations": "Confirmations",
"confirmations_display": "%d confirmations | %s",
"confirmed": "Confirmé",
"connected": "Connecté",
"connected_peers": "Pairs connectés",
"connecting": "Connexion...",
"console": "Console",
"console_auto_scroll": "Défilement auto",
"console_available_commands": "Commandes disponibles :",
"console_capturing_output": "Capture de la sortie du daemon...",
"console_clear": "Effacer",
"console_clear_console": "Effacer la console",
"console_cleared": "Console effacée",
"console_click_commands": "Cliquez sur les commandes ci-dessus pour les insérer",
"console_click_insert": "Cliquez pour insérer",
"console_click_insert_params": "Cliquez pour insérer avec paramètres",
"console_close": "Fermer",
"console_commands": "Commandes",
"console_common_rpc": "Commandes RPC courantes :",
"console_completions": "Complétions :",
"console_connected": "Connecté au daemon",
"console_copy_all": "Tout copier",
"console_copy_selected": "Copier",
"console_daemon": "Daemon",
"console_daemon_error": "Erreur du daemon !",
"console_daemon_started": "Daemon démarré",
"console_daemon_stopped": "Daemon arrêté",
"console_disconnected": "Déconnecté du daemon",
"console_errors": "Erreurs",
"console_filter_hint": "Filtrer la sortie...",
"console_help_clear": " clear - Effacer la console",
"console_help_getbalance": " getbalance - Afficher le solde transparent",
"console_help_getblockcount": " getblockcount - Afficher la hauteur de bloc actuelle",
"console_help_getinfo": " getinfo - Afficher les infos du nœud",
"console_help_getmininginfo": " getmininginfo - Afficher le statut du minage",
"console_help_getpeerinfo": " getpeerinfo - Afficher les pairs connectés",
"console_help_gettotalbalance": " gettotalbalance - Afficher le solde total",
"console_help_help": " help - Afficher ce message d'aide",
"console_help_setgenerate": " setgenerate - Contrôler le minage",
"console_help_stop": " stop - Arrêter le daemon",
"console_line_count": "%zu lignes",
"console_new_lines": "%d nouvelles lignes",
"console_no_daemon": "Pas de daemon",
"console_not_connected": "Erreur : Non connecté au daemon",
"console_rpc_reference": "Référence des commandes RPC",
"console_scanline": "Scanline de la console",
"console_search_commands": "Rechercher des commandes...",
"console_select_all": "Tout sélectionner",
"console_show_daemon_output": "Afficher la sortie du daemon",
"console_show_errors_only": "Afficher uniquement les erreurs",
"console_show_rpc_ref": "Afficher la référence des commandes RPC",
"console_showing_lines": "Affichage de %zu sur %zu lignes",
"console_starting_node": "Démarrage du nœud...",
"console_status_error": "Erreur",
"console_status_running": "En cours",
"console_status_starting": "Démarrage",
"console_status_stopped": "Arrêté",
"console_status_stopping": "Arrêt",
"console_status_unknown": "Inconnu",
"console_tab_completion": "Tab pour compléter",
"console_type_help": "Tapez 'help' pour les commandes disponibles",
"console_welcome": "Bienvenue dans la console ObsidianDragon",
"console_zoom_in": "Agrandir",
"console_zoom_out": "Réduire",
"copy": "Copier",
"copy_address": "Copier l'adresse complète",
"copy_error": "Copier l'erreur",
"copy_to_clipboard": "Copier dans le presse-papiers",
"copy_txid": "Copier le TxID",
"copy_uri": "Copier l'URI",
"current_price": "Prix actuel",
"custom_fees": "Frais personnalisés",
"dark": "Sombre",
"date": "Date",
"date_label": "Date :",
"delete": "Supprimer",
"difficulty": "Difficulté",
"disconnected": "Déconnecté",
"dismiss": "Ignorer",
"display": "Affichage",
"dragonx_green": "DragonX (Vert)",
"edit": "Modifier",
"error": "Erreur",
"est_time_to_block": "Temps est. par bloc",
"exit": "Quitter",
"explorer": "EXPLORATEUR",
"export": "Exporter",
"export_csv": "Exporter en CSV",
"export_keys_btn": "Exporter les clés",
"export_keys_danger": "DANGER : Ceci exportera TOUTES les clés privées de votre portefeuille ! Toute personne ayant accès à ce fichier peut voler vos fonds. Conservez-le en sécurité et supprimez-le après utilisation.",
"export_keys_include_t": "Inclure les adresses T (transparentes)",
"export_keys_include_z": "Inclure les adresses Z (blindées)",
"export_keys_options": "Options d'exportation :",
"export_keys_success": "Clés exportées avec succès",
"export_keys_title": "Exporter toutes les clés privées",
"export_private_key": "Exporter la clé privée",
"export_tx_count": "Exporter %zu transactions en fichier CSV.",
"export_tx_file_fail": "Impossible de créer le fichier CSV",
"export_tx_none": "Aucune transaction à exporter",
"export_tx_success": "Transactions exportées avec succès",
"export_tx_title": "Exporter les transactions en CSV",
"export_viewing_key": "Exporter la clé de visualisation",
"failed_create_shielded": "Échec de la création de l'adresse blindée",
"failed_create_transparent": "Échec de la création de l'adresse transparente",
"fee": "Frais",
"fee_high": "Élevés",
"fee_label": "Frais :",
"fee_low": "Faibles",
"fee_normal": "Normal",
"fetch_prices": "Récupérer les prix",
"file": "Fichier",
"file_save_location": "Le fichier sera enregistré dans : ~/.config/ObsidianDragon/",
"font_scale": "Taille de police",
"from": "De",
"from_upper": "DE",
"full_details": "Tous les détails",
"general": "Général",
"go_to_receive": "Aller à Recevoir",
"height": "Hauteur",
"help": "Aide",
"hide": "Masquer",
"history": "Historique",
"immature_type": "Immature",
"import": "Importer",
"import_key_btn": "Importer clé(s)",
"import_key_formats": "Formats de clés pris en charge :",
"import_key_full_rescan": "(0 = rescan complet)",
"import_key_label": "Clé(s) privée(s) :",
"import_key_no_valid": "Aucune clé valide trouvée dans l'entrée",
"import_key_rescan": "Re-scanner la blockchain après l'importation",
"import_key_start_height": "Hauteur de départ :",
"import_key_success": "Clés importées avec succès",
"import_key_t_format": "Clés privées WIF d'adresses T",
"import_key_title": "Importer une clé privée",
"import_key_tooltip": "Entrez une ou plusieurs clés privées, une par ligne.\nPrend en charge les clés z-adresse et t-adresse.\nLes lignes commençant par # sont traitées comme des commentaires.",
"import_key_warning": "Attention : Ne partagez jamais vos clés privées ! L'importation de clés provenant de sources non fiables peut compromettre votre portefeuille.",
"import_key_z_format": "Clés de dépenses z-adresse (secret-extended-key-...)",
"import_private_key": "Importer une clé privée...",
"invalid_address": "Format d'adresse invalide",
"ip_address": "Adresse IP",
"keep": "Conserver",
"keep_daemon": "Garder le daemon en marche",
"key_export_fetching": "Récupération de la clé depuis le portefeuille...",
"key_export_private_key": "Clé privée :",
"key_export_private_warning": "Gardez cette clé SECRÈTE ! Toute personne possédant cette clé peut dépenser vos fonds. Ne la partagez jamais en ligne ou avec des tiers non fiables.",
"key_export_reveal": "Révéler la clé",
"key_export_viewing_key": "Clé de visualisation :",
"key_export_viewing_warning": "Cette clé de visualisation permet à d'autres de voir vos transactions entrantes et votre solde, mais PAS de dépenser vos fonds. Ne la partagez qu'avec des personnes de confiance.",
"label": "Libellé :",
"language": "Langue",
"light": "Clair",
"loading": "Chargement...",
"loading_addresses": "Chargement des adresses...",
"local_hashrate": "Hashrate local",
"low_spec_mode": "Mode économie",
"market": "Marché",
"market_12h": "12h",
"market_18h": "18h",
"market_24h": "24h",
"market_24h_volume": "VOLUME 24H",
"market_6h": "6h",
"market_attribution": "Données de prix de NonKYC",
"market_btc_price": "PRIX BTC",
"market_cap": "Capitalisation",
"market_no_history": "Aucun historique de prix disponible",
"market_no_price": "Pas de données de prix",
"market_now": "Maintenant",
"market_pct_shielded": "%.0f%% Blindé",
"market_portfolio": "PORTEFEUILLE",
"market_price_unavailable": "Données de prix indisponibles",
"market_refresh_price": "Actualiser les données de prix",
"market_trade_on": "Échanger sur %s",
"mature": "Mature",
"max": "Max",
"memo": "Mémo (optionnel, chiffré)",
"memo_label": "Mémo :",
"memo_optional": "MÉMO (OPTIONNEL)",
"memo_upper": "MÉMO",
"memo_z_only": "Note : Les mémos ne sont disponibles que lors de l'envoi vers des adresses blindées (z)",
"merge_description": "Fusionnez plusieurs UTXOs en une seule adresse blindée. Cela peut réduire la taille du portefeuille et améliorer la confidentialité.",
"merge_funds": "Fusionner les fonds",
"merge_started": "Opération de fusion démarrée",
"merge_title": "Fusionner vers une adresse",
"mine_when_idle": "Miner au repos",
"mined": "miné",
"mined_filter": "Miné",
"mined_type": "Miné",
"mined_upper": "MINÉ",
"miner_fee": "Frais de mineur",
"mining": "Minage",
"mining_active": "Actif",
"mining_address_copied": "Adresse de minage copiée",
"mining_all_time": "Tout le temps",
"mining_already_saved": "URL du pool déjà enregistrée",
"mining_block_copied": "Hash du bloc copié",
"mining_chart_1m_ago": "il y a 1m",
"mining_chart_5m_ago": "il y a 5m",
"mining_chart_now": "Maintenant",
"mining_chart_start": "Début",
"mining_click": "Cliquer",
"mining_click_copy_address": "Cliquez pour copier l'adresse",
"mining_click_copy_block": "Cliquez pour copier le hash du bloc",
"mining_click_copy_difficulty": "Cliquez pour copier la difficulté",
"mining_connected": "Connecté",
"mining_connecting": "Connexion...",
"mining_control": "Contrôle du minage",
"mining_difficulty_copied": "Difficulté copiée",
"mining_est_block": "Bloc est.",
"mining_est_daily": "Est. quotidien",
"mining_filter_all": "Tout",
"mining_filter_tip_all": "Afficher tous les gains",
"mining_filter_tip_pool": "Afficher uniquement les gains du pool",
"mining_filter_tip_solo": "Afficher uniquement les gains solo",
"mining_idle_off_tooltip": "Activer le minage au repos",
"mining_idle_on_tooltip": "Désactiver le minage au repos",
"mining_local_hashrate": "Hashrate local",
"mining_mine": "Miner",
"mining_mining_addr": "Adr. minage",
"mining_network": "Réseau",
"mining_no_blocks_yet": "Aucun bloc trouvé pour l'instant",
"mining_no_payouts_yet": "Aucun paiement de pool pour l'instant",
"mining_no_saved_addresses": "Aucune adresse enregistrée",
"mining_no_saved_pools": "Aucun pool enregistré",
"mining_off": "Le minage est DÉSACTIVÉ",
"mining_on": "Le minage est ACTIVÉ",
"mining_open_in_explorer": "Ouvrir dans l'explorateur",
"mining_payout_address": "Adresse de paiement",
"mining_payout_tooltip": "Adresse pour recevoir les récompenses de minage",
"mining_pool": "Pool",
"mining_pool_hashrate": "Hashrate du pool",
"mining_pool_url": "URL du pool",
"mining_recent_blocks": "BLOCS RÉCENTS",
"mining_recent_payouts": "PAIEMENTS DE POOL RÉCENTS",
"mining_remove": "Supprimer",
"mining_reset_defaults": "Réinitialiser les paramètres",
"mining_save_payout_address": "Enregistrer l'adresse de paiement",
"mining_save_pool_url": "Enregistrer l'URL du pool",
"mining_saved_addresses": "Adresses enregistrées :",
"mining_saved_pools": "Pools enregistrés :",
"mining_shares": "Parts",
"mining_show_chart": "Graphique",
"mining_show_log": "Journal",
"mining_solo": "Solo",
"mining_starting": "Démarrage...",
"mining_starting_tooltip": "Le mineur démarre...",
"mining_statistics": "Statistiques de minage",
"mining_stop": "Arrêter",
"mining_stop_solo_for_pool": "Arrêtez le minage solo avant de démarrer le minage en pool",
"mining_stop_solo_for_pool_settings": "Arrêtez le minage solo pour modifier les paramètres du pool",
"mining_stopping": "Arrêt...",
"mining_stopping_tooltip": "Le mineur s'arrête...",
"mining_syncing_tooltip": "La blockchain se synchronise...",
"mining_threads": "Threads de minage",
"mining_to_save": "pour enregistrer",
"mining_today": "Aujourd'hui",
"mining_uptime": "Temps de fonctionnement",
"mining_yesterday": "Hier",
"network": "Réseau",
"network_fee": "FRAIS RÉSEAU",
"network_hashrate": "Hashrate du réseau",
"new": "+ Nouveau",
"new_shielded_created": "Nouvelle adresse blindée créée",
"new_t_address": "Nouvelle adresse T",
"new_t_transparent": "Nouvelle adresse t (Transparente)",
"new_transparent_created": "Nouvelle adresse transparente créée",
"new_z_address": "Nouvelle adresse Z",
"new_z_shielded": "Nouvelle adresse z (Blindée)",
"no_addresses": "Aucune adresse trouvée. Créez-en une avec les boutons ci-dessus.",
"no_addresses_available": "Aucune adresse disponible",
"no_addresses_match": "Aucune adresse ne correspond au filtre",
"no_addresses_with_balance": "Aucune adresse avec solde",
"no_matching": "Aucune transaction correspondante",
"no_recent_receives": "Aucune réception récente",
"no_recent_sends": "Aucun envoi récent",
"no_transactions": "Aucune transaction trouvée",
"node": "NŒUD",
"node_security": "NŒUD & SÉCURITÉ",
"noise": "Bruit",
"not_connected": "Non connecté au daemon...",
"not_connected_to_daemon": "Non connecté au daemon",
"notes": "Notes",
"notes_optional": "Notes (optionnel) :",
"output_filename": "Nom du fichier de sortie :",
"overview": "Aperçu",
"paste": "Coller",
"paste_from_clipboard": "Coller depuis le presse-papiers",
"pay_from": "Payer depuis",
"payment_request": "DEMANDE DE PAIEMENT",
"payment_request_copied": "Demande de paiement copiée",
"payment_uri_copied": "URI de paiement copiée",
"peers": "Pairs",
"peers_avg_ping": "Ping moyen",
"peers_ban_24h": "Bannir le pair 24h",
"peers_ban_score": "Score de ban : %d",
"peers_banned": "Bannis",
"peers_banned_count": "Bannis : %d",
"peers_best_block": "Meilleur bloc",
"peers_blockchain": "BLOCKCHAIN",
"peers_blocks": "Blocs",
"peers_blocks_left": "%d blocs restants",
"peers_clear_all_bans": "Lever tous les bannissements",
"peers_click_copy": "Cliquez pour copier",
"peers_connected": "Connectés",
"peers_connected_count": "Connectés : %d",
"peers_copy_ip": "Copier l'IP",
"peers_dir_in": "Ent.",
"peers_dir_out": "Sort.",
"peers_hash_copied": "Hash copié",
"peers_hashrate": "Hashrate",
"peers_in_out": "Ent./Sort.",
"peers_longest": "Plus longue",
"peers_longest_chain": "Plus longue chaîne",
"peers_memory": "Mémoire",
"peers_no_banned": "Aucun pair banni",
"peers_no_connected": "Aucun pair connecté",
"peers_no_tls": "Pas de TLS",
"peers_notarized": "Notarisé",
"peers_p2p_port": "Port P2P",
"peers_protocol": "Protocole",
"peers_received": "Reçu",
"peers_refresh": "Actualiser",
"peers_refresh_tooltip": "Actualiser la liste des pairs",
"peers_refreshing": "Actualisation...",
"peers_sent": "Envoyé",
"peers_tt_id": "ID : %d",
"peers_tt_received": "Reçu : %s",
"peers_tt_sent": "Envoyé : %s",
"peers_tt_services": "Services : %s",
"peers_tt_start_height": "Hauteur de départ : %d",
"peers_tt_synced": "Synchronisé H/B : %d/%d",
"peers_tt_tls_cipher": "TLS : %s",
"peers_unban": "Débannir",
"peers_upper": "PAIRS",
"peers_version": "Version",
"pending": "En attente",
"ping": "Ping",
"price_chart": "Graphique des prix",
"qr_code": "Code QR",
"qr_failed": "Échec de la génération du code QR",
"qr_title": "Code QR",
"qr_unavailable": "QR indisponible",
"receive": "Recevoir",
"received": "reçu",
"received_filter": "Reçu",
"received_label": "Reçu",
"received_upper": "REÇU",
"receiving_addresses": "Vos adresses de réception",
"recent_received": "REÇUS RÉCENTS",
"recent_sends": "ENVOIS RÉCENTS",
"recipient": "DESTINATAIRE",
"recv_type": "Reçu",
"refresh": "Actualiser",
"refresh_now": "Actualiser maintenant",
"report_bug": "Signaler un bug",
"request_amount": "Montant (optionnel) :",
"request_copy_uri": "Copier l'URI",
"request_description": "Générez une demande de paiement que d'autres peuvent scanner ou copier. Le code QR contient votre adresse et un montant/mémo optionnel.",
"request_label": "Libellé (optionnel) :",
"request_memo": "Mémo (optionnel) :",
"request_payment": "Demander un paiement",
"request_payment_uri": "URI de paiement :",
"request_receive_address": "Adresse de réception :",
"request_select_address": "Sélectionner une adresse...",
"request_shielded_addrs": "-- Adresses blindées --",
"request_title": "Demander un paiement",
"request_transparent_addrs": "-- Adresses transparentes --",
"request_uri_copied": "URI de paiement copiée dans le presse-papiers",
"rescan": "Re-scanner",
"reset_to_defaults": "Réinitialiser les paramètres",
"review_send": "Vérifier l'envoi",
"rpc_host": "Hôte RPC",
"rpc_pass": "Mot de passe",
"rpc_port": "Port",
"rpc_user": "Nom d'utilisateur",
"save": "Enregistrer",
"save_settings": "Enregistrer les paramètres",
"save_z_transactions": "Enregistrer les Z-tx dans la liste",
"search_placeholder": "Rechercher...",
"security": "SÉCURITÉ",
"select_address": "Sélectionner une adresse...",
"select_receiving_address": "Sélectionner une adresse de réception...",
"select_source_address": "Sélectionner une adresse source...",
"send": "Envoyer",
"send_amount": "Montant",
"send_amount_details": "DÉTAILS DU MONTANT",
"send_amount_upper": "MONTANT",
"send_clear_fields": "Effacer tous les champs du formulaire ?",
"send_copy_error": "Copier l'erreur",
"send_dismiss": "Ignorer",
"send_error_copied": "Erreur copiée dans le presse-papiers",
"send_error_prefix": "Erreur : %s",
"send_exceeds_available": "Dépasse le disponible (%.8f)",
"send_fee": "Frais",
"send_fee_high": "Élevés",
"send_fee_low": "Faibles",
"send_fee_normal": "Normal",
"send_form_restored": "Formulaire restauré",
"send_from_this_address": "Envoyer depuis cette adresse",
"send_go_to_receive": "Aller à Recevoir",
"send_keep": "Conserver",
"send_network_fee": "FRAIS RÉSEAU",
"send_no_balance": "Pas de solde",
"send_no_recent": "Aucun envoi récent",
"send_recent_sends": "ENVOIS RÉCENTS",
"send_recipient": "DESTINATAIRE",
"send_select_source": "Sélectionner une adresse source...",
"send_sending_from": "ENVOI DEPUIS",
"send_submitting": "Soumission de la transaction...",
"send_switch_to_receive": "Passez à Recevoir pour obtenir votre adresse et commencer à recevoir des fonds.",
"send_to": "Envoyer à",
"send_tooltip_enter_amount": "Entrez un montant à envoyer",
"send_tooltip_exceeds_balance": "Le montant dépasse le solde disponible",
"send_tooltip_in_progress": "Transaction déjà en cours",
"send_tooltip_invalid_address": "Entrez une adresse de destinataire valide",
"send_tooltip_not_connected": "Non connecté au daemon",
"send_tooltip_select_source": "Sélectionnez d'abord une adresse source",
"send_tooltip_syncing": "Attendez la synchronisation de la blockchain",
"send_total": "Total",
"send_transaction": "Envoyer la transaction",
"send_tx_failed": "Transaction échouée",
"send_tx_sent": "Transaction envoyée !",
"send_tx_success": "Transaction envoyée avec succès !",
"send_txid_copied": "TxID copié dans le presse-papiers",
"send_txid_label": "TxID : %s",
"send_valid_shielded": "Adresse blindée valide",
"send_valid_transparent": "Adresse transparente valide",
"send_wallet_empty": "Votre portefeuille est vide",
"send_yes_clear": "Oui, effacer",
"sending": "Envoi de la transaction",
"sending_from": "ENVOI DEPUIS",
"sent": "envoyé",
"sent_filter": "Envoyé",
"sent_type": "Envoyé",
"sent_upper": "ENVOYÉ",
"settings": "Paramètres",
"setup_wizard": "Assistant de configuration",
"share": "Partager",
"shield_check_status": "Vérifier le statut",
"shield_completed": "Opération terminée avec succès !",
"shield_description": "Blindez vos récompenses de minage en envoyant les sorties coinbase des adresses transparentes vers une adresse blindée. Cela améliore la confidentialité en masquant vos revenus de minage.",
"shield_from_address": "Depuis l'adresse :",
"shield_funds": "Blinder les fonds",
"shield_in_progress": "Opération en cours...",
"shield_max_utxos": "UTXOs max par opération",
"shield_merge_done": "Blindage/fusion terminé !",
"shield_select_z": "Sélectionner une z-adresse...",
"shield_started": "Opération de blindage démarrée",
"shield_title": "Blinder les récompenses coinbase",
"shield_to_address": "Vers l'adresse (blindée) :",
"shield_utxo_limit": "Limite UTXO :",
"shield_wildcard_hint": "Utilisez '*' pour blinder depuis toutes les adresses transparentes",
"shielded": "Blindé",
"shielded_to": "BLINDÉ VERS",
"shielded_type": "Blindé",
"show": "Afficher",
"show_qr_code": "Afficher le code QR",
"showing_transactions": "Affichage %d\xe2\x80\x93%d sur %d transactions (total : %zu)",
"simple_background": "Arrière-plan simple",
"start_mining": "Démarrer le minage",
"status": "Statut",
"stop_external": "Arrêter le daemon externe",
"stop_mining": "Arrêter le minage",
"submitting_transaction": "Soumission de la transaction...",
"success": "Succès",
"summary": "Résumé",
"syncing": "Synchronisation...",
"t_addresses": "Adresses T",
"test_connection": "Tester",
"theme": "Thème",
"theme_effects": "Effets de thème",
"time_days_ago": "il y a %d jours",
"time_hours_ago": "il y a %d heures",
"time_minutes_ago": "il y a %d minutes",
"time_seconds_ago": "il y a %d secondes",
"to": "À",
"to_upper": "À",
"tools": "OUTILS",
"total": "Total",
"transaction_id": "ID DE TRANSACTION",
"transaction_sent": "Transaction envoyée avec succès",
"transaction_sent_msg": "Transaction envoyée !",
"transaction_url": "URL de transaction",
"transactions": "Transactions",
"transactions_upper": "TRANSACTIONS",
"transparent": "Transparent",
"tx_confirmations": "%d confirmations",
"tx_details_title": "Détails de la transaction",
"tx_from_address": "Adresse d'origine :",
"tx_id_label": "ID de transaction :",
"tx_immature": "IMMATURE",
"tx_mined": "MINÉ",
"tx_received": "REÇU",
"tx_sent": "ENVOYÉ",
"tx_to_address": "Adresse de destination :",
"tx_view_explorer": "Voir dans l'explorateur",
"txs_count": "%d txs",
"type": "Type",
"ui_opacity": "Opacité de l'interface",
"unban": "Débannir",
"unconfirmed": "Non confirmé",
"undo_clear": "Annuler l'effacement",
"unknown": "Inconnu",
"use_embedded_daemon": "Utiliser le dragonxd intégré",
"use_tor": "Utiliser Tor",
"validate_btn": "Valider",
"validate_description": "Entrez une adresse DragonX pour vérifier si elle est valide et si elle appartient à ce portefeuille.",
"validate_invalid": "INVALIDE",
"validate_is_mine": "Ce portefeuille possède cette adresse",
"validate_not_mine": "N'appartient pas à ce portefeuille",
"validate_ownership": "Propriété :",
"validate_results": "Résultats :",
"validate_shielded_type": "Blindée (z-adresse)",
"validate_status": "Statut :",
"validate_title": "Valider l'adresse",
"validate_transparent_type": "Transparente (t-adresse)",
"validate_type": "Type :",
"validate_valid": "VALIDE",
"validating": "Validation...",
"verbose_logging": "Journalisation détaillée",
"version": "Version",
"view": "Afficher",
"view_details": "Voir les détails",
"view_on_explorer": "Voir dans l'explorateur",
"waiting_for_daemon": "En attente de la connexion au daemon...",
"wallet": "PORTEFEUILLE",
"wallet_empty": "Votre portefeuille est vide",
"wallet_empty_hint": "Passez à Recevoir pour obtenir votre adresse et commencer à recevoir des fonds.",
"warning": "Attention",
"warning_upper": "ATTENTION !",
"website": "Site web",
"window_opacity": "Opacité de la fenêtre",
"yes_clear": "Oui, effacer",
"your_addresses": "Vos adresses",
"z_addresses": "Adresses Z",
}
out = os.path.join(os.path.dirname(__file__), "..", "res", "lang", "fr.json")
with open(out, "w", encoding="utf-8") as f:
json.dump(translations, f, indent=4, ensure_ascii=False, sort_keys=True)
print(f"Wrote {len(translations)} French translations to {os.path.abspath(out)}")

View File

@@ -1,646 +0,0 @@
#!/usr/bin/env python3
"""Generate Japanese (ja) translations for ObsidianDragon wallet."""
import json, os
translations = {
"24h_change": "24時間変動",
"24h_volume": "24時間出来高",
"about": "概要",
"about_block_explorer": "ブロックエクスプローラー",
"about_block_height": "ブロック高:",
"about_build_date": "ビルド日:",
"about_build_type": "ビルドタイプ:",
"about_chain": "チェーン:",
"about_connections": "接続数:",
"about_credits": "クレジット",
"about_daemon": "デーモン:",
"about_debug": "デバッグ",
"about_dragonx": "ObsidianDragonについて",
"about_edition": "ImGui エディション",
"about_github": "GitHub",
"about_imgui": "ImGui",
"about_license": "ライセンス",
"about_license_text": "本ソフトウェアはGNU General Public License v3 (GPLv3)の下で公開されています。ライセンス条項に従い、自由に使用、変更、配布できます。",
"about_peers_count": "%zu ピア",
"about_release": "リリース",
"about_title": "ObsidianDragonについて",
"about_version": "バージョン:",
"about_website": "ウェブサイト",
"acrylic": "アクリル",
"add": "追加",
"address": "アドレス",
"address_book_add": "アドレスを追加",
"address_book_add_new": "新規追加",
"address_book_added": "アドレスをアドレス帳に追加しました",
"address_book_count": "%zu 件のアドレスを保存済み",
"address_book_deleted": "エントリを削除しました",
"address_book_edit": "アドレスを編集",
"address_book_empty": "保存されたアドレスがありません。「新規追加」をクリックして追加してください。",
"address_book_exists": "アドレスは既にアドレス帳に存在します",
"address_book_title": "アドレス帳",
"address_book_update_failed": "更新に失敗しました — アドレスが重複している可能性があります",
"address_book_updated": "アドレスを更新しました",
"address_copied": "アドレスをクリップボードにコピーしました",
"address_details": "アドレス詳細",
"address_label": "アドレス:",
"address_upper": "アドレス",
"address_url": "アドレスURL",
"addresses_appear_here": "接続後、受信アドレスがここに表示されます。",
"advanced": "詳細設定",
"all_filter": "すべて",
"allow_custom_fees": "カスタム手数料を許可",
"amount": "金額",
"amount_details": "金額の詳細",
"amount_exceeds_balance": "金額が残高を超えています",
"amount_label": "金額:",
"appearance": "外観",
"auto_shield": "マイニング自動シールド",
"available": "利用可能",
"backup_backing_up": "バックアップ中...",
"backup_create": "バックアップを作成",
"backup_created": "ウォレットのバックアップを作成しました",
"backup_data": "バックアップとデータ",
"backup_description": "wallet.datファイルのバックアップを作成します。このファイルにはすべての秘密鍵と取引履歴が含まれています。バックアップは安全な場所に保管してください。",
"backup_destination": "バックアップ先:",
"backup_tip_external": "外部ドライブまたはクラウドストレージにバックアップを保存",
"backup_tip_multiple": "異なる場所に複数のバックアップを作成",
"backup_tip_test": "定期的にバックアップからの復元をテスト",
"backup_tips": "ヒント:",
"backup_title": "ウォレットのバックアップ",
"backup_wallet": "ウォレットをバックアップ...",
"backup_wallet_not_found": "警告予想される場所にwallet.datが見つかりません",
"balance": "残高",
"balance_layout": "残高レイアウト",
"ban": "ブロック",
"banned_peers": "ブロック済みピア",
"block": "ブロック",
"block_bits": "ビット:",
"block_click_next": "クリックして次のブロックを表示",
"block_click_prev": "クリックして前のブロックを表示",
"block_explorer": "ブロックエクスプローラー",
"block_get_info": "ブロック情報を取得",
"block_hash": "ブロックハッシュ:",
"block_height": "ブロック高:",
"block_info_title": "ブロック情報",
"block_merkle_root": "マークルルート:",
"block_nav_next": "次へ >>",
"block_nav_prev": "<< 前へ",
"block_next": "次のブロック:",
"block_previous": "前のブロック:",
"block_size": "サイズ:",
"block_timestamp": "タイムスタンプ:",
"block_transactions": "トランザクション:",
"blockchain_syncing": "ブロックチェーン同期中 (%.1f%%)... 残高が不正確な場合があります。",
"cancel": "キャンセル",
"characters": "文字",
"clear": "クリア",
"clear_all_bans": "すべてのブロックを解除",
"clear_form_confirm": "すべてのフォームフィールドをクリアしますか?",
"clear_request": "リクエストをクリア",
"click_copy_address": "クリックしてアドレスをコピー",
"click_copy_uri": "クリックしてURIをコピー",
"close": "閉じる",
"conf_count": "%d 確認",
"confirm_and_send": "確認して送金",
"confirm_send": "送金を確認",
"confirm_transaction": "取引を確認",
"confirmations": "確認数",
"confirmations_display": "%d 確認 | %s",
"confirmed": "確認済み",
"connected": "接続済み",
"connected_peers": "接続中のピア",
"connecting": "接続中...",
"console": "コンソール",
"console_auto_scroll": "自動スクロール",
"console_available_commands": "利用可能なコマンド:",
"console_capturing_output": "デーモン出力をキャプチャ中...",
"console_clear": "クリア",
"console_clear_console": "コンソールをクリア",
"console_cleared": "コンソールをクリアしました",
"console_click_commands": "上のコマンドをクリックして挿入",
"console_click_insert": "クリックして挿入",
"console_click_insert_params": "クリックしてパラメータ付きで挿入",
"console_close": "閉じる",
"console_commands": "コマンド",
"console_common_rpc": "一般的なRPCコマンド",
"console_completions": "補完:",
"console_connected": "デーモンに接続済み",
"console_copy_all": "すべてコピー",
"console_copy_selected": "コピー",
"console_daemon": "デーモン",
"console_daemon_error": "デーモンエラー!",
"console_daemon_started": "デーモンが起動しました",
"console_daemon_stopped": "デーモンが停止しました",
"console_disconnected": "デーモンから切断されました",
"console_errors": "エラー",
"console_filter_hint": "出力をフィルタ...",
"console_help_clear": " clear - コンソールをクリア",
"console_help_getbalance": " getbalance - 透明残高を表示",
"console_help_getblockcount": " getblockcount - 現在のブロック高を表示",
"console_help_getinfo": " getinfo - ノード情報を表示",
"console_help_getmininginfo": " getmininginfo - マイニング状況を表示",
"console_help_getpeerinfo": " getpeerinfo - 接続中のピアを表示",
"console_help_gettotalbalance": " gettotalbalance - 合計残高を表示",
"console_help_help": " help - このヘルプを表示",
"console_help_setgenerate": " setgenerate - マイニングを制御",
"console_help_stop": " stop - デーモンを停止",
"console_line_count": "%zu 行",
"console_new_lines": "%d 新しい行",
"console_no_daemon": "デーモンなし",
"console_not_connected": "エラー:デーモンに接続されていません",
"console_rpc_reference": "RPCコマンドリファレンス",
"console_scanline": "コンソールスキャンライン",
"console_search_commands": "コマンドを検索...",
"console_select_all": "すべて選択",
"console_show_daemon_output": "デーモン出力を表示",
"console_show_errors_only": "エラーのみ表示",
"console_show_rpc_ref": "RPCコマンドリファレンスを表示",
"console_showing_lines": "%zu / %zu 行を表示中",
"console_starting_node": "ノードを起動中...",
"console_status_error": "エラー",
"console_status_running": "実行中",
"console_status_starting": "起動中",
"console_status_stopped": "停止済み",
"console_status_stopping": "停止中",
"console_status_unknown": "不明",
"console_tab_completion": "Tabで補完",
"console_type_help": "'help'と入力して利用可能なコマンドを表示",
"console_welcome": "ObsidianDragonコンソールへようこそ",
"console_zoom_in": "拡大",
"console_zoom_out": "縮小",
"copy": "コピー",
"copy_address": "完全なアドレスをコピー",
"copy_error": "エラーをコピー",
"copy_to_clipboard": "クリップボードにコピー",
"copy_txid": "TxIDをコピー",
"copy_uri": "URIをコピー",
"current_price": "現在の価格",
"custom_fees": "カスタム手数料",
"dark": "ダーク",
"date": "日付",
"date_label": "日付:",
"delete": "削除",
"difficulty": "難易度",
"disconnected": "切断済み",
"dismiss": "閉じる",
"display": "表示",
"dragonx_green": "DragonXグリーン",
"edit": "編集",
"error": "エラー",
"est_time_to_block": "予測ブロック時間",
"exit": "終了",
"explorer": "エクスプローラー",
"export": "エクスポート",
"export_csv": "CSVエクスポート",
"export_keys_btn": "鍵をエクスポート",
"export_keys_danger": "危険:ウォレットからすべての秘密鍵がエクスポートされます!このファイルにアクセスできる人は誰でもあなたの資金を盗めます。安全に保管し、使用後は削除してください。",
"export_keys_include_t": "Tアドレスを含める透明",
"export_keys_include_z": "Zアドレスを含めるシールド",
"export_keys_options": "エクスポートオプション:",
"export_keys_success": "鍵のエクスポートに成功しました",
"export_keys_title": "すべての秘密鍵をエクスポート",
"export_private_key": "秘密鍵をエクスポート",
"export_tx_count": "%zu件の取引をCSVファイルにエクスポート。",
"export_tx_file_fail": "CSVファイルの作成に失敗しました",
"export_tx_none": "エクスポートする取引がありません",
"export_tx_success": "取引のエクスポートに成功しました",
"export_tx_title": "取引をCSVにエクスポート",
"export_viewing_key": "閲覧鍵をエクスポート",
"failed_create_shielded": "シールドアドレスの作成に失敗しました",
"failed_create_transparent": "透明アドレスの作成に失敗しました",
"fee": "手数料",
"fee_high": "高い",
"fee_label": "手数料:",
"fee_low": "低い",
"fee_normal": "通常",
"fetch_prices": "価格を取得",
"file": "ファイル",
"file_save_location": "ファイルの保存先:~/.config/ObsidianDragon/",
"font_scale": "フォントサイズ",
"from": "送信元",
"from_upper": "送信元",
"full_details": "詳細情報",
"general": "一般",
"go_to_receive": "受信へ移動",
"height": "高さ",
"help": "ヘルプ",
"hide": "非表示",
"history": "履歴",
"immature_type": "未成熟",
"import": "インポート",
"import_key_btn": "鍵をインポート",
"import_key_formats": "サポートされる鍵形式:",
"import_key_full_rescan": "0 = 完全再スキャン)",
"import_key_label": "秘密鍵:",
"import_key_no_valid": "入力に有効な鍵が見つかりません",
"import_key_rescan": "インポート後にブロックチェーンを再スキャン",
"import_key_start_height": "開始高:",
"import_key_success": "鍵のインポートに成功しました",
"import_key_t_format": "TアドレスWIF秘密鍵",
"import_key_title": "秘密鍵をインポート",
"import_key_tooltip": "1行に1つずつ秘密鍵を入力してください。\nzアドレスとtアドレスの鍵の両方に対応しています。\n#で始まる行はコメントとして扱われます。",
"import_key_warning": "警告:秘密鍵を決して共有しないでください!信頼できないソースからの鍵のインポートはウォレットを危険にさらす可能性があります。",
"import_key_z_format": "Zアドレス支出鍵 (secret-extended-key-...)",
"import_private_key": "秘密鍵をインポート...",
"invalid_address": "無効なアドレス形式",
"ip_address": "IPアドレス",
"keep": "保持",
"keep_daemon": "デーモンを実行し続ける",
"key_export_fetching": "ウォレットから鍵を取得中...",
"key_export_private_key": "秘密鍵:",
"key_export_private_warning": "この鍵は秘密にしてください!この鍵を持つ人は誰でもあなたの資金を使えます。オンラインや信頼できない相手と共有しないでください。",
"key_export_reveal": "鍵を表示",
"key_export_viewing_key": "閲覧鍵:",
"key_export_viewing_warning": "この閲覧鍵を使うと、他者があなたの受信取引と残高を見ることができますが、資金を使うことはできません。信頼できる相手とのみ共有してください。",
"label": "ラベル:",
"language": "言語",
"light": "ライト",
"loading": "読み込み中...",
"loading_addresses": "アドレスを読み込み中...",
"local_hashrate": "ローカルハッシュレート",
"low_spec_mode": "省電力モード",
"market": "市場",
"market_12h": "12時間",
"market_18h": "18時間",
"market_24h": "24時間",
"market_24h_volume": "24時間出来高",
"market_6h": "6時間",
"market_attribution": "価格データNonKYC提供",
"market_btc_price": "BTC価格",
"market_cap": "時価総額",
"market_no_history": "価格履歴がありません",
"market_no_price": "価格データなし",
"market_now": "現在",
"market_pct_shielded": "%.0f%% シールド済み",
"market_portfolio": "ポートフォリオ",
"market_price_unavailable": "価格データが利用できません",
"market_refresh_price": "価格データを更新",
"market_trade_on": "%s で取引",
"mature": "成熟済み",
"max": "最大",
"memo": "メモ(任意、暗号化)",
"memo_label": "メモ:",
"memo_optional": "メモ(任意)",
"memo_upper": "メモ",
"memo_z_only": "注:メモはシールド (z) アドレスへの送金時のみ利用可能です",
"merge_description": "複数のUTXOを単一のシールドアドレスに統合します。ウォレットサイズの縮小とプライバシーの向上に役立ちます。",
"merge_funds": "資金を統合",
"merge_started": "統合操作を開始しました",
"merge_title": "アドレスに統合",
"mine_when_idle": "アイドル時にマイニング",
"mined": "採掘済み",
"mined_filter": "採掘済み",
"mined_type": "採掘済み",
"mined_upper": "採掘済み",
"miner_fee": "マイナー手数料",
"mining": "マイニング",
"mining_active": "アクティブ",
"mining_address_copied": "マイニングアドレスをコピーしました",
"mining_all_time": "全期間",
"mining_already_saved": "プールURLは既に保存済みです",
"mining_block_copied": "ブロックハッシュをコピーしました",
"mining_chart_1m_ago": "1分前",
"mining_chart_5m_ago": "5分前",
"mining_chart_now": "現在",
"mining_chart_start": "開始",
"mining_click": "クリック",
"mining_click_copy_address": "クリックしてアドレスをコピー",
"mining_click_copy_block": "クリックしてブロックハッシュをコピー",
"mining_click_copy_difficulty": "クリックして難易度をコピー",
"mining_connected": "接続済み",
"mining_connecting": "接続中...",
"mining_control": "マイニング制御",
"mining_difficulty_copied": "難易度をコピーしました",
"mining_est_block": "予測ブロック",
"mining_est_daily": "予測日収",
"mining_filter_all": "すべて",
"mining_filter_tip_all": "すべての収益を表示",
"mining_filter_tip_pool": "プール収益のみ表示",
"mining_filter_tip_solo": "ソロ収益のみ表示",
"mining_idle_off_tooltip": "アイドルマイニングを有効にする",
"mining_idle_on_tooltip": "アイドルマイニングを無効にする",
"mining_local_hashrate": "ローカルハッシュレート",
"mining_mine": "マイニング",
"mining_mining_addr": "マイニングアドレス",
"mining_network": "ネットワーク",
"mining_no_blocks_yet": "まだブロックが見つかっていません",
"mining_no_payouts_yet": "まだプール支払いがありません",
"mining_no_saved_addresses": "保存されたアドレスがありません",
"mining_no_saved_pools": "保存されたプールがありません",
"mining_off": "マイニングはオフです",
"mining_on": "マイニングはオンです",
"mining_open_in_explorer": "エクスプローラーで開く",
"mining_payout_address": "支払いアドレス",
"mining_payout_tooltip": "マイニング報酬の受取アドレス",
"mining_pool": "プール",
"mining_pool_hashrate": "プールハッシュレート",
"mining_pool_url": "プールURL",
"mining_recent_blocks": "最近のブロック",
"mining_recent_payouts": "最近のプール支払い",
"mining_remove": "削除",
"mining_reset_defaults": "デフォルトにリセット",
"mining_save_payout_address": "支払いアドレスを保存",
"mining_save_pool_url": "プールURLを保存",
"mining_saved_addresses": "保存済みアドレス:",
"mining_saved_pools": "保存済みプール:",
"mining_shares": "シェア",
"mining_show_chart": "チャート",
"mining_show_log": "ログ",
"mining_solo": "ソロ",
"mining_starting": "起動中...",
"mining_starting_tooltip": "マイナーを起動中...",
"mining_statistics": "マイニング統計",
"mining_stop": "停止",
"mining_stop_solo_for_pool": "プールマイニングを開始する前にソロマイニングを停止してください",
"mining_stop_solo_for_pool_settings": "プール設定を変更するにはソロマイニングを停止してください",
"mining_stopping": "停止中...",
"mining_stopping_tooltip": "マイナーを停止中...",
"mining_syncing_tooltip": "ブロックチェーン同期中...",
"mining_threads": "マイニングスレッド",
"mining_to_save": "保存する",
"mining_today": "今日",
"mining_uptime": "稼働時間",
"mining_yesterday": "昨日",
"network": "ネットワーク",
"network_fee": "ネットワーク手数料",
"network_hashrate": "ネットワークハッシュレート",
"new": "+ 新規",
"new_shielded_created": "新しいシールドアドレスを作成しました",
"new_t_address": "新しいTアドレス",
"new_t_transparent": "新しいtアドレス透明",
"new_transparent_created": "新しい透明アドレスを作成しました",
"new_z_address": "新しいZアドレス",
"new_z_shielded": "新しいzアドレスシールド",
"no_addresses": "アドレスが見つかりません。上のボタンを使用して作成してください。",
"no_addresses_available": "利用可能なアドレスがありません",
"no_addresses_match": "フィルタに一致するアドレスがありません",
"no_addresses_with_balance": "残高のあるアドレスがありません",
"no_matching": "一致する取引がありません",
"no_recent_receives": "最近の受信がありません",
"no_recent_sends": "最近の送信がありません",
"no_transactions": "取引が見つかりません",
"node": "ノード",
"node_security": "ノードとセキュリティ",
"noise": "ノイズ",
"not_connected": "デーモンに未接続...",
"not_connected_to_daemon": "デーモンに未接続",
"notes": "メモ",
"notes_optional": "メモ(任意):",
"output_filename": "出力ファイル名:",
"overview": "概要",
"paste": "貼り付け",
"paste_from_clipboard": "クリップボードから貼り付け",
"pay_from": "支払い元",
"payment_request": "支払い請求",
"payment_request_copied": "支払い請求をコピーしました",
"payment_uri_copied": "支払いURIをコピーしました",
"peers": "ピア",
"peers_avg_ping": "平均Ping",
"peers_ban_24h": "ピアを24時間ブロック",
"peers_ban_score": "ブロックスコア:%d",
"peers_banned": "ブロック済み",
"peers_banned_count": "ブロック済み:%d",
"peers_best_block": "最良ブロック",
"peers_blockchain": "ブロックチェーン",
"peers_blocks": "ブロック",
"peers_blocks_left": "残り %d ブロック",
"peers_clear_all_bans": "すべてのブロックを解除",
"peers_click_copy": "クリックしてコピー",
"peers_connected": "接続済み",
"peers_connected_count": "接続済み:%d",
"peers_copy_ip": "IPをコピー",
"peers_dir_in": "",
"peers_dir_out": "",
"peers_hash_copied": "ハッシュをコピーしました",
"peers_hashrate": "ハッシュレート",
"peers_in_out": "入/出",
"peers_longest": "最長",
"peers_longest_chain": "最長チェーン",
"peers_memory": "メモリ",
"peers_no_banned": "ブロック済みピアなし",
"peers_no_connected": "接続済みピアなし",
"peers_no_tls": "TLSなし",
"peers_notarized": "公証済み",
"peers_p2p_port": "P2Pポート",
"peers_protocol": "プロトコル",
"peers_received": "受信",
"peers_refresh": "更新",
"peers_refresh_tooltip": "ピアリストを更新",
"peers_refreshing": "更新中...",
"peers_sent": "送信",
"peers_tt_id": "ID%d",
"peers_tt_received": "受信:%s",
"peers_tt_sent": "送信:%s",
"peers_tt_services": "サービス:%s",
"peers_tt_start_height": "開始高:%d",
"peers_tt_synced": "同期済み H/B%d/%d",
"peers_tt_tls_cipher": "TLS%s",
"peers_unban": "ブロック解除",
"peers_upper": "ピア",
"peers_version": "バージョン",
"pending": "保留中",
"ping": "Ping",
"price_chart": "価格チャート",
"qr_code": "QRコード",
"qr_failed": "QRコードの生成に失敗しました",
"qr_title": "QRコード",
"qr_unavailable": "QR利用不可",
"receive": "受信",
"received": "受信済み",
"received_filter": "受信済み",
"received_label": "受信済み",
"received_upper": "受信済み",
"receiving_addresses": "あなたの受信アドレス",
"recent_received": "最近の受信",
"recent_sends": "最近の送信",
"recipient": "受取人",
"recv_type": "受信",
"refresh": "更新",
"refresh_now": "今すぐ更新",
"report_bug": "バグを報告",
"request_amount": "金額(任意):",
"request_copy_uri": "URIをコピー",
"request_description": "他の人がスキャンまたはコピーできる支払い請求を生成します。QRコードにはアドレスとオプションの金額/メモが含まれます。",
"request_label": "ラベル(任意):",
"request_memo": "メモ(任意):",
"request_payment": "支払いを請求",
"request_payment_uri": "支払いURI",
"request_receive_address": "受信アドレス:",
"request_select_address": "アドレスを選択...",
"request_shielded_addrs": "-- シールドアドレス --",
"request_title": "支払いを請求",
"request_transparent_addrs": "-- 透明アドレス --",
"request_uri_copied": "支払いURIをクリップボードにコピーしました",
"rescan": "再スキャン",
"reset_to_defaults": "デフォルトにリセット",
"review_send": "送金を確認",
"rpc_host": "RPCホスト",
"rpc_pass": "パスワード",
"rpc_port": "ポート",
"rpc_user": "ユーザー名",
"save": "保存",
"save_settings": "設定を保存",
"save_z_transactions": "Z取引を取引リストに保存",
"search_placeholder": "検索...",
"security": "セキュリティ",
"select_address": "アドレスを選択...",
"select_receiving_address": "受信アドレスを選択...",
"select_source_address": "送信元アドレスを選択...",
"send": "送金",
"send_amount": "金額",
"send_amount_details": "金額の詳細",
"send_amount_upper": "金額",
"send_clear_fields": "すべてのフォームフィールドをクリアしますか?",
"send_copy_error": "エラーをコピー",
"send_dismiss": "閉じる",
"send_error_copied": "エラーをクリップボードにコピーしました",
"send_error_prefix": "エラー:%s",
"send_exceeds_available": "利用可能額を超過 (%.8f)",
"send_fee": "手数料",
"send_fee_high": "高い",
"send_fee_low": "低い",
"send_fee_normal": "通常",
"send_form_restored": "フォームが復元されました",
"send_from_this_address": "このアドレスから送金",
"send_go_to_receive": "受信へ移動",
"send_keep": "保持",
"send_network_fee": "ネットワーク手数料",
"send_no_balance": "残高なし",
"send_no_recent": "最近の送信なし",
"send_recent_sends": "最近の送信",
"send_recipient": "受取人",
"send_select_source": "送信元アドレスを選択...",
"send_sending_from": "送信元",
"send_submitting": "取引を送信中...",
"send_switch_to_receive": "受信に切り替えてアドレスを取得し、資金の受け取りを開始してください。",
"send_to": "送金先",
"send_tooltip_enter_amount": "送金額を入力してください",
"send_tooltip_exceeds_balance": "金額が利用可能残高を超えています",
"send_tooltip_in_progress": "取引は既に進行中です",
"send_tooltip_invalid_address": "有効な受取人アドレスを入力してください",
"send_tooltip_not_connected": "デーモンに未接続",
"send_tooltip_select_source": "まず送信元アドレスを選択してください",
"send_tooltip_syncing": "ブロックチェーンの同期をお待ちください",
"send_total": "合計",
"send_transaction": "取引を送信",
"send_tx_failed": "取引に失敗しました",
"send_tx_sent": "取引を送信しました!",
"send_tx_success": "取引の送信に成功しました!",
"send_txid_copied": "TxIDをクリップボードにコピーしました",
"send_txid_label": "TxID%s",
"send_valid_shielded": "有効なシールドアドレス",
"send_valid_transparent": "有効な透明アドレス",
"send_wallet_empty": "ウォレットは空です",
"send_yes_clear": "はい、クリア",
"sending": "取引を送信中",
"sending_from": "送信元",
"sent": "送信済み",
"sent_filter": "送信済み",
"sent_type": "送信済み",
"sent_upper": "送信済み",
"settings": "設定",
"setup_wizard": "セットアップウィザード",
"share": "共有",
"shield_check_status": "ステータスを確認",
"shield_completed": "操作が正常に完了しました!",
"shield_description": "透明アドレスのcoinbase出力をシールドアドレスに送信して、マイニング報酬をシールドします。マイニング収入を隠すことでプライバシーが向上します。",
"shield_from_address": "送信元アドレス:",
"shield_funds": "資金をシールド",
"shield_in_progress": "操作進行中...",
"shield_max_utxos": "1回の操作あたりの最大UTXO数",
"shield_merge_done": "シールド/統合が完了しました!",
"shield_select_z": "zアドレスを選択...",
"shield_started": "シールド操作を開始しました",
"shield_title": "Coinbase報酬をシールド",
"shield_to_address": "送信先アドレス(シールド):",
"shield_utxo_limit": "UTXO制限",
"shield_wildcard_hint": "'*' を使用してすべての透明アドレスからシールド",
"shielded": "シールド",
"shielded_to": "シールド先",
"shielded_type": "シールド",
"show": "表示",
"show_qr_code": "QRコードを表示",
"showing_transactions": "%d\xe2\x80\x93%d / %d 件の取引を表示中(合計:%zu",
"simple_background": "シンプル背景",
"start_mining": "マイニング開始",
"status": "ステータス",
"stop_external": "外部デーモンを停止",
"stop_mining": "マイニング停止",
"submitting_transaction": "取引を送信中...",
"success": "成功",
"summary": "概要",
"syncing": "同期中...",
"t_addresses": "Tアドレス",
"test_connection": "テスト",
"theme": "テーマ",
"theme_effects": "テーマ効果",
"time_days_ago": "%d日前",
"time_hours_ago": "%d時間前",
"time_minutes_ago": "%d分前",
"time_seconds_ago": "%d秒前",
"to": "宛先",
"to_upper": "宛先",
"tools": "ツール",
"total": "合計",
"transaction_id": "取引ID",
"transaction_sent": "取引の送信に成功しました",
"transaction_sent_msg": "取引を送信しました!",
"transaction_url": "取引URL",
"transactions": "取引",
"transactions_upper": "取引",
"transparent": "透明",
"tx_confirmations": "%d 確認",
"tx_details_title": "取引の詳細",
"tx_from_address": "送信元アドレス:",
"tx_id_label": "取引ID",
"tx_immature": "未成熟",
"tx_mined": "採掘済み",
"tx_received": "受信済み",
"tx_sent": "送信済み",
"tx_to_address": "送信先アドレス:",
"tx_view_explorer": "エクスプローラーで表示",
"txs_count": "%d",
"type": "タイプ",
"ui_opacity": "UI透明度",
"unban": "ブロック解除",
"unconfirmed": "未確認",
"undo_clear": "クリアを元に戻す",
"unknown": "不明",
"use_embedded_daemon": "内蔵dragonxdを使用",
"use_tor": "Torを使用",
"validate_btn": "検証",
"validate_description": "DragonXアドレスを入力して、有効かどうか、そしてこのウォレットに属しているかどうかを確認します。",
"validate_invalid": "無効",
"validate_is_mine": "このウォレットがこのアドレスを所有しています",
"validate_not_mine": "このウォレットに属していません",
"validate_ownership": "所有者:",
"validate_results": "結果:",
"validate_shielded_type": "シールドzアドレス",
"validate_status": "ステータス:",
"validate_title": "アドレスを検証",
"validate_transparent_type": "透明tアドレス",
"validate_type": "タイプ:",
"validate_valid": "有効",
"validating": "検証中...",
"verbose_logging": "詳細ログ",
"version": "バージョン",
"view": "表示",
"view_details": "詳細を表示",
"view_on_explorer": "エクスプローラーで表示",
"waiting_for_daemon": "デーモン接続を待機中...",
"wallet": "ウォレット",
"wallet_empty": "ウォレットは空です",
"wallet_empty_hint": "受信に切り替えてアドレスを取得し、資金の受け取りを開始してください。",
"warning": "警告",
"warning_upper": "警告!",
"website": "ウェブサイト",
"window_opacity": "ウィンドウ透明度",
"yes_clear": "はい、クリア",
"your_addresses": "あなたのアドレス",
"z_addresses": "Zアドレス",
}
out = os.path.join(os.path.dirname(__file__), "..", "res", "lang", "ja.json")
with open(out, "w", encoding="utf-8") as f:
json.dump(translations, f, indent=4, ensure_ascii=False, sort_keys=True)
print(f"Wrote {len(translations)} Japanese translations to {os.path.abspath(out)}")

View File

@@ -1,646 +0,0 @@
#!/usr/bin/env python3
"""Generate Korean (ko) translations for ObsidianDragon wallet."""
import json, os
translations = {
"24h_change": "24시간 변동",
"24h_volume": "24시간 거래량",
"about": "정보",
"about_block_explorer": "블록 탐색기",
"about_block_height": "블록 높이:",
"about_build_date": "빌드 날짜:",
"about_build_type": "빌드 유형:",
"about_chain": "체인:",
"about_connections": "연결:",
"about_credits": "크레딧",
"about_daemon": "데몬:",
"about_debug": "디버그",
"about_dragonx": "ObsidianDragon 정보",
"about_edition": "ImGui 에디션",
"about_github": "GitHub",
"about_imgui": "ImGui:",
"about_license": "라이선스",
"about_license_text": "본 소프트웨어는 GNU General Public License v3 (GPLv3) 하에 배포됩니다. 라이선스 조건에 따라 자유롭게 사용, 수정 및 배포할 수 있습니다.",
"about_peers_count": "%zu 피어",
"about_release": "릴리스",
"about_title": "ObsidianDragon 정보",
"about_version": "버전:",
"about_website": "웹사이트",
"acrylic": "아크릴",
"add": "추가",
"address": "주소",
"address_book_add": "주소 추가",
"address_book_add_new": "새로 추가",
"address_book_added": "주소록에 주소를 추가했습니다",
"address_book_count": "저장된 주소 %zu개",
"address_book_deleted": "항목이 삭제되었습니다",
"address_book_edit": "주소 편집",
"address_book_empty": "저장된 주소가 없습니다. '새로 추가'를 클릭하여 추가하세요.",
"address_book_exists": "주소가 이미 주소록에 있습니다",
"address_book_title": "주소록",
"address_book_update_failed": "업데이트 실패 — 주소가 중복될 수 있습니다",
"address_book_updated": "주소가 업데이트되었습니다",
"address_copied": "주소가 클립보드에 복사되었습니다",
"address_details": "주소 상세",
"address_label": "주소:",
"address_upper": "주소",
"address_url": "주소 URL",
"addresses_appear_here": "연결 후 수신 주소가 여기에 표시됩니다.",
"advanced": "고급 설정",
"all_filter": "전체",
"allow_custom_fees": "사용자 정의 수수료 허용",
"amount": "금액",
"amount_details": "금액 상세",
"amount_exceeds_balance": "금액이 잔액을 초과합니다",
"amount_label": "금액:",
"appearance": "외관",
"auto_shield": "채굴 자동 차폐",
"available": "사용 가능",
"backup_backing_up": "백업 중...",
"backup_create": "백업 생성",
"backup_created": "지갑 백업이 생성되었습니다",
"backup_data": "백업 및 데이터",
"backup_description": "wallet.dat 파일의 백업을 생성합니다. 이 파일에는 모든 개인 키와 거래 내역이 포함되어 있습니다. 백업을 안전한 곳에 보관하세요.",
"backup_destination": "백업 위치:",
"backup_tip_external": "외장 드라이브 또는 클라우드 스토리지에 백업 저장",
"backup_tip_multiple": "서로 다른 위치에 여러 백업 생성",
"backup_tip_test": "정기적으로 백업 복원 테스트",
"backup_tips": "팁:",
"backup_title": "지갑 백업",
"backup_wallet": "지갑 백업...",
"backup_wallet_not_found": "경고: 예상 위치에서 wallet.dat를 찾을 수 없습니다",
"balance": "잔액",
"balance_layout": "잔액 레이아웃",
"ban": "차단",
"banned_peers": "차단된 피어",
"block": "블록",
"block_bits": "비트:",
"block_click_next": "클릭하여 다음 블록 보기",
"block_click_prev": "클릭하여 이전 블록 보기",
"block_explorer": "블록 탐색기",
"block_get_info": "블록 정보 조회",
"block_hash": "블록 해시:",
"block_height": "블록 높이:",
"block_info_title": "블록 정보",
"block_merkle_root": "머클 루트:",
"block_nav_next": "다음 >>",
"block_nav_prev": "<< 이전",
"block_next": "다음 블록:",
"block_previous": "이전 블록:",
"block_size": "크기:",
"block_timestamp": "타임스탬프:",
"block_transactions": "트랜잭션:",
"blockchain_syncing": "블록체인 동기화 중 (%.1f%%)... 잔액이 정확하지 않을 수 있습니다.",
"cancel": "취소",
"characters": "문자",
"clear": "지우기",
"clear_all_bans": "모든 차단 해제",
"clear_form_confirm": "모든 양식 필드를 지우시겠습니까?",
"clear_request": "요청 지우기",
"click_copy_address": "클릭하여 주소 복사",
"click_copy_uri": "클릭하여 URI 복사",
"close": "닫기",
"conf_count": "%d 확인",
"confirm_and_send": "확인 후 전송",
"confirm_send": "전송 확인",
"confirm_transaction": "거래 확인",
"confirmations": "확인 수",
"confirmations_display": "%d 확인 | %s",
"confirmed": "확인됨",
"connected": "연결됨",
"connected_peers": "연결된 피어",
"connecting": "연결 중...",
"console": "콘솔",
"console_auto_scroll": "자동 스크롤",
"console_available_commands": "사용 가능한 명령어:",
"console_capturing_output": "데몬 출력 캡처 중...",
"console_clear": "지우기",
"console_clear_console": "콘솔 지우기",
"console_cleared": "콘솔이 지워졌습니다",
"console_click_commands": "위의 명령어를 클릭하여 삽입",
"console_click_insert": "클릭하여 삽입",
"console_click_insert_params": "클릭하여 매개변수와 함께 삽입",
"console_close": "닫기",
"console_commands": "명령어",
"console_common_rpc": "일반 RPC 명령어:",
"console_completions": "자동 완성:",
"console_connected": "데몬에 연결됨",
"console_copy_all": "모두 복사",
"console_copy_selected": "복사",
"console_daemon": "데몬",
"console_daemon_error": "데몬 오류!",
"console_daemon_started": "데몬이 시작되었습니다",
"console_daemon_stopped": "데몬이 중지되었습니다",
"console_disconnected": "데몬 연결이 끊어졌습니다",
"console_errors": "오류",
"console_filter_hint": "출력 필터...",
"console_help_clear": " clear - 콘솔 지우기",
"console_help_getbalance": " getbalance - 투명 잔액 표시",
"console_help_getblockcount": " getblockcount - 현재 블록 높이 표시",
"console_help_getinfo": " getinfo - 노드 정보 표시",
"console_help_getmininginfo": " getmininginfo - 채굴 상태 표시",
"console_help_getpeerinfo": " getpeerinfo - 연결된 피어 표시",
"console_help_gettotalbalance": " gettotalbalance - 총 잔액 표시",
"console_help_help": " help - 도움말 표시",
"console_help_setgenerate": " setgenerate - 채굴 제어",
"console_help_stop": " stop - 데몬 중지",
"console_line_count": "%zu줄",
"console_new_lines": "%d 새 줄",
"console_no_daemon": "데몬 없음",
"console_not_connected": "오류: 데몬에 연결되지 않았습니다",
"console_rpc_reference": "RPC 명령어 참조",
"console_scanline": "콘솔 스캔라인",
"console_search_commands": "명령어 검색...",
"console_select_all": "모두 선택",
"console_show_daemon_output": "데몬 출력 표시",
"console_show_errors_only": "오류만 표시",
"console_show_rpc_ref": "RPC 명령어 참조 표시",
"console_showing_lines": "%zu / %zu줄 표시 중",
"console_starting_node": "노드 시작 중...",
"console_status_error": "오류",
"console_status_running": "실행 중",
"console_status_starting": "시작 중",
"console_status_stopped": "중지됨",
"console_status_stopping": "중지 중",
"console_status_unknown": "알 수 없음",
"console_tab_completion": "Tab으로 자동 완성",
"console_type_help": "'help'를 입력하여 사용 가능한 명령어 보기",
"console_welcome": "ObsidianDragon 콘솔에 오신 것을 환영합니다",
"console_zoom_in": "확대",
"console_zoom_out": "축소",
"copy": "복사",
"copy_address": "전체 주소 복사",
"copy_error": "오류 복사",
"copy_to_clipboard": "클립보드에 복사",
"copy_txid": "TxID 복사",
"copy_uri": "URI 복사",
"current_price": "현재 가격",
"custom_fees": "사용자 정의 수수료",
"dark": "다크",
"date": "날짜",
"date_label": "날짜:",
"delete": "삭제",
"difficulty": "난이도",
"disconnected": "연결 끊김",
"dismiss": "닫기",
"display": "디스플레이",
"dragonx_green": "DragonX(그린)",
"edit": "편집",
"error": "오류",
"est_time_to_block": "예상 블록 시간",
"exit": "종료",
"explorer": "탐색기",
"export": "내보내기",
"export_csv": "CSV 내보내기",
"export_keys_btn": "키 내보내기",
"export_keys_danger": "위험: 지갑의 모든 개인 키가 내보내집니다! 이 파일에 접근할 수 있는 사람은 누구나 자금을 훔칠 수 있습니다. 안전하게 보관하고 사용 후 삭제하세요.",
"export_keys_include_t": "T 주소 포함 (투명)",
"export_keys_include_z": "Z 주소 포함 (차폐)",
"export_keys_options": "내보내기 옵션:",
"export_keys_success": "키 내보내기 성공",
"export_keys_title": "모든 개인 키 내보내기",
"export_private_key": "개인 키 내보내기",
"export_tx_count": "%zu건의 거래를 CSV 파일로 내보냈습니다.",
"export_tx_file_fail": "CSV 파일 생성 실패",
"export_tx_none": "내보낼 거래가 없습니다",
"export_tx_success": "거래 내보내기 성공",
"export_tx_title": "거래를 CSV로 내보내기",
"export_viewing_key": "조회 키 내보내기",
"failed_create_shielded": "차폐 주소 생성 실패",
"failed_create_transparent": "투명 주소 생성 실패",
"fee": "수수료",
"fee_high": "높음",
"fee_label": "수수료:",
"fee_low": "낮음",
"fee_normal": "보통",
"fetch_prices": "가격 조회",
"file": "파일",
"file_save_location": "파일 저장 위치: ~/.config/ObsidianDragon/",
"font_scale": "글꼴 크기",
"from": "보낸 곳",
"from_upper": "보낸 곳",
"full_details": "전체 세부 정보",
"general": "일반",
"go_to_receive": "수신으로 이동",
"height": "높이",
"help": "도움말",
"hide": "숨기기",
"history": "내역",
"immature_type": "미성숙",
"import": "가져오기",
"import_key_btn": "키 가져오기",
"import_key_formats": "지원되는 키 형식:",
"import_key_full_rescan": "(0 = 전체 재스캔)",
"import_key_label": "개인 키:",
"import_key_no_valid": "입력에서 유효한 키를 찾을 수 없습니다",
"import_key_rescan": "가져오기 후 블록체인 재스캔",
"import_key_start_height": "시작 높이:",
"import_key_success": "키 가져오기 성공",
"import_key_t_format": "T 주소 WIF 개인 키",
"import_key_title": "개인 키 가져오기",
"import_key_tooltip": "한 줄에 하나의 개인 키를 입력하세요.\nz 주소와 t 주소 키 모두 지원됩니다.\n#으로 시작하는 줄은 주석으로 처리됩니다.",
"import_key_warning": "경고: 개인 키를 절대 공유하지 마세요! 신뢰할 수 없는 소스의 키를 가져오면 지갑이 위험해질 수 있습니다.",
"import_key_z_format": "Z 주소 지출 키 (secret-extended-key-...)",
"import_private_key": "개인 키 가져오기...",
"invalid_address": "잘못된 주소 형식",
"ip_address": "IP 주소",
"keep": "유지",
"keep_daemon": "데몬 계속 실행",
"key_export_fetching": "지갑에서 키를 가져오는 중...",
"key_export_private_key": "개인 키:",
"key_export_private_warning": "이 키를 비밀로 유지하세요! 이 키를 가진 사람은 누구나 자금을 사용할 수 있습니다. 온라인이나 신뢰할 수 없는 사람과 공유하지 마세요.",
"key_export_reveal": "키 표시",
"key_export_viewing_key": "조회 키:",
"key_export_viewing_warning": "이 조회 키를 사용하면 다른 사람이 수신 거래와 잔액을 볼 수 있지만 자금을 사용할 수는 없습니다. 신뢰할 수 있는 사람에게만 공유하세요.",
"label": "라벨:",
"language": "언어",
"light": "라이트",
"loading": "로딩 중...",
"loading_addresses": "주소 로딩 중...",
"local_hashrate": "로컬 해시레이트",
"low_spec_mode": "저사양 모드",
"market": "시장",
"market_12h": "12시간",
"market_18h": "18시간",
"market_24h": "24시간",
"market_24h_volume": "24시간 거래량",
"market_6h": "6시간",
"market_attribution": "가격 데이터: NonKYC 제공",
"market_btc_price": "BTC 가격",
"market_cap": "시가총액",
"market_no_history": "가격 내역 없음",
"market_no_price": "가격 데이터 없음",
"market_now": "현재",
"market_pct_shielded": "%.0f%% 차폐됨",
"market_portfolio": "포트폴리오",
"market_price_unavailable": "가격 데이터를 사용할 수 없습니다",
"market_refresh_price": "가격 데이터 새로고침",
"market_trade_on": "%s에서 거래",
"mature": "성숙됨",
"max": "최대",
"memo": "메모 (선택, 암호화)",
"memo_label": "메모:",
"memo_optional": "메모 (선택)",
"memo_upper": "메모",
"memo_z_only": "참고: 메모는 차폐 (z) 주소로 전송할 때만 사용할 수 있습니다",
"merge_description": "여러 UTXO를 단일 차폐 주소로 통합합니다. 지갑 크기를 줄이고 프라이버시를 향상시킵니다.",
"merge_funds": "자금 통합",
"merge_started": "통합 작업이 시작되었습니다",
"merge_title": "주소로 통합",
"mine_when_idle": "유휴 시 채굴",
"mined": "채굴됨",
"mined_filter": "채굴됨",
"mined_type": "채굴됨",
"mined_upper": "채굴됨",
"miner_fee": "채굴 수수료",
"mining": "채굴",
"mining_active": "활성",
"mining_address_copied": "채굴 주소가 복사되었습니다",
"mining_all_time": "전체 기간",
"mining_already_saved": "풀 URL이 이미 저장되어 있습니다",
"mining_block_copied": "블록 해시가 복사되었습니다",
"mining_chart_1m_ago": "1분 전",
"mining_chart_5m_ago": "5분 전",
"mining_chart_now": "현재",
"mining_chart_start": "시작",
"mining_click": "클릭",
"mining_click_copy_address": "클릭하여 주소 복사",
"mining_click_copy_block": "클릭하여 블록 해시 복사",
"mining_click_copy_difficulty": "클릭하여 난이도 복사",
"mining_connected": "연결됨",
"mining_connecting": "연결 중...",
"mining_control": "채굴 제어",
"mining_difficulty_copied": "난이도가 복사되었습니다",
"mining_est_block": "예상 블록",
"mining_est_daily": "예상 일일 수익",
"mining_filter_all": "전체",
"mining_filter_tip_all": "모든 수익 표시",
"mining_filter_tip_pool": "풀 수익만 표시",
"mining_filter_tip_solo": "솔로 수익만 표시",
"mining_idle_off_tooltip": "유휴 채굴 활성화",
"mining_idle_on_tooltip": "유휴 채굴 비활성화",
"mining_local_hashrate": "로컬 해시레이트",
"mining_mine": "채굴",
"mining_mining_addr": "채굴 주소",
"mining_network": "네트워크",
"mining_no_blocks_yet": "아직 블록을 찾지 못했습니다",
"mining_no_payouts_yet": "아직 풀 지급이 없습니다",
"mining_no_saved_addresses": "저장된 주소 없음",
"mining_no_saved_pools": "저장된 풀 없음",
"mining_off": "채굴이 꺼져 있습니다",
"mining_on": "채굴이 켜져 있습니다",
"mining_open_in_explorer": "탐색기에서 열기",
"mining_payout_address": "지급 주소",
"mining_payout_tooltip": "채굴 보상 수신 주소",
"mining_pool": "",
"mining_pool_hashrate": "풀 해시레이트",
"mining_pool_url": "풀 URL",
"mining_recent_blocks": "최근 블록",
"mining_recent_payouts": "최근 풀 지급",
"mining_remove": "제거",
"mining_reset_defaults": "기본값으로 재설정",
"mining_save_payout_address": "지급 주소 저장",
"mining_save_pool_url": "풀 URL 저장",
"mining_saved_addresses": "저장된 주소:",
"mining_saved_pools": "저장된 풀:",
"mining_shares": "셰어",
"mining_show_chart": "차트",
"mining_show_log": "로그",
"mining_solo": "솔로",
"mining_starting": "시작 중...",
"mining_starting_tooltip": "채굴기 시작 중...",
"mining_statistics": "채굴 통계",
"mining_stop": "중지",
"mining_stop_solo_for_pool": "풀 채굴을 시작하려면 솔로 채굴을 먼저 중지하세요",
"mining_stop_solo_for_pool_settings": "풀 설정을 변경하려면 솔로 채굴을 중지하세요",
"mining_stopping": "중지 중...",
"mining_stopping_tooltip": "채굴기 중지 중...",
"mining_syncing_tooltip": "블록체인 동기화 중...",
"mining_threads": "채굴 스레드",
"mining_to_save": "저장하려면",
"mining_today": "오늘",
"mining_uptime": "가동 시간",
"mining_yesterday": "어제",
"network": "네트워크",
"network_fee": "네트워크 수수료",
"network_hashrate": "네트워크 해시레이트",
"new": "+ 새로 만들기",
"new_shielded_created": "새 차폐 주소가 생성되었습니다",
"new_t_address": "새 T 주소",
"new_t_transparent": "새 t 주소 (투명)",
"new_transparent_created": "새 투명 주소가 생성되었습니다",
"new_z_address": "새 Z 주소",
"new_z_shielded": "새 z 주소 (차폐)",
"no_addresses": "주소가 없습니다. 위의 버튼을 사용하여 생성하세요.",
"no_addresses_available": "사용 가능한 주소 없음",
"no_addresses_match": "필터와 일치하는 주소가 없습니다",
"no_addresses_with_balance": "잔액이 있는 주소가 없습니다",
"no_matching": "일치하는 거래가 없습니다",
"no_recent_receives": "최근 수신 내역 없음",
"no_recent_sends": "최근 전송 내역 없음",
"no_transactions": "거래 내역이 없습니다",
"node": "노드",
"node_security": "노드 및 보안",
"noise": "노이즈",
"not_connected": "데몬에 연결되지 않음...",
"not_connected_to_daemon": "데몬에 연결되지 않음",
"notes": "메모",
"notes_optional": "메모 (선택):",
"output_filename": "출력 파일명:",
"overview": "개요",
"paste": "붙여넣기",
"paste_from_clipboard": "클립보드에서 붙여넣기",
"pay_from": "보낼 곳",
"payment_request": "결제 요청",
"payment_request_copied": "결제 요청이 복사되었습니다",
"payment_uri_copied": "결제 URI가 복사되었습니다",
"peers": "피어",
"peers_avg_ping": "평균 Ping",
"peers_ban_24h": "피어 24시간 차단",
"peers_ban_score": "차단 점수: %d",
"peers_banned": "차단됨",
"peers_banned_count": "차단됨: %d",
"peers_best_block": "최고 블록",
"peers_blockchain": "블록체인",
"peers_blocks": "블록",
"peers_blocks_left": "남은 블록: %d",
"peers_clear_all_bans": "모든 차단 해제",
"peers_click_copy": "클릭하여 복사",
"peers_connected": "연결됨",
"peers_connected_count": "연결됨: %d",
"peers_copy_ip": "IP 복사",
"peers_dir_in": "수신",
"peers_dir_out": "송신",
"peers_hash_copied": "해시가 복사되었습니다",
"peers_hashrate": "해시레이트",
"peers_in_out": "수신/송신",
"peers_longest": "최장",
"peers_longest_chain": "최장 체인",
"peers_memory": "메모리",
"peers_no_banned": "차단된 피어 없음",
"peers_no_connected": "연결된 피어 없음",
"peers_no_tls": "TLS 없음",
"peers_notarized": "공증됨",
"peers_p2p_port": "P2P 포트",
"peers_protocol": "프로토콜",
"peers_received": "수신됨",
"peers_refresh": "새로고침",
"peers_refresh_tooltip": "피어 목록 새로고침",
"peers_refreshing": "새로고침 중...",
"peers_sent": "전송됨",
"peers_tt_id": "ID: %d",
"peers_tt_received": "수신: %s",
"peers_tt_sent": "전송: %s",
"peers_tt_services": "서비스: %s",
"peers_tt_start_height": "시작 높이: %d",
"peers_tt_synced": "동기화 H/B: %d/%d",
"peers_tt_tls_cipher": "TLS: %s",
"peers_unban": "차단 해제",
"peers_upper": "피어",
"peers_version": "버전",
"pending": "대기 중",
"ping": "Ping",
"price_chart": "가격 차트",
"qr_code": "QR 코드",
"qr_failed": "QR 코드 생성 실패",
"qr_title": "QR 코드",
"qr_unavailable": "QR 사용 불가",
"receive": "수신",
"received": "수신됨",
"received_filter": "수신됨",
"received_label": "수신됨",
"received_upper": "수신됨",
"receiving_addresses": "수신 주소",
"recent_received": "최근 수신",
"recent_sends": "최근 전송",
"recipient": "수신자",
"recv_type": "수신",
"refresh": "새로고침",
"refresh_now": "지금 새로고침",
"report_bug": "버그 신고",
"request_amount": "금액 (선택):",
"request_copy_uri": "URI 복사",
"request_description": "다른 사람이 스캔하거나 복사할 수 있는 결제 요청을 생성합니다. QR 코드에는 주소와 선택적 금액/메모가 포함됩니다.",
"request_label": "라벨 (선택):",
"request_memo": "메모 (선택):",
"request_payment": "결제 요청",
"request_payment_uri": "결제 URI:",
"request_receive_address": "수신 주소:",
"request_select_address": "주소 선택...",
"request_shielded_addrs": "-- 차폐 주소 --",
"request_title": "결제 요청",
"request_transparent_addrs": "-- 투명 주소 --",
"request_uri_copied": "결제 URI가 클립보드에 복사되었습니다",
"rescan": "재스캔",
"reset_to_defaults": "기본값으로 재설정",
"review_send": "전송 검토",
"rpc_host": "RPC 호스트",
"rpc_pass": "비밀번호",
"rpc_port": "포트",
"rpc_user": "사용자명",
"save": "저장",
"save_settings": "설정 저장",
"save_z_transactions": "Z 거래를 거래 목록에 저장",
"search_placeholder": "검색...",
"security": "보안",
"select_address": "주소 선택...",
"select_receiving_address": "수신 주소 선택...",
"select_source_address": "보낼 주소 선택...",
"send": "전송",
"send_amount": "금액",
"send_amount_details": "금액 상세",
"send_amount_upper": "금액",
"send_clear_fields": "모든 양식 필드를 지우시겠습니까?",
"send_copy_error": "오류 복사",
"send_dismiss": "닫기",
"send_error_copied": "오류가 클립보드에 복사되었습니다",
"send_error_prefix": "오류: %s",
"send_exceeds_available": "사용 가능 금액 초과 (%.8f)",
"send_fee": "수수료",
"send_fee_high": "높음",
"send_fee_low": "낮음",
"send_fee_normal": "보통",
"send_form_restored": "양식이 복원되었습니다",
"send_from_this_address": "이 주소에서 전송",
"send_go_to_receive": "수신으로 이동",
"send_keep": "유지",
"send_network_fee": "네트워크 수수료",
"send_no_balance": "잔액 없음",
"send_no_recent": "최근 전송 없음",
"send_recent_sends": "최근 전송",
"send_recipient": "수신자",
"send_select_source": "보낼 주소 선택...",
"send_sending_from": "보내는 곳",
"send_submitting": "거래 제출 중...",
"send_switch_to_receive": "수신으로 전환하여 주소를 받고 자금 수신을 시작하세요.",
"send_to": "받는 곳",
"send_tooltip_enter_amount": "전송할 금액을 입력하세요",
"send_tooltip_exceeds_balance": "금액이 사용 가능 잔액을 초과합니다",
"send_tooltip_in_progress": "거래가 이미 진행 중입니다",
"send_tooltip_invalid_address": "유효한 수신자 주소를 입력하세요",
"send_tooltip_not_connected": "데몬에 연결되지 않음",
"send_tooltip_select_source": "먼저 보낼 주소를 선택하세요",
"send_tooltip_syncing": "블록체인 동기화를 기다려 주세요",
"send_total": "합계",
"send_transaction": "거래 전송",
"send_tx_failed": "거래 실패",
"send_tx_sent": "거래가 전송되었습니다!",
"send_tx_success": "거래 전송 성공!",
"send_txid_copied": "TxID가 클립보드에 복사되었습니다",
"send_txid_label": "TxID: %s",
"send_valid_shielded": "유효한 차폐 주소",
"send_valid_transparent": "유효한 투명 주소",
"send_wallet_empty": "지갑이 비어 있습니다",
"send_yes_clear": "예, 지우기",
"sending": "거래 전송 중",
"sending_from": "보내는 곳",
"sent": "전송됨",
"sent_filter": "전송됨",
"sent_type": "전송됨",
"sent_upper": "전송됨",
"settings": "설정",
"setup_wizard": "설정 마법사",
"share": "공유",
"shield_check_status": "상태 확인",
"shield_completed": "작업이 성공적으로 완료되었습니다!",
"shield_description": "투명 주소의 코인베이스 출력을 차폐 주소로 전송하여 채굴 보상을 차폐합니다. 채굴 수입을 숨겨 프라이버시가 향상됩니다.",
"shield_from_address": "보내는 주소:",
"shield_funds": "자금 차폐",
"shield_in_progress": "작업 진행 중...",
"shield_max_utxos": "작업당 최대 UTXO 수",
"shield_merge_done": "차폐/통합이 완료되었습니다!",
"shield_select_z": "z 주소 선택...",
"shield_started": "차폐 작업이 시작되었습니다",
"shield_title": "코인베이스 보상 차폐",
"shield_to_address": "받는 주소 (차폐):",
"shield_utxo_limit": "UTXO 제한:",
"shield_wildcard_hint": "'*'를 사용하여 모든 투명 주소에서 차폐",
"shielded": "차폐",
"shielded_to": "차폐 대상",
"shielded_type": "차폐",
"show": "표시",
"show_qr_code": "QR 코드 표시",
"showing_transactions": "%d\xe2\x80\x93%d / %d건의 거래 표시 중 (총: %zu)",
"simple_background": "단순 배경",
"start_mining": "채굴 시작",
"status": "상태",
"stop_external": "외부 데몬 중지",
"stop_mining": "채굴 중지",
"submitting_transaction": "거래 제출 중...",
"success": "성공",
"summary": "요약",
"syncing": "동기화 중...",
"t_addresses": "T 주소",
"test_connection": "테스트",
"theme": "테마",
"theme_effects": "테마 효과",
"time_days_ago": "%d일 전",
"time_hours_ago": "%d시간 전",
"time_minutes_ago": "%d분 전",
"time_seconds_ago": "%d초 전",
"to": "받는 곳",
"to_upper": "받는 곳",
"tools": "도구",
"total": "합계",
"transaction_id": "거래 ID",
"transaction_sent": "거래 전송 성공",
"transaction_sent_msg": "거래가 전송되었습니다!",
"transaction_url": "거래 URL",
"transactions": "거래",
"transactions_upper": "거래",
"transparent": "투명",
"tx_confirmations": "%d 확인",
"tx_details_title": "거래 상세",
"tx_from_address": "보낸 주소:",
"tx_id_label": "거래 ID:",
"tx_immature": "미성숙",
"tx_mined": "채굴됨",
"tx_received": "수신됨",
"tx_sent": "전송됨",
"tx_to_address": "받는 주소:",
"tx_view_explorer": "탐색기에서 보기",
"txs_count": "%d",
"type": "유형",
"ui_opacity": "UI 투명도",
"unban": "차단 해제",
"unconfirmed": "미확인",
"undo_clear": "지우기 취소",
"unknown": "알 수 없음",
"use_embedded_daemon": "내장 dragonxd 사용",
"use_tor": "Tor 사용",
"validate_btn": "검증",
"validate_description": "DragonX 주소를 입력하여 유효한지 그리고 이 지갑에 속하는지 확인합니다.",
"validate_invalid": "유효하지 않음",
"validate_is_mine": "이 지갑이 이 주소를 소유합니다",
"validate_not_mine": "이 지갑에 속하지 않음",
"validate_ownership": "소유자:",
"validate_results": "결과:",
"validate_shielded_type": "차폐 (z 주소)",
"validate_status": "상태:",
"validate_title": "주소 검증",
"validate_transparent_type": "투명 (t 주소)",
"validate_type": "유형:",
"validate_valid": "유효함",
"validating": "검증 중...",
"verbose_logging": "상세 로깅",
"version": "버전",
"view": "보기",
"view_details": "상세 보기",
"view_on_explorer": "탐색기에서 보기",
"waiting_for_daemon": "데몬 연결 대기 중...",
"wallet": "지갑",
"wallet_empty": "지갑이 비어 있습니다",
"wallet_empty_hint": "수신으로 전환하여 주소를 받고 자금 수신을 시작하세요.",
"warning": "경고",
"warning_upper": "경고!",
"website": "웹사이트",
"window_opacity": "창 투명도",
"yes_clear": "예, 지우기",
"your_addresses": "내 주소",
"z_addresses": "Z 주소",
}
out = os.path.join(os.path.dirname(__file__), "..", "res", "lang", "ko.json")
with open(out, "w", encoding="utf-8") as f:
json.dump(translations, f, indent=4, ensure_ascii=False, sort_keys=True)
print(f"Wrote {len(translations)} Korean translations to {os.path.abspath(out)}")

View File

@@ -1,646 +0,0 @@
#!/usr/bin/env python3
"""Generate Portuguese (pt) translations for ObsidianDragon wallet."""
import json, os
translations = {
"24h_change": "Variação 24h",
"24h_volume": "Volume 24h",
"about": "Sobre",
"about_block_explorer": "Explorador de Blocos",
"about_block_height": "Altura do Bloco:",
"about_build_date": "Data de Compilação:",
"about_build_type": "Tipo de Build:",
"about_chain": "Chain:",
"about_connections": "Conexões:",
"about_credits": "Créditos",
"about_daemon": "Daemon:",
"about_debug": "Depuração",
"about_dragonx": "Sobre o ObsidianDragon",
"about_edition": "Edição ImGui",
"about_github": "GitHub",
"about_imgui": "ImGui:",
"about_license": "Licença",
"about_license_text": "Este software é disponibilizado sob a Licença Pública Geral GNU v3 (GPLv3). Você é livre para usar, modificar e distribuir este software sob os termos da licença.",
"about_peers_count": "%zu pares",
"about_release": "Versão",
"about_title": "Sobre o ObsidianDragon",
"about_version": "Versão:",
"about_website": "Website",
"acrylic": "Acrílico",
"add": "Adicionar",
"address": "Endereço",
"address_book_add": "Adicionar Endereço",
"address_book_add_new": "Adicionar Novo",
"address_book_added": "Endereço adicionado ao livro",
"address_book_count": "%zu endereços salvos",
"address_book_deleted": "Entrada excluída",
"address_book_edit": "Editar Endereço",
"address_book_empty": "Nenhum endereço salvo. Clique em 'Adicionar Novo' para criar um.",
"address_book_exists": "Endereço já existe no livro",
"address_book_title": "Livro de Endereços",
"address_book_update_failed": "Falha na atualização - endereço pode ser duplicado",
"address_book_updated": "Endereço atualizado",
"address_copied": "Endereço copiado para a área de transferência",
"address_details": "Detalhes do Endereço",
"address_label": "Endereço:",
"address_upper": "ENDEREÇO",
"address_url": "URL do Endereço",
"addresses_appear_here": "Seus endereços de recebimento aparecerão aqui após a conexão.",
"advanced": "AVANÇADO",
"all_filter": "Todos",
"allow_custom_fees": "Permitir taxas personalizadas",
"amount": "Valor",
"amount_details": "DETALHES DO VALOR",
"amount_exceeds_balance": "Valor excede o saldo",
"amount_label": "Valor:",
"appearance": "APARÊNCIA",
"auto_shield": "Auto-blindar mineração",
"available": "Disponível",
"backup_backing_up": "Fazendo backup...",
"backup_create": "Criar Backup",
"backup_created": "Backup da carteira criado",
"backup_data": "BACKUP & DADOS",
"backup_description": "Crie um backup do seu arquivo wallet.dat. Este arquivo contém todas as suas chaves privadas e histórico de transações. Guarde o backup em um local seguro.",
"backup_destination": "Destino do backup:",
"backup_tip_external": "Armazene backups em unidades externas ou armazenamento em nuvem",
"backup_tip_multiple": "Crie múltiplos backups em diferentes locais",
"backup_tip_test": "Teste a restauração do backup periodicamente",
"backup_tips": "Dicas:",
"backup_title": "Backup da Carteira",
"backup_wallet": "Fazer Backup da Carteira...",
"backup_wallet_not_found": "Aviso: wallet.dat não encontrado no local esperado",
"balance": "Saldo",
"balance_layout": "Layout do Saldo",
"ban": "Banir",
"banned_peers": "Pares Banidos",
"block": "Bloco",
"block_bits": "Bits:",
"block_click_next": "Clique para ver o próximo bloco",
"block_click_prev": "Clique para ver o bloco anterior",
"block_explorer": "Explorador de Blocos",
"block_get_info": "Obter Info do Bloco",
"block_hash": "Hash do Bloco:",
"block_height": "Altura do Bloco:",
"block_info_title": "Informações do Bloco",
"block_merkle_root": "Raiz Merkle:",
"block_nav_next": "Próximo >>",
"block_nav_prev": "<< Anterior",
"block_next": "Próximo Bloco:",
"block_previous": "Bloco Anterior:",
"block_size": "Tamanho:",
"block_timestamp": "Carimbo de Data:",
"block_transactions": "Transações:",
"blockchain_syncing": "Blockchain sincronizando (%.1f%%)... Os saldos podem ser imprecisos.",
"cancel": "Cancelar",
"characters": "caracteres",
"clear": "Limpar",
"clear_all_bans": "Remover Todos os Banimentos",
"clear_form_confirm": "Limpar todos os campos do formulário?",
"clear_request": "Limpar Solicitação",
"click_copy_address": "Clique para copiar o endereço",
"click_copy_uri": "Clique para copiar a URI",
"close": "Fechar",
"conf_count": "%d conf.",
"confirm_and_send": "Confirmar & Enviar",
"confirm_send": "Confirmar Envio",
"confirm_transaction": "Confirmar Transação",
"confirmations": "Confirmações",
"confirmations_display": "%d confirmações | %s",
"confirmed": "Confirmado",
"connected": "Conectado",
"connected_peers": "Pares Conectados",
"connecting": "Conectando...",
"console": "Console",
"console_auto_scroll": "Rolagem automática",
"console_available_commands": "Comandos disponíveis:",
"console_capturing_output": "Capturando saída do daemon...",
"console_clear": "Limpar",
"console_clear_console": "Limpar Console",
"console_cleared": "Console limpo",
"console_click_commands": "Clique nos comandos acima para inseri-los",
"console_click_insert": "Clique para inserir",
"console_click_insert_params": "Clique para inserir com parâmetros",
"console_close": "Fechar",
"console_commands": "Comandos",
"console_common_rpc": "Comandos RPC comuns:",
"console_completions": "Completações:",
"console_connected": "Conectado ao daemon",
"console_copy_all": "Copiar Tudo",
"console_copy_selected": "Copiar",
"console_daemon": "Daemon",
"console_daemon_error": "Erro do daemon!",
"console_daemon_started": "Daemon iniciado",
"console_daemon_stopped": "Daemon parado",
"console_disconnected": "Desconectado do daemon",
"console_errors": "Erros",
"console_filter_hint": "Filtrar saída...",
"console_help_clear": " clear - Limpar o console",
"console_help_getbalance": " getbalance - Mostrar saldo transparente",
"console_help_getblockcount": " getblockcount - Mostrar altura atual do bloco",
"console_help_getinfo": " getinfo - Mostrar informações do nó",
"console_help_getmininginfo": " getmininginfo - Mostrar status da mineração",
"console_help_getpeerinfo": " getpeerinfo - Mostrar pares conectados",
"console_help_gettotalbalance": " gettotalbalance - Mostrar saldo total",
"console_help_help": " help - Mostrar esta mensagem de ajuda",
"console_help_setgenerate": " setgenerate - Controlar mineração",
"console_help_stop": " stop - Parar o daemon",
"console_line_count": "%zu linhas",
"console_new_lines": "%d novas linhas",
"console_no_daemon": "Sem daemon",
"console_not_connected": "Erro: Não conectado ao daemon",
"console_rpc_reference": "Referência de Comandos RPC",
"console_scanline": "Scanline do console",
"console_search_commands": "Pesquisar comandos...",
"console_select_all": "Selecionar Tudo",
"console_show_daemon_output": "Mostrar saída do daemon",
"console_show_errors_only": "Mostrar apenas erros",
"console_show_rpc_ref": "Mostrar referência de comandos RPC",
"console_showing_lines": "Mostrando %zu de %zu linhas",
"console_starting_node": "Iniciando nó...",
"console_status_error": "Erro",
"console_status_running": "Em execução",
"console_status_starting": "Iniciando",
"console_status_stopped": "Parado",
"console_status_stopping": "Parando",
"console_status_unknown": "Desconhecido",
"console_tab_completion": "Tab para completar",
"console_type_help": "Digite 'help' para comandos disponíveis",
"console_welcome": "Bem-vindo ao Console ObsidianDragon",
"console_zoom_in": "Aumentar zoom",
"console_zoom_out": "Diminuir zoom",
"copy": "Copiar",
"copy_address": "Copiar Endereço Completo",
"copy_error": "Copiar Erro",
"copy_to_clipboard": "Copiar para Área de Transferência",
"copy_txid": "Copiar TxID",
"copy_uri": "Copiar URI",
"current_price": "Preço Atual",
"custom_fees": "Taxas personalizadas",
"dark": "Escuro",
"date": "Data",
"date_label": "Data:",
"delete": "Excluir",
"difficulty": "Dificuldade",
"disconnected": "Desconectado",
"dismiss": "Dispensar",
"display": "Exibição",
"dragonx_green": "DragonX (Verde)",
"edit": "Editar",
"error": "Erro",
"est_time_to_block": "Tempo Est. por Bloco",
"exit": "Sair",
"explorer": "EXPLORADOR",
"export": "Exportar",
"export_csv": "Exportar CSV",
"export_keys_btn": "Exportar Chaves",
"export_keys_danger": "PERIGO: Isto exportará TODAS as chaves privadas da sua carteira! Qualquer pessoa com acesso a este arquivo pode roubar seus fundos. Guarde com segurança e exclua após o uso.",
"export_keys_include_t": "Incluir endereços T (transparentes)",
"export_keys_include_z": "Incluir endereços Z (blindados)",
"export_keys_options": "Opções de exportação:",
"export_keys_success": "Chaves exportadas com sucesso",
"export_keys_title": "Exportar Todas as Chaves Privadas",
"export_private_key": "Exportar Chave Privada",
"export_tx_count": "Exportar %zu transações para arquivo CSV.",
"export_tx_file_fail": "Falha ao criar arquivo CSV",
"export_tx_none": "Nenhuma transação para exportar",
"export_tx_success": "Transações exportadas com sucesso",
"export_tx_title": "Exportar Transações para CSV",
"export_viewing_key": "Exportar Chave de Visualização",
"failed_create_shielded": "Falha ao criar endereço blindado",
"failed_create_transparent": "Falha ao criar endereço transparente",
"fee": "Taxa",
"fee_high": "Alta",
"fee_label": "Taxa:",
"fee_low": "Baixa",
"fee_normal": "Normal",
"fetch_prices": "Buscar preços",
"file": "Arquivo",
"file_save_location": "O arquivo será salvo em: ~/.config/ObsidianDragon/",
"font_scale": "Escala da Fonte",
"from": "De",
"from_upper": "DE",
"full_details": "Detalhes Completos",
"general": "Geral",
"go_to_receive": "Ir para Receber",
"height": "Altura",
"help": "Ajuda",
"hide": "Ocultar",
"history": "Histórico",
"immature_type": "Imaturo",
"import": "Importar",
"import_key_btn": "Importar Chave(s)",
"import_key_formats": "Formatos de chave suportados:",
"import_key_full_rescan": "(0 = rescan completo)",
"import_key_label": "Chave(s) Privada(s):",
"import_key_no_valid": "Nenhuma chave válida encontrada na entrada",
"import_key_rescan": "Reescanear blockchain após importação",
"import_key_start_height": "Altura inicial:",
"import_key_success": "Chaves importadas com sucesso",
"import_key_t_format": "Chaves privadas WIF de endereços T",
"import_key_title": "Importar Chave Privada",
"import_key_tooltip": "Digite uma ou mais chaves privadas, uma por linha.\nSuporta chaves de z-endereço e t-endereço.\nLinhas começando com # são tratadas como comentários.",
"import_key_warning": "Aviso: Nunca compartilhe suas chaves privadas! Importar chaves de fontes não confiáveis pode comprometer sua carteira.",
"import_key_z_format": "Chaves de gasto de z-endereço (secret-extended-key-...)",
"import_private_key": "Importar Chave Privada...",
"invalid_address": "Formato de endereço inválido",
"ip_address": "Endereço IP",
"keep": "Manter",
"keep_daemon": "Manter daemon em execução",
"key_export_fetching": "Buscando chave da carteira...",
"key_export_private_key": "Chave Privada:",
"key_export_private_warning": "Mantenha esta chave em SEGREDO! Qualquer pessoa com esta chave pode gastar seus fundos. Nunca a compartilhe online ou com terceiros não confiáveis.",
"key_export_reveal": "Revelar Chave",
"key_export_viewing_key": "Chave de Visualização:",
"key_export_viewing_warning": "Esta chave de visualização permite que outros vejam suas transações recebidas e saldo, mas NÃO gastem seus fundos. Compartilhe apenas com partes confiáveis.",
"label": "Rótulo:",
"language": "Idioma",
"light": "Claro",
"loading": "Carregando...",
"loading_addresses": "Carregando endereços...",
"local_hashrate": "Hashrate Local",
"low_spec_mode": "Modo econômico",
"market": "Mercado",
"market_12h": "12h",
"market_18h": "18h",
"market_24h": "24h",
"market_24h_volume": "VOLUME 24H",
"market_6h": "6h",
"market_attribution": "Dados de preço do NonKYC",
"market_btc_price": "PREÇO BTC",
"market_cap": "Capitalização",
"market_no_history": "Nenhum histórico de preços disponível",
"market_no_price": "Sem dados de preço",
"market_now": "Agora",
"market_pct_shielded": "%.0f%% Blindado",
"market_portfolio": "PORTFÓLIO",
"market_price_unavailable": "Dados de preço indisponíveis",
"market_refresh_price": "Atualizar dados de preço",
"market_trade_on": "Negociar no %s",
"mature": "Maduro",
"max": "Máx",
"memo": "Memo (opcional, criptografado)",
"memo_label": "Memo:",
"memo_optional": "MEMO (OPCIONAL)",
"memo_upper": "MEMO",
"memo_z_only": "Nota: Memos só estão disponíveis ao enviar para endereços blindados (z)",
"merge_description": "Fundir múltiplos UTXOs em um único endereço blindado. Isso pode ajudar a reduzir o tamanho da carteira e melhorar a privacidade.",
"merge_funds": "Fundir Fundos",
"merge_started": "Operação de fusão iniciada",
"merge_title": "Fundir para Endereço",
"mine_when_idle": "Minerar quando ocioso",
"mined": "minerado",
"mined_filter": "Minerado",
"mined_type": "Minerado",
"mined_upper": "MINERADO",
"miner_fee": "Taxa de Minerador",
"mining": "Mineração",
"mining_active": "Ativo",
"mining_address_copied": "Endereço de mineração copiado",
"mining_all_time": "Todo o Tempo",
"mining_already_saved": "URL do pool já salva",
"mining_block_copied": "Hash do bloco copiado",
"mining_chart_1m_ago": "1m atrás",
"mining_chart_5m_ago": "5m atrás",
"mining_chart_now": "Agora",
"mining_chart_start": "Início",
"mining_click": "Clique",
"mining_click_copy_address": "Clique para copiar o endereço",
"mining_click_copy_block": "Clique para copiar o hash do bloco",
"mining_click_copy_difficulty": "Clique para copiar a dificuldade",
"mining_connected": "Conectado",
"mining_connecting": "Conectando...",
"mining_control": "Controle de Mineração",
"mining_difficulty_copied": "Dificuldade copiada",
"mining_est_block": "Bloco Est.",
"mining_est_daily": "Est. Diário",
"mining_filter_all": "Todos",
"mining_filter_tip_all": "Mostrar todos os ganhos",
"mining_filter_tip_pool": "Mostrar apenas ganhos do pool",
"mining_filter_tip_solo": "Mostrar apenas ganhos solo",
"mining_idle_off_tooltip": "Ativar mineração ociosa",
"mining_idle_on_tooltip": "Desativar mineração ociosa",
"mining_local_hashrate": "Hashrate Local",
"mining_mine": "Minerar",
"mining_mining_addr": "End. Mineração",
"mining_network": "Rede",
"mining_no_blocks_yet": "Nenhum bloco encontrado ainda",
"mining_no_payouts_yet": "Nenhum pagamento de pool ainda",
"mining_no_saved_addresses": "Nenhum endereço salvo",
"mining_no_saved_pools": "Nenhum pool salvo",
"mining_off": "Mineração está DESLIGADA",
"mining_on": "Mineração está LIGADA",
"mining_open_in_explorer": "Abrir no explorador",
"mining_payout_address": "Endereço de Pagamento",
"mining_payout_tooltip": "Endereço para receber recompensas de mineração",
"mining_pool": "Pool",
"mining_pool_hashrate": "Hashrate do Pool",
"mining_pool_url": "URL do Pool",
"mining_recent_blocks": "BLOCOS RECENTES",
"mining_recent_payouts": "PAGAMENTOS DE POOL RECENTES",
"mining_remove": "Remover",
"mining_reset_defaults": "Redefinir Padrões",
"mining_save_payout_address": "Salvar endereço de pagamento",
"mining_save_pool_url": "Salvar URL do pool",
"mining_saved_addresses": "Endereços Salvos:",
"mining_saved_pools": "Pools Salvos:",
"mining_shares": "Shares",
"mining_show_chart": "Gráfico",
"mining_show_log": "Log",
"mining_solo": "Solo",
"mining_starting": "Iniciando...",
"mining_starting_tooltip": "Minerador está iniciando...",
"mining_statistics": "Estatísticas de Mineração",
"mining_stop": "Parar",
"mining_stop_solo_for_pool": "Pare a mineração solo antes de iniciar a mineração em pool",
"mining_stop_solo_for_pool_settings": "Pare a mineração solo para alterar as configurações do pool",
"mining_stopping": "Parando...",
"mining_stopping_tooltip": "Minerador está parando...",
"mining_syncing_tooltip": "Blockchain está sincronizando...",
"mining_threads": "Threads de Mineração",
"mining_to_save": "para salvar",
"mining_today": "Hoje",
"mining_uptime": "Tempo Ativo",
"mining_yesterday": "Ontem",
"network": "Rede",
"network_fee": "TAXA DA REDE",
"network_hashrate": "Hashrate da Rede",
"new": "+ Novo",
"new_shielded_created": "Novo endereço blindado criado",
"new_t_address": "Novo Endereço T",
"new_t_transparent": "Novo endereço t (Transparente)",
"new_transparent_created": "Novo endereço transparente criado",
"new_z_address": "Novo Endereço Z",
"new_z_shielded": "Novo endereço z (Blindado)",
"no_addresses": "Nenhum endereço encontrado. Crie um usando os botões acima.",
"no_addresses_available": "Nenhum endereço disponível",
"no_addresses_match": "Nenhum endereço corresponde ao filtro",
"no_addresses_with_balance": "Nenhum endereço com saldo",
"no_matching": "Nenhuma transação correspondente",
"no_recent_receives": "Nenhum recebimento recente",
"no_recent_sends": "Nenhum envio recente",
"no_transactions": "Nenhuma transação encontrada",
"node": "",
"node_security": "NÓ & SEGURANÇA",
"noise": "Ruído",
"not_connected": "Não conectado ao daemon...",
"not_connected_to_daemon": "Não conectado ao daemon",
"notes": "Notas",
"notes_optional": "Notas (opcional):",
"output_filename": "Nome do arquivo de saída:",
"overview": "Visão Geral",
"paste": "Colar",
"paste_from_clipboard": "Colar da Área de Transferência",
"pay_from": "Pagar de",
"payment_request": "SOLICITAÇÃO DE PAGAMENTO",
"payment_request_copied": "Solicitação de pagamento copiada",
"payment_uri_copied": "URI de pagamento copiada",
"peers": "Pares",
"peers_avg_ping": "Ping Médio",
"peers_ban_24h": "Banir Par 24h",
"peers_ban_score": "Score de Ban: %d",
"peers_banned": "Banidos",
"peers_banned_count": "Banidos: %d",
"peers_best_block": "Melhor Bloco",
"peers_blockchain": "BLOCKCHAIN",
"peers_blocks": "Blocos",
"peers_blocks_left": "%d blocos restantes",
"peers_clear_all_bans": "Remover Todos os Banimentos",
"peers_click_copy": "Clique para copiar",
"peers_connected": "Conectados",
"peers_connected_count": "Conectados: %d",
"peers_copy_ip": "Copiar IP",
"peers_dir_in": "Ent.",
"peers_dir_out": "Saí.",
"peers_hash_copied": "Hash copiado",
"peers_hashrate": "Hashrate",
"peers_in_out": "Ent./Saí.",
"peers_longest": "Mais longa",
"peers_longest_chain": "Chain Mais Longa",
"peers_memory": "Memória",
"peers_no_banned": "Nenhum par banido",
"peers_no_connected": "Nenhum par conectado",
"peers_no_tls": "Sem TLS",
"peers_notarized": "Notarizado",
"peers_p2p_port": "Porta P2P",
"peers_protocol": "Protocolo",
"peers_received": "Recebido",
"peers_refresh": "Atualizar",
"peers_refresh_tooltip": "Atualizar lista de pares",
"peers_refreshing": "Atualizando...",
"peers_sent": "Enviado",
"peers_tt_id": "ID: %d",
"peers_tt_received": "Recebido: %s",
"peers_tt_sent": "Enviado: %s",
"peers_tt_services": "Serviços: %s",
"peers_tt_start_height": "Altura Inicial: %d",
"peers_tt_synced": "Sincronizado H/B: %d/%d",
"peers_tt_tls_cipher": "TLS: %s",
"peers_unban": "Desbanir",
"peers_upper": "PARES",
"peers_version": "Versão",
"pending": "Pendente",
"ping": "Ping",
"price_chart": "Gráfico de Preços",
"qr_code": "Código QR",
"qr_failed": "Falha ao gerar código QR",
"qr_title": "Código QR",
"qr_unavailable": "QR indisponível",
"receive": "Receber",
"received": "recebido",
"received_filter": "Recebido",
"received_label": "Recebido",
"received_upper": "RECEBIDO",
"receiving_addresses": "Seus Endereços de Recebimento",
"recent_received": "RECEBIDOS RECENTES",
"recent_sends": "ENVIOS RECENTES",
"recipient": "DESTINATÁRIO",
"recv_type": "Receb.",
"refresh": "Atualizar",
"refresh_now": "Atualizar Agora",
"report_bug": "Reportar Bug",
"request_amount": "Valor (opcional):",
"request_copy_uri": "Copiar URI",
"request_description": "Gere uma solicitação de pagamento que outros podem escanear ou copiar. O código QR contém seu endereço e valor/memo opcionais.",
"request_label": "Rótulo (opcional):",
"request_memo": "Memo (opcional):",
"request_payment": "Solicitar Pagamento",
"request_payment_uri": "URI de Pagamento:",
"request_receive_address": "Endereço de Recebimento:",
"request_select_address": "Selecionar endereço...",
"request_shielded_addrs": "-- Endereços Blindados --",
"request_title": "Solicitar Pagamento",
"request_transparent_addrs": "-- Endereços Transparentes --",
"request_uri_copied": "URI de pagamento copiada para a área de transferência",
"rescan": "Reescanear",
"reset_to_defaults": "Redefinir Padrões",
"review_send": "Revisar Envio",
"rpc_host": "Host RPC",
"rpc_pass": "Senha",
"rpc_port": "Porta",
"rpc_user": "Usuário",
"save": "Salvar",
"save_settings": "Salvar Configurações",
"save_z_transactions": "Salvar Z-tx na lista de tx",
"search_placeholder": "Pesquisar...",
"security": "SEGURANÇA",
"select_address": "Selecionar endereço...",
"select_receiving_address": "Selecionar endereço de recebimento...",
"select_source_address": "Selecionar endereço de origem...",
"send": "Enviar",
"send_amount": "Valor",
"send_amount_details": "DETALHES DO VALOR",
"send_amount_upper": "VALOR",
"send_clear_fields": "Limpar todos os campos do formulário?",
"send_copy_error": "Copiar Erro",
"send_dismiss": "Dispensar",
"send_error_copied": "Erro copiado para a área de transferência",
"send_error_prefix": "Erro: %s",
"send_exceeds_available": "Excede o disponível (%.8f)",
"send_fee": "Taxa",
"send_fee_high": "Alta",
"send_fee_low": "Baixa",
"send_fee_normal": "Normal",
"send_form_restored": "Formulário restaurado",
"send_from_this_address": "Enviar deste endereço",
"send_go_to_receive": "Ir para Receber",
"send_keep": "Manter",
"send_network_fee": "TAXA DA REDE",
"send_no_balance": "Sem saldo",
"send_no_recent": "Nenhum envio recente",
"send_recent_sends": "ENVIOS RECENTES",
"send_recipient": "DESTINATÁRIO",
"send_select_source": "Selecionar endereço de origem...",
"send_sending_from": "ENVIANDO DE",
"send_submitting": "Enviando transação...",
"send_switch_to_receive": "Mude para Receber para obter seu endereço e começar a receber fundos.",
"send_to": "Enviar para",
"send_tooltip_enter_amount": "Digite um valor para enviar",
"send_tooltip_exceeds_balance": "Valor excede o saldo disponível",
"send_tooltip_in_progress": "Transação já em andamento",
"send_tooltip_invalid_address": "Digite um endereço de destinatário válido",
"send_tooltip_not_connected": "Não conectado ao daemon",
"send_tooltip_select_source": "Selecione primeiro um endereço de origem",
"send_tooltip_syncing": "Aguarde a sincronização da blockchain",
"send_total": "Total",
"send_transaction": "Enviar Transação",
"send_tx_failed": "Transação falhou",
"send_tx_sent": "Transação enviada!",
"send_tx_success": "Transação enviada com sucesso!",
"send_txid_copied": "TxID copiado para a área de transferência",
"send_txid_label": "TxID: %s",
"send_valid_shielded": "Endereço blindado válido",
"send_valid_transparent": "Endereço transparente válido",
"send_wallet_empty": "Sua carteira está vazia",
"send_yes_clear": "Sim, Limpar",
"sending": "Enviando transação",
"sending_from": "ENVIANDO DE",
"sent": "enviado",
"sent_filter": "Enviado",
"sent_type": "Enviado",
"sent_upper": "ENVIADO",
"settings": "Configurações",
"setup_wizard": "Assistente de Configuração",
"share": "Compartilhar",
"shield_check_status": "Verificar Status",
"shield_completed": "Operação concluída com sucesso!",
"shield_description": "Blinde suas recompensas de mineração enviando saídas coinbase de endereços transparentes para um endereço blindado. Isso melhora a privacidade ocultando sua renda de mineração.",
"shield_from_address": "Do Endereço:",
"shield_funds": "Blindar Fundos",
"shield_in_progress": "Operação em andamento...",
"shield_max_utxos": "Máx. UTXOs por operação",
"shield_merge_done": "Blindagem/fusão concluída!",
"shield_select_z": "Selecionar z-endereço...",
"shield_started": "Operação de blindagem iniciada",
"shield_title": "Blindar Recompensas Coinbase",
"shield_to_address": "Para Endereço (Blindado):",
"shield_utxo_limit": "Limite UTXO:",
"shield_wildcard_hint": "Use '*' para blindar de todos os endereços transparentes",
"shielded": "Blindado",
"shielded_to": "BLINDADO PARA",
"shielded_type": "Blindado",
"show": "Mostrar",
"show_qr_code": "Mostrar Código QR",
"showing_transactions": "Mostrando %d\xe2\x80\x93%d de %d transações (total: %zu)",
"simple_background": "Fundo simples",
"start_mining": "Iniciar Mineração",
"status": "Status",
"stop_external": "Parar daemon externo",
"stop_mining": "Parar Mineração",
"submitting_transaction": "Enviando transação...",
"success": "Sucesso",
"summary": "Resumo",
"syncing": "Sincronizando...",
"t_addresses": "Endereços T",
"test_connection": "Testar",
"theme": "Tema",
"theme_effects": "Efeitos de tema",
"time_days_ago": "%d dias",
"time_hours_ago": "%d horas",
"time_minutes_ago": "%d minutos",
"time_seconds_ago": "%d segundos",
"to": "Para",
"to_upper": "PARA",
"tools": "FERRAMENTAS",
"total": "Total",
"transaction_id": "ID DA TRANSAÇÃO",
"transaction_sent": "Transação enviada com sucesso",
"transaction_sent_msg": "Transação enviada!",
"transaction_url": "URL da Transação",
"transactions": "Transações",
"transactions_upper": "TRANSAÇÕES",
"transparent": "Transparente",
"tx_confirmations": "%d confirmações",
"tx_details_title": "Detalhes da Transação",
"tx_from_address": "Endereço de Origem:",
"tx_id_label": "ID da Transação:",
"tx_immature": "IMATURO",
"tx_mined": "MINERADO",
"tx_received": "RECEBIDO",
"tx_sent": "ENVIADO",
"tx_to_address": "Endereço de Destino:",
"tx_view_explorer": "Ver no Explorador",
"txs_count": "%d txs",
"type": "Tipo",
"ui_opacity": "Opacidade da Interface",
"unban": "Desbanir",
"unconfirmed": "Não confirmado",
"undo_clear": "Desfazer Limpeza",
"unknown": "Desconhecido",
"use_embedded_daemon": "Usar dragonxd integrado",
"use_tor": "Usar Tor",
"validate_btn": "Validar",
"validate_description": "Digite um endereço DragonX para verificar se é válido e se pertence a esta carteira.",
"validate_invalid": "INVÁLIDO",
"validate_is_mine": "Esta carteira possui este endereço",
"validate_not_mine": "Não pertence a esta carteira",
"validate_ownership": "Propriedade:",
"validate_results": "Resultados:",
"validate_shielded_type": "Blindado (z-endereço)",
"validate_status": "Status:",
"validate_title": "Validar Endereço",
"validate_transparent_type": "Transparente (t-endereço)",
"validate_type": "Tipo:",
"validate_valid": "VÁLIDO",
"validating": "Validando...",
"verbose_logging": "Log detalhado",
"version": "Versão",
"view": "Visualizar",
"view_details": "Ver Detalhes",
"view_on_explorer": "Ver no Explorador",
"waiting_for_daemon": "Aguardando conexão com o daemon...",
"wallet": "CARTEIRA",
"wallet_empty": "Sua carteira está vazia",
"wallet_empty_hint": "Mude para Receber para obter seu endereço e começar a receber fundos.",
"warning": "Aviso",
"warning_upper": "AVISO!",
"website": "Website",
"window_opacity": "Opacidade da Janela",
"yes_clear": "Sim, Limpar",
"your_addresses": "Seus Endereços",
"z_addresses": "Endereços Z",
}
out = os.path.join(os.path.dirname(__file__), "..", "res", "lang", "pt.json")
with open(out, "w", encoding="utf-8") as f:
json.dump(translations, f, indent=4, ensure_ascii=False, sort_keys=True)
print(f"Wrote {len(translations)} Portuguese translations to {os.path.abspath(out)}")

View File

@@ -1,646 +0,0 @@
#!/usr/bin/env python3
"""Generate Russian (ru) translations for ObsidianDragon wallet."""
import json, os
translations = {
"24h_change": "Изменение за 24ч",
"24h_volume": "Объём за 24ч",
"about": "О программе",
"about_block_explorer": "Обозреватель блоков",
"about_block_height": "Высота блока:",
"about_build_date": "Дата сборки:",
"about_build_type": "Тип сборки:",
"about_chain": "Цепочка:",
"about_connections": "Подключения:",
"about_credits": "Благодарности",
"about_daemon": "Daemon:",
"about_debug": "Отладка",
"about_dragonx": "Об ObsidianDragon",
"about_edition": "Редакция ImGui",
"about_github": "GitHub",
"about_imgui": "ImGui:",
"about_license": "Лицензия",
"about_license_text": "Это программное обеспечение выпущено под лицензией GNU General Public License v3 (GPLv3). Вы можете свободно использовать, изменять и распространять это ПО в соответствии с условиями лицензии.",
"about_peers_count": "%zu узлов",
"about_release": "Релиз",
"about_title": "Об ObsidianDragon",
"about_version": "Версия:",
"about_website": "Веб-сайт",
"acrylic": "Акрил",
"add": "Добавить",
"address": "Адрес",
"address_book_add": "Добавить адрес",
"address_book_add_new": "Добавить новый",
"address_book_added": "Адрес добавлен в книгу",
"address_book_count": "%zu адресов сохранено",
"address_book_deleted": "Запись удалена",
"address_book_edit": "Редактировать адрес",
"address_book_empty": "Нет сохранённых адресов. Нажмите 'Добавить новый', чтобы создать.",
"address_book_exists": "Адрес уже существует в книге",
"address_book_title": "Адресная книга",
"address_book_update_failed": "Не удалось обновить — адрес может быть дубликатом",
"address_book_updated": "Адрес обновлён",
"address_copied": "Адрес скопирован в буфер обмена",
"address_details": "Детали адреса",
"address_label": "Адрес:",
"address_upper": "АДРЕС",
"address_url": "URL адреса",
"addresses_appear_here": "Ваши адреса для получения появятся здесь после подключения.",
"advanced": "РАСШИРЕННЫЕ",
"all_filter": "Все",
"allow_custom_fees": "Разрешить пользовательские комиссии",
"amount": "Сумма",
"amount_details": "ДЕТАЛИ СУММЫ",
"amount_exceeds_balance": "Сумма превышает баланс",
"amount_label": "Сумма:",
"appearance": "ВНЕШНИЙ ВИД",
"auto_shield": "Авто-экранирование майнинга",
"available": "Доступно",
"backup_backing_up": "Создание резервной копии...",
"backup_create": "Создать резервную копию",
"backup_created": "Резервная копия кошелька создана",
"backup_data": "РЕЗЕРВНОЕ КОПИРОВАНИЕ И ДАННЫЕ",
"backup_description": "Создайте резервную копию файла wallet.dat. Этот файл содержит все ваши приватные ключи и историю транзакций. Храните копию в безопасном месте.",
"backup_destination": "Место сохранения:",
"backup_tip_external": "Храните резервные копии на внешних дисках или в облаке",
"backup_tip_multiple": "Создавайте несколько копий в разных местах",
"backup_tip_test": "Периодически проверяйте восстановление из резервной копии",
"backup_tips": "Советы:",
"backup_title": "Резервное копирование кошелька",
"backup_wallet": "Создать резервную копию...",
"backup_wallet_not_found": "Предупреждение: wallet.dat не найден в ожидаемом расположении",
"balance": "Баланс",
"balance_layout": "Макет баланса",
"ban": "Заблокировать",
"banned_peers": "Заблокированные узлы",
"block": "Блок",
"block_bits": "Биты:",
"block_click_next": "Нажмите для следующего блока",
"block_click_prev": "Нажмите для предыдущего блока",
"block_explorer": "Обозреватель блоков",
"block_get_info": "Получить информацию о блоке",
"block_hash": "Хэш блока:",
"block_height": "Высота блока:",
"block_info_title": "Информация о блоке",
"block_merkle_root": "Корень Меркла:",
"block_nav_next": "Далее >>",
"block_nav_prev": "<< Назад",
"block_next": "Следующий блок:",
"block_previous": "Предыдущий блок:",
"block_size": "Размер:",
"block_timestamp": "Временная метка:",
"block_transactions": "Транзакции:",
"blockchain_syncing": "Синхронизация блокчейна (%.1f%%)... Балансы могут быть неточными.",
"cancel": "Отмена",
"characters": "символов",
"clear": "Очистить",
"clear_all_bans": "Снять все блокировки",
"clear_form_confirm": "Очистить все поля формы?",
"clear_request": "Очистить запрос",
"click_copy_address": "Нажмите, чтобы скопировать адрес",
"click_copy_uri": "Нажмите, чтобы скопировать URI",
"close": "Закрыть",
"conf_count": "%d подтв.",
"confirm_and_send": "Подтвердить и отправить",
"confirm_send": "Подтвердить отправку",
"confirm_transaction": "Подтвердить транзакцию",
"confirmations": "Подтверждения",
"confirmations_display": "%d подтверждений | %s",
"confirmed": "Подтверждено",
"connected": "Подключено",
"connected_peers": "Подключённые узлы",
"connecting": "Подключение...",
"console": "Консоль",
"console_auto_scroll": "Авто-прокрутка",
"console_available_commands": "Доступные команды:",
"console_capturing_output": "Захват вывода daemon...",
"console_clear": "Очистить",
"console_clear_console": "Очистить консоль",
"console_cleared": "Консоль очищена",
"console_click_commands": "Нажмите на команды выше, чтобы вставить их",
"console_click_insert": "Нажмите для вставки",
"console_click_insert_params": "Нажмите для вставки с параметрами",
"console_close": "Закрыть",
"console_commands": "Команды",
"console_common_rpc": "Частые RPC-команды:",
"console_completions": "Дополнения:",
"console_connected": "Подключено к daemon",
"console_copy_all": "Копировать всё",
"console_copy_selected": "Копировать",
"console_daemon": "Daemon",
"console_daemon_error": "Ошибка daemon!",
"console_daemon_started": "Daemon запущен",
"console_daemon_stopped": "Daemon остановлен",
"console_disconnected": "Отключено от daemon",
"console_errors": "Ошибки",
"console_filter_hint": "Фильтр вывода...",
"console_help_clear": " clear - Очистить консоль",
"console_help_getbalance": " getbalance - Показать прозрачный баланс",
"console_help_getblockcount": " getblockcount - Показать текущую высоту блока",
"console_help_getinfo": " getinfo - Показать информацию об узле",
"console_help_getmininginfo": " getmininginfo - Показать статус майнинга",
"console_help_getpeerinfo": " getpeerinfo - Показать подключённые узлы",
"console_help_gettotalbalance": " gettotalbalance - Показать общий баланс",
"console_help_help": " help - Показать эту справку",
"console_help_setgenerate": " setgenerate - Управление майнингом",
"console_help_stop": " stop - Остановить daemon",
"console_line_count": "%zu строк",
"console_new_lines": "%d новых строк",
"console_no_daemon": "Нет daemon",
"console_not_connected": "Ошибка: Не подключено к daemon",
"console_rpc_reference": "Справочник RPC-команд",
"console_scanline": "Скан-линия консоли",
"console_search_commands": "Поиск команд...",
"console_select_all": "Выбрать всё",
"console_show_daemon_output": "Показать вывод daemon",
"console_show_errors_only": "Показать только ошибки",
"console_show_rpc_ref": "Показать справочник RPC-команд",
"console_showing_lines": "Показано %zu из %zu строк",
"console_starting_node": "Запуск узла...",
"console_status_error": "Ошибка",
"console_status_running": "Работает",
"console_status_starting": "Запуск",
"console_status_stopped": "Остановлен",
"console_status_stopping": "Остановка",
"console_status_unknown": "Неизвестно",
"console_tab_completion": "Tab для дополнения",
"console_type_help": "Введите 'help' для списка команд",
"console_welcome": "Добро пожаловать в консоль ObsidianDragon",
"console_zoom_in": "Увеличить",
"console_zoom_out": "Уменьшить",
"copy": "Копировать",
"copy_address": "Копировать полный адрес",
"copy_error": "Копировать ошибку",
"copy_to_clipboard": "Копировать в буфер обмена",
"copy_txid": "Копировать TxID",
"copy_uri": "Копировать URI",
"current_price": "Текущая цена",
"custom_fees": "Пользовательские комиссии",
"dark": "Тёмная",
"date": "Дата",
"date_label": "Дата:",
"delete": "Удалить",
"difficulty": "Сложность",
"disconnected": "Отключено",
"dismiss": "Отклонить",
"display": "Отображение",
"dragonx_green": "DragonX (Зелёная)",
"edit": "Редактировать",
"error": "Ошибка",
"est_time_to_block": "Расч. время до блока",
"exit": "Выход",
"explorer": "ОБОЗРЕВАТЕЛЬ",
"export": "Экспорт",
"export_csv": "Экспорт в CSV",
"export_keys_btn": "Экспорт ключей",
"export_keys_danger": "ОПАСНОСТЬ: Будут экспортированы ВСЕ приватные ключи из вашего кошелька! Любой, кто получит доступ к этому файлу, сможет украсть ваши средства. Храните его в безопасности и удалите после использования.",
"export_keys_include_t": "Включить T-адреса (прозрачные)",
"export_keys_include_z": "Включить Z-адреса (экранированные)",
"export_keys_options": "Параметры экспорта:",
"export_keys_success": "Ключи успешно экспортированы",
"export_keys_title": "Экспорт всех приватных ключей",
"export_private_key": "Экспорт приватного ключа",
"export_tx_count": "Экспортировать %zu транзакций в файл CSV.",
"export_tx_file_fail": "Не удалось создать файл CSV",
"export_tx_none": "Нет транзакций для экспорта",
"export_tx_success": "Транзакции успешно экспортированы",
"export_tx_title": "Экспорт транзакций в CSV",
"export_viewing_key": "Экспорт ключа просмотра",
"failed_create_shielded": "Не удалось создать экранированный адрес",
"failed_create_transparent": "Не удалось создать прозрачный адрес",
"fee": "Комиссия",
"fee_high": "Высокая",
"fee_label": "Комиссия:",
"fee_low": "Низкая",
"fee_normal": "Обычная",
"fetch_prices": "Получить цены",
"file": "Файл",
"file_save_location": "Файл будет сохранён в: ~/.config/ObsidianDragon/",
"font_scale": "Масштаб шрифта",
"from": "От",
"from_upper": "ОТ",
"full_details": "Полные детали",
"general": "Общие",
"go_to_receive": "Перейти к получению",
"height": "Высота",
"help": "Справка",
"hide": "Скрыть",
"history": "История",
"immature_type": "Незрелая",
"import": "Импорт",
"import_key_btn": "Импорт ключей",
"import_key_formats": "Поддерживаемые форматы ключей:",
"import_key_full_rescan": "(0 = полное сканирование)",
"import_key_label": "Приватный ключ(и):",
"import_key_no_valid": "В введённых данных не найдено действительных ключей",
"import_key_rescan": "Пересканировать блокчейн после импорта",
"import_key_start_height": "Начальная высота:",
"import_key_success": "Ключи успешно импортированы",
"import_key_t_format": "Приватные ключи WIF для T-адресов",
"import_key_title": "Импорт приватного ключа",
"import_key_tooltip": "Введите один или несколько приватных ключей, по одному на строку.\nПоддерживаются ключи z-адресов и t-адресов.\nСтроки, начинающиеся с #, считаются комментариями.",
"import_key_warning": "Предупреждение: Никогда не делитесь своими приватными ключами! Импорт ключей из ненадёжных источников может скомпрометировать ваш кошелёк.",
"import_key_z_format": "Ключи расходования z-адресов (secret-extended-key-...)",
"import_private_key": "Импорт приватного ключа...",
"invalid_address": "Неверный формат адреса",
"ip_address": "IP-адрес",
"keep": "Сохранить",
"keep_daemon": "Оставить daemon работающим",
"key_export_fetching": "Получение ключа из кошелька...",
"key_export_private_key": "Приватный ключ:",
"key_export_private_warning": "Держите этот ключ в ТАЙНЕ! Любой, кто владеет этим ключом, может потратить ваши средства. Никогда не делитесь им в интернете или с ненадёжными лицами.",
"key_export_reveal": "Показать ключ",
"key_export_viewing_key": "Ключ просмотра:",
"key_export_viewing_warning": "Этот ключ просмотра позволяет другим видеть входящие транзакции и баланс, но НЕ тратить ваши средства. Делитесь только с доверенными лицами.",
"label": "Метка:",
"language": "Язык",
"light": "Светлая",
"loading": "Загрузка...",
"loading_addresses": "Загрузка адресов...",
"local_hashrate": "Локальный хешрейт",
"low_spec_mode": "Режим экономии",
"market": "Рынок",
"market_12h": "12ч",
"market_18h": "18ч",
"market_24h": "24ч",
"market_24h_volume": "ОБЪЁМ 24Ч",
"market_6h": "",
"market_attribution": "Данные о ценах с NonKYC",
"market_btc_price": "ЦЕНА BTC",
"market_cap": "Рыночная капитализация",
"market_no_history": "Нет истории цен",
"market_no_price": "Нет данных о ценах",
"market_now": "Сейчас",
"market_pct_shielded": "%.0f%% Экранировано",
"market_portfolio": "ПОРТФЕЛЬ",
"market_price_unavailable": "Данные о ценах недоступны",
"market_refresh_price": "Обновить данные о ценах",
"market_trade_on": "Торговать на %s",
"mature": "Зрелая",
"max": "Макс",
"memo": "Заметка (необязательно, зашифровано)",
"memo_label": "Заметка:",
"memo_optional": "ЗАМЕТКА (НЕОБЯЗАТЕЛЬНО)",
"memo_upper": "ЗАМЕТКА",
"memo_z_only": "Примечание: Заметки доступны только при отправке на экранированные (z) адреса",
"merge_description": "Объедините несколько UTXO в один экранированный адрес. Это может уменьшить размер кошелька и улучшить конфиденциальность.",
"merge_funds": "Объединить средства",
"merge_started": "Операция объединения начата",
"merge_title": "Объединить на адрес",
"mine_when_idle": "Майнить в простое",
"mined": "добыто",
"mined_filter": "Добытые",
"mined_type": "Добытая",
"mined_upper": "ДОБЫТО",
"miner_fee": "Комиссия майнера",
"mining": "Майнинг",
"mining_active": "Активен",
"mining_address_copied": "Адрес майнинга скопирован",
"mining_all_time": "За всё время",
"mining_already_saved": "URL пула уже сохранён",
"mining_block_copied": "Хэш блока скопирован",
"mining_chart_1m_ago": "1м назад",
"mining_chart_5m_ago": "5м назад",
"mining_chart_now": "Сейчас",
"mining_chart_start": "Старт",
"mining_click": "Нажмите",
"mining_click_copy_address": "Нажмите, чтобы скопировать адрес",
"mining_click_copy_block": "Нажмите, чтобы скопировать хэш блока",
"mining_click_copy_difficulty": "Нажмите, чтобы скопировать сложность",
"mining_connected": "Подключено",
"mining_connecting": "Подключение...",
"mining_control": "Управление майнингом",
"mining_difficulty_copied": "Сложность скопирована",
"mining_est_block": "Расч. блок",
"mining_est_daily": "Расч. за день",
"mining_filter_all": "Все",
"mining_filter_tip_all": "Показать все доходы",
"mining_filter_tip_pool": "Показать только доходы пула",
"mining_filter_tip_solo": "Показать только доходы соло",
"mining_idle_off_tooltip": "Включить майнинг в простое",
"mining_idle_on_tooltip": "Отключить майнинг в простое",
"mining_local_hashrate": "Локальный хешрейт",
"mining_mine": "Майнить",
"mining_mining_addr": "Адрес майн.",
"mining_network": "Сеть",
"mining_no_blocks_yet": "Блоки пока не найдены",
"mining_no_payouts_yet": "Выплат пула пока нет",
"mining_no_saved_addresses": "Нет сохранённых адресов",
"mining_no_saved_pools": "Нет сохранённых пулов",
"mining_off": "Майнинг ВЫКЛЮЧЕН",
"mining_on": "Майнинг ВКЛЮЧЁН",
"mining_open_in_explorer": "Открыть в обозревателе",
"mining_payout_address": "Адрес выплат",
"mining_payout_tooltip": "Адрес для получения вознаграждений за майнинг",
"mining_pool": "Пул",
"mining_pool_hashrate": "Хешрейт пула",
"mining_pool_url": "URL пула",
"mining_recent_blocks": "ПОСЛЕДНИЕ БЛОКИ",
"mining_recent_payouts": "ПОСЛЕДНИЕ ВЫПЛАТЫ ПУЛА",
"mining_remove": "Удалить",
"mining_reset_defaults": "Сбросить настройки",
"mining_save_payout_address": "Сохранить адрес выплат",
"mining_save_pool_url": "Сохранить URL пула",
"mining_saved_addresses": "Сохранённые адреса:",
"mining_saved_pools": "Сохранённые пулы:",
"mining_shares": "Шары",
"mining_show_chart": "График",
"mining_show_log": "Журнал",
"mining_solo": "Соло",
"mining_starting": "Запуск...",
"mining_starting_tooltip": "Майнер запускается...",
"mining_statistics": "Статистика майнинга",
"mining_stop": "Стоп",
"mining_stop_solo_for_pool": "Остановите соло-майнинг перед запуском пул-майнинга",
"mining_stop_solo_for_pool_settings": "Остановите соло-майнинг для изменения настроек пула",
"mining_stopping": "Остановка...",
"mining_stopping_tooltip": "Майнер останавливается...",
"mining_syncing_tooltip": "Блокчейн синхронизируется...",
"mining_threads": "Потоки майнинга",
"mining_to_save": "для сохранения",
"mining_today": "Сегодня",
"mining_uptime": "Время работы",
"mining_yesterday": "Вчера",
"network": "Сеть",
"network_fee": "СЕТЕВАЯ КОМИССИЯ",
"network_hashrate": "Хешрейт сети",
"new": "+ Новый",
"new_shielded_created": "Создан новый экранированный адрес",
"new_t_address": "Новый T-адрес",
"new_t_transparent": "Новый t-адрес (Прозрачный)",
"new_transparent_created": "Создан новый прозрачный адрес",
"new_z_address": "Новый Z-адрес",
"new_z_shielded": "Новый z-адрес (Экранированный)",
"no_addresses": "Адреса не найдены. Создайте один, используя кнопки выше.",
"no_addresses_available": "Нет доступных адресов",
"no_addresses_match": "Нет адресов, соответствующих фильтру",
"no_addresses_with_balance": "Нет адресов с балансом",
"no_matching": "Нет подходящих транзакций",
"no_recent_receives": "Нет недавних получений",
"no_recent_sends": "Нет недавних отправлений",
"no_transactions": "Транзакции не найдены",
"node": "УЗЕЛ",
"node_security": "УЗЕЛ И БЕЗОПАСНОСТЬ",
"noise": "Шум",
"not_connected": "Не подключено к daemon...",
"not_connected_to_daemon": "Не подключено к daemon",
"notes": "Заметки",
"notes_optional": "Заметки (необязательно):",
"output_filename": "Имя выходного файла:",
"overview": "Обзор",
"paste": "Вставить",
"paste_from_clipboard": "Вставить из буфера обмена",
"pay_from": "Оплатить с",
"payment_request": "ЗАПРОС НА ОПЛАТУ",
"payment_request_copied": "Запрос на оплату скопирован",
"payment_uri_copied": "URI платежа скопирован",
"peers": "Узлы",
"peers_avg_ping": "Средний пинг",
"peers_ban_24h": "Заблокировать узел на 24ч",
"peers_ban_score": "Очки блокировки: %d",
"peers_banned": "Заблокированные",
"peers_banned_count": "Заблокировано: %d",
"peers_best_block": "Лучший блок",
"peers_blockchain": "БЛОКЧЕЙН",
"peers_blocks": "Блоки",
"peers_blocks_left": "Осталось %d блоков",
"peers_clear_all_bans": "Снять все блокировки",
"peers_click_copy": "Нажмите, чтобы скопировать",
"peers_connected": "Подключено",
"peers_connected_count": "Подключено: %d",
"peers_copy_ip": "Копировать IP",
"peers_dir_in": "Вх.",
"peers_dir_out": "Исх.",
"peers_hash_copied": "Хэш скопирован",
"peers_hashrate": "Хешрейт",
"peers_in_out": "Вх./Исх.",
"peers_longest": "Длиннейшая",
"peers_longest_chain": "Длиннейшая цепь",
"peers_memory": "Память",
"peers_no_banned": "Нет заблокированных узлов",
"peers_no_connected": "Нет подключённых узлов",
"peers_no_tls": "Без TLS",
"peers_notarized": "Нотаризован",
"peers_p2p_port": "P2P-порт",
"peers_protocol": "Протокол",
"peers_received": "Получено",
"peers_refresh": "Обновить",
"peers_refresh_tooltip": "Обновить список узлов",
"peers_refreshing": "Обновление...",
"peers_sent": "Отправлено",
"peers_tt_id": "ID: %d",
"peers_tt_received": "Получено: %s",
"peers_tt_sent": "Отправлено: %s",
"peers_tt_services": "Сервисы: %s",
"peers_tt_start_height": "Начальная высота: %d",
"peers_tt_synced": "Синхронизировано В/Б: %d/%d",
"peers_tt_tls_cipher": "TLS: %s",
"peers_unban": "Разблокировать",
"peers_upper": "УЗЛЫ",
"peers_version": "Версия",
"pending": "Ожидание",
"ping": "Пинг",
"price_chart": "График цен",
"qr_code": "QR-код",
"qr_failed": "Не удалось сгенерировать QR-код",
"qr_title": "QR-код",
"qr_unavailable": "QR недоступен",
"receive": "Получить",
"received": "получено",
"received_filter": "Получено",
"received_label": "Получено",
"received_upper": "ПОЛУЧЕНО",
"receiving_addresses": "Ваши адреса для получения",
"recent_received": "НЕДАВНО ПОЛУЧЕНО",
"recent_sends": "НЕДАВНО ОТПРАВЛЕНО",
"recipient": "ПОЛУЧАТЕЛЬ",
"recv_type": "Получ.",
"refresh": "Обновить",
"refresh_now": "Обновить сейчас",
"report_bug": "Сообщить об ошибке",
"request_amount": "Сумма (необязательно):",
"request_copy_uri": "Копировать URI",
"request_description": "Создайте запрос на оплату, который другие могут отсканировать или скопировать. QR-код содержит ваш адрес и опциональную сумму/заметку.",
"request_label": "Метка (необязательно):",
"request_memo": "Заметка (необязательно):",
"request_payment": "Запрос оплаты",
"request_payment_uri": "URI платежа:",
"request_receive_address": "Адрес получения:",
"request_select_address": "Выбрать адрес...",
"request_shielded_addrs": "-- Экранированные адреса --",
"request_title": "Запрос оплаты",
"request_transparent_addrs": "-- Прозрачные адреса --",
"request_uri_copied": "URI платежа скопирован в буфер обмена",
"rescan": "Пересканировать",
"reset_to_defaults": "Сбросить настройки",
"review_send": "Проверить отправку",
"rpc_host": "RPC-хост",
"rpc_pass": "Пароль",
"rpc_port": "Порт",
"rpc_user": "Имя пользователя",
"save": "Сохранить",
"save_settings": "Сохранить настройки",
"save_z_transactions": "Сохранять Z-tx в списке транзакций",
"search_placeholder": "Поиск...",
"security": "БЕЗОПАСНОСТЬ",
"select_address": "Выбрать адрес...",
"select_receiving_address": "Выбрать адрес получения...",
"select_source_address": "Выбрать адрес-источник...",
"send": "Отправить",
"send_amount": "Сумма",
"send_amount_details": "ДЕТАЛИ СУММЫ",
"send_amount_upper": "СУММА",
"send_clear_fields": "Очистить все поля формы?",
"send_copy_error": "Копировать ошибку",
"send_dismiss": "Отклонить",
"send_error_copied": "Ошибка скопирована в буфер обмена",
"send_error_prefix": "Ошибка: %s",
"send_exceeds_available": "Превышает доступное (%.8f)",
"send_fee": "Комиссия",
"send_fee_high": "Высокая",
"send_fee_low": "Низкая",
"send_fee_normal": "Обычная",
"send_form_restored": "Форма восстановлена",
"send_from_this_address": "Отправить с этого адреса",
"send_go_to_receive": "Перейти к получению",
"send_keep": "Сохранить",
"send_network_fee": "СЕТЕВАЯ КОМИССИЯ",
"send_no_balance": "Нет баланса",
"send_no_recent": "Нет недавних отправлений",
"send_recent_sends": "НЕДАВНО ОТПРАВЛЕНО",
"send_recipient": "ПОЛУЧАТЕЛЬ",
"send_select_source": "Выбрать адрес-источник...",
"send_sending_from": "ОТПРАВКА С",
"send_submitting": "Отправка транзакции...",
"send_switch_to_receive": "Перейдите к получению, чтобы получить свой адрес и начать получать средства.",
"send_to": "Отправить на",
"send_tooltip_enter_amount": "Введите сумму для отправки",
"send_tooltip_exceeds_balance": "Сумма превышает доступный баланс",
"send_tooltip_in_progress": "Транзакция уже выполняется",
"send_tooltip_invalid_address": "Введите действительный адрес получателя",
"send_tooltip_not_connected": "Не подключено к daemon",
"send_tooltip_select_source": "Сначала выберите адрес-источник",
"send_tooltip_syncing": "Дождитесь синхронизации блокчейна",
"send_total": "Итого",
"send_transaction": "Отправить транзакцию",
"send_tx_failed": "Транзакция не удалась",
"send_tx_sent": "Транзакция отправлена!",
"send_tx_success": "Транзакция успешно отправлена!",
"send_txid_copied": "TxID скопирован в буфер обмена",
"send_txid_label": "TxID: %s",
"send_valid_shielded": "Действительный экранированный адрес",
"send_valid_transparent": "Действительный прозрачный адрес",
"send_wallet_empty": "Ваш кошелёк пуст",
"send_yes_clear": "Да, очистить",
"sending": "Отправка транзакции",
"sending_from": "ОТПРАВКА С",
"sent": "отправлено",
"sent_filter": "Отправлено",
"sent_type": "Отправлено",
"sent_upper": "ОТПРАВЛЕНО",
"settings": "Настройки",
"setup_wizard": "Мастер настройки",
"share": "Поделиться",
"shield_check_status": "Проверить статус",
"shield_completed": "Операция успешно завершена!",
"shield_description": "Экранируйте вознаграждения за майнинг, отправив coinbase-выходы с прозрачных адресов на экранированный адрес. Это улучшает конфиденциальность, скрывая ваш доход от майнинга.",
"shield_from_address": "С адреса:",
"shield_funds": "Экранировать средства",
"shield_in_progress": "Операция выполняется...",
"shield_max_utxos": "Макс. UTXO за операцию",
"shield_merge_done": "Экранирование/объединение завершено!",
"shield_select_z": "Выбрать z-адрес...",
"shield_started": "Операция экранирования начата",
"shield_title": "Экранировать вознаграждения coinbase",
"shield_to_address": "На адрес (экранированный):",
"shield_utxo_limit": "Лимит UTXO:",
"shield_wildcard_hint": "Используйте '*' для экранирования со всех прозрачных адресов",
"shielded": "Экранированный",
"shielded_to": "ЭКРАНИРОВАНО НА",
"shielded_type": "Экранированный",
"show": "Показать",
"show_qr_code": "Показать QR-код",
"showing_transactions": "Показано %d\xe2\x80\x93%d из %d транзакций (всего: %zu)",
"simple_background": "Простой фон",
"start_mining": "Начать майнинг",
"status": "Статус",
"stop_external": "Остановить внешний daemon",
"stop_mining": "Остановить майнинг",
"submitting_transaction": "Отправка транзакции...",
"success": "Успешно",
"summary": "Итоги",
"syncing": "Синхронизация...",
"t_addresses": "T-адреса",
"test_connection": "Тест",
"theme": "Тема",
"theme_effects": "Эффекты темы",
"time_days_ago": "%d дней назад",
"time_hours_ago": "%d часов назад",
"time_minutes_ago": "%d минут назад",
"time_seconds_ago": "%d секунд назад",
"to": "Кому",
"to_upper": "КОМУ",
"tools": "ИНСТРУМЕНТЫ",
"total": "Итого",
"transaction_id": "ID ТРАНЗАКЦИИ",
"transaction_sent": "Транзакция успешно отправлена",
"transaction_sent_msg": "Транзакция отправлена!",
"transaction_url": "URL транзакции",
"transactions": "Транзакции",
"transactions_upper": "ТРАНЗАКЦИИ",
"transparent": "Прозрачный",
"tx_confirmations": "%d подтверждений",
"tx_details_title": "Детали транзакции",
"tx_from_address": "Адрес отправителя:",
"tx_id_label": "ID транзакции:",
"tx_immature": "НЕЗРЕЛАЯ",
"tx_mined": "ДОБЫТА",
"tx_received": "ПОЛУЧЕНО",
"tx_sent": "ОТПРАВЛЕНО",
"tx_to_address": "Адрес получателя:",
"tx_view_explorer": "Посмотреть в обозревателе",
"txs_count": "%d тр.",
"type": "Тип",
"ui_opacity": "Прозрачность интерфейса",
"unban": "Разблокировать",
"unconfirmed": "Не подтверждено",
"undo_clear": "Отменить очистку",
"unknown": "Неизвестно",
"use_embedded_daemon": "Использовать встроенный dragonxd",
"use_tor": "Использовать Tor",
"validate_btn": "Проверить",
"validate_description": "Введите адрес DragonX, чтобы проверить его действительность и принадлежность к этому кошельку.",
"validate_invalid": "НЕДЕЙСТВИТЕЛЕН",
"validate_is_mine": "Этот кошелёк владеет этим адресом",
"validate_not_mine": "Не принадлежит этому кошельку",
"validate_ownership": "Принадлежность:",
"validate_results": "Результаты:",
"validate_shielded_type": "Экранированный (z-адрес)",
"validate_status": "Статус:",
"validate_title": "Проверить адрес",
"validate_transparent_type": "Прозрачный (t-адрес)",
"validate_type": "Тип:",
"validate_valid": "ДЕЙСТВИТЕЛЕН",
"validating": "Проверка...",
"verbose_logging": "Подробное логирование",
"version": "Версия",
"view": "Просмотр",
"view_details": "Подробнее",
"view_on_explorer": "Посмотреть в обозревателе",
"waiting_for_daemon": "Ожидание подключения к daemon...",
"wallet": "КОШЕЛЁК",
"wallet_empty": "Ваш кошелёк пуст",
"wallet_empty_hint": "Перейдите к получению, чтобы получить свой адрес и начать получать средства.",
"warning": "Предупреждение",
"warning_upper": "ПРЕДУПРЕЖДЕНИЕ!",
"website": "Веб-сайт",
"window_opacity": "Прозрачность окна",
"yes_clear": "Да, очистить",
"your_addresses": "Ваши адреса",
"z_addresses": "Z-адреса",
}
out = os.path.join(os.path.dirname(__file__), "..", "res", "lang", "ru.json")
with open(out, "w", encoding="utf-8") as f:
json.dump(translations, f, indent=4, ensure_ascii=False, sort_keys=True)
print(f"Wrote {len(translations)} Russian translations to {os.path.abspath(out)}")

View File

@@ -1,646 +0,0 @@
#!/usr/bin/env python3
"""Generate Chinese Simplified (zh) translations for ObsidianDragon wallet."""
import json, os
translations = {
"24h_change": "24小时变化",
"24h_volume": "24小时交易量",
"about": "关于",
"about_block_explorer": "区块浏览器",
"about_block_height": "区块高度:",
"about_build_date": "构建日期:",
"about_build_type": "构建类型:",
"about_chain": "链:",
"about_connections": "连接数:",
"about_credits": "致谢",
"about_daemon": "守护进程:",
"about_debug": "调试",
"about_dragonx": "关于 ObsidianDragon",
"about_edition": "ImGui 版本",
"about_github": "GitHub",
"about_imgui": "ImGui",
"about_license": "许可证",
"about_license_text": "本软件根据 GNU 通用公共许可证 v3 (GPLv3) 发布。您可以根据许可证条款自由使用、修改和分发本软件。",
"about_peers_count": "%zu 个节点",
"about_release": "发布版",
"about_title": "关于 ObsidianDragon",
"about_version": "版本:",
"about_website": "网站",
"acrylic": "亚克力",
"add": "添加",
"address": "地址",
"address_book_add": "添加地址",
"address_book_add_new": "添加新地址",
"address_book_added": "地址已添加到通讯录",
"address_book_count": "已保存 %zu 个地址",
"address_book_deleted": "条目已删除",
"address_book_edit": "编辑地址",
"address_book_empty": "没有保存的地址。点击'添加新地址'创建一个。",
"address_book_exists": "地址已存在于通讯录中",
"address_book_title": "地址簿",
"address_book_update_failed": "更新失败——地址可能重复",
"address_book_updated": "地址已更新",
"address_copied": "地址已复制到剪贴板",
"address_details": "地址详情",
"address_label": "地址:",
"address_upper": "地址",
"address_url": "地址 URL",
"addresses_appear_here": "连接后,您的接收地址将显示在此处。",
"advanced": "高级",
"all_filter": "全部",
"allow_custom_fees": "允许自定义手续费",
"amount": "金额",
"amount_details": "金额详情",
"amount_exceeds_balance": "金额超过余额",
"amount_label": "金额:",
"appearance": "外观",
"auto_shield": "自动屏蔽挖矿",
"available": "可用",
"backup_backing_up": "正在备份...",
"backup_create": "创建备份",
"backup_created": "钱包备份已创建",
"backup_data": "备份与数据",
"backup_description": "创建 wallet.dat 文件的备份。此文件包含您所有的私钥和交易历史。请将备份存放在安全的地方。",
"backup_destination": "备份目标:",
"backup_tip_external": "将备份存储在外部驱动器或云存储中",
"backup_tip_multiple": "在不同位置创建多个备份",
"backup_tip_test": "定期测试从备份恢复",
"backup_tips": "提示:",
"backup_title": "备份钱包",
"backup_wallet": "备份钱包...",
"backup_wallet_not_found": "警告:在预期位置未找到 wallet.dat",
"balance": "余额",
"balance_layout": "余额布局",
"ban": "封禁",
"banned_peers": "已封禁节点",
"block": "区块",
"block_bits": "比特:",
"block_click_next": "点击查看下一个区块",
"block_click_prev": "点击查看上一个区块",
"block_explorer": "区块浏览器",
"block_get_info": "获取区块信息",
"block_hash": "区块哈希:",
"block_height": "区块高度:",
"block_info_title": "区块信息",
"block_merkle_root": "默克尔根:",
"block_nav_next": "下一个 >>",
"block_nav_prev": "<< 上一个",
"block_next": "下一个区块:",
"block_previous": "上一个区块:",
"block_size": "大小:",
"block_timestamp": "时间戳:",
"block_transactions": "交易:",
"blockchain_syncing": "区块链同步中 (%.1f%%)... 余额可能不准确。",
"cancel": "取消",
"characters": "字符",
"clear": "清除",
"clear_all_bans": "解除所有封禁",
"clear_form_confirm": "清除所有表单字段?",
"clear_request": "清除请求",
"click_copy_address": "点击复制地址",
"click_copy_uri": "点击复制 URI",
"close": "关闭",
"conf_count": "%d 确认",
"confirm_and_send": "确认并发送",
"confirm_send": "确认发送",
"confirm_transaction": "确认交易",
"confirmations": "确认数",
"confirmations_display": "%d 次确认 | %s",
"confirmed": "已确认",
"connected": "已连接",
"connected_peers": "已连接节点",
"connecting": "连接中...",
"console": "控制台",
"console_auto_scroll": "自动滚动",
"console_available_commands": "可用命令:",
"console_capturing_output": "正在捕获守护进程输出...",
"console_clear": "清除",
"console_clear_console": "清除控制台",
"console_cleared": "控制台已清除",
"console_click_commands": "点击上方命令以插入",
"console_click_insert": "点击插入",
"console_click_insert_params": "点击插入(含参数)",
"console_close": "关闭",
"console_commands": "命令",
"console_common_rpc": "常用 RPC 命令:",
"console_completions": "补全:",
"console_connected": "已连接到守护进程",
"console_copy_all": "全部复制",
"console_copy_selected": "复制",
"console_daemon": "守护进程",
"console_daemon_error": "守护进程错误!",
"console_daemon_started": "守护进程已启动",
"console_daemon_stopped": "守护进程已停止",
"console_disconnected": "已断开与守护进程的连接",
"console_errors": "错误",
"console_filter_hint": "过滤输出...",
"console_help_clear": " clear - 清除控制台",
"console_help_getbalance": " getbalance - 显示透明余额",
"console_help_getblockcount": " getblockcount - 显示当前区块高度",
"console_help_getinfo": " getinfo - 显示节点信息",
"console_help_getmininginfo": " getmininginfo - 显示挖矿状态",
"console_help_getpeerinfo": " getpeerinfo - 显示已连接节点",
"console_help_gettotalbalance": " gettotalbalance - 显示总余额",
"console_help_help": " help - 显示此帮助信息",
"console_help_setgenerate": " setgenerate - 控制挖矿",
"console_help_stop": " stop - 停止守护进程",
"console_line_count": "%zu 行",
"console_new_lines": "%d 新行",
"console_no_daemon": "无守护进程",
"console_not_connected": "错误:未连接到守护进程",
"console_rpc_reference": "RPC 命令参考",
"console_scanline": "控制台扫描线",
"console_search_commands": "搜索命令...",
"console_select_all": "全选",
"console_show_daemon_output": "显示守护进程输出",
"console_show_errors_only": "仅显示错误",
"console_show_rpc_ref": "显示 RPC 命令参考",
"console_showing_lines": "显示 %zu / %zu 行",
"console_starting_node": "正在启动节点...",
"console_status_error": "错误",
"console_status_running": "运行中",
"console_status_starting": "启动中",
"console_status_stopped": "已停止",
"console_status_stopping": "停止中",
"console_status_unknown": "未知",
"console_tab_completion": "Tab 补全",
"console_type_help": "输入 'help' 查看可用命令",
"console_welcome": "欢迎使用 ObsidianDragon 控制台",
"console_zoom_in": "放大",
"console_zoom_out": "缩小",
"copy": "复制",
"copy_address": "复制完整地址",
"copy_error": "复制错误",
"copy_to_clipboard": "复制到剪贴板",
"copy_txid": "复制交易ID",
"copy_uri": "复制 URI",
"current_price": "当前价格",
"custom_fees": "自定义手续费",
"dark": "深色",
"date": "日期",
"date_label": "日期:",
"delete": "删除",
"difficulty": "难度",
"disconnected": "已断开",
"dismiss": "关闭",
"display": "显示",
"dragonx_green": "DragonX绿色",
"edit": "编辑",
"error": "错误",
"est_time_to_block": "预计出块时间",
"exit": "退出",
"explorer": "浏览器",
"export": "导出",
"export_csv": "导出 CSV",
"export_keys_btn": "导出密钥",
"export_keys_danger": "危险:这将导出您钱包中的所有私钥!任何获得此文件的人都可以窃取您的资金。请安全保管并在使用后删除。",
"export_keys_include_t": "包含 T 地址(透明)",
"export_keys_include_z": "包含 Z 地址(屏蔽)",
"export_keys_options": "导出选项:",
"export_keys_success": "密钥导出成功",
"export_keys_title": "导出所有私钥",
"export_private_key": "导出私钥",
"export_tx_count": "导出 %zu 笔交易到 CSV 文件。",
"export_tx_file_fail": "无法创建 CSV 文件",
"export_tx_none": "没有交易可导出",
"export_tx_success": "交易导出成功",
"export_tx_title": "导出交易到 CSV",
"export_viewing_key": "导出查看密钥",
"failed_create_shielded": "无法创建屏蔽地址",
"failed_create_transparent": "无法创建透明地址",
"fee": "手续费",
"fee_high": "",
"fee_label": "手续费:",
"fee_low": "",
"fee_normal": "普通",
"fetch_prices": "获取价格",
"file": "文件",
"file_save_location": "文件将保存至:~/.config/ObsidianDragon/",
"font_scale": "字体大小",
"from": "",
"from_upper": "",
"full_details": "完整详情",
"general": "常规",
"go_to_receive": "前往接收",
"height": "高度",
"help": "帮助",
"hide": "隐藏",
"history": "历史",
"immature_type": "未成熟",
"import": "导入",
"import_key_btn": "导入密钥",
"import_key_formats": "支持的密钥格式:",
"import_key_full_rescan": "0 = 完整重扫)",
"import_key_label": "私钥:",
"import_key_no_valid": "输入中未找到有效密钥",
"import_key_rescan": "导入后重新扫描区块链",
"import_key_start_height": "起始高度:",
"import_key_success": "密钥导入成功",
"import_key_t_format": "T 地址 WIF 私钥",
"import_key_title": "导入私钥",
"import_key_tooltip": "输入一个或多个私钥,每行一个。\n支持 z 地址和 t 地址密钥。\n以 # 开头的行视为注释。",
"import_key_warning": "警告:切勿分享您的私钥!从不可信来源导入密钥可能会危及您的钱包安全。",
"import_key_z_format": "Z 地址花费密钥 (secret-extended-key-...)",
"import_private_key": "导入私钥...",
"invalid_address": "无效的地址格式",
"ip_address": "IP 地址",
"keep": "保留",
"keep_daemon": "保持守护进程运行",
"key_export_fetching": "正在从钱包获取密钥...",
"key_export_private_key": "私钥:",
"key_export_private_warning": "请保密此密钥!任何拥有此密钥的人都可以花费您的资金。切勿在网上或与不可信的人分享。",
"key_export_reveal": "显示密钥",
"key_export_viewing_key": "查看密钥:",
"key_export_viewing_warning": "此查看密钥允许他人查看您的入账交易和余额,但不能花费您的资金。仅与信任的人分享。",
"label": "标签:",
"language": "语言",
"light": "浅色",
"loading": "加载中...",
"loading_addresses": "正在加载地址...",
"local_hashrate": "本地算力",
"low_spec_mode": "低配模式",
"market": "市场",
"market_12h": "12小时",
"market_18h": "18小时",
"market_24h": "24小时",
"market_24h_volume": "24小时交易量",
"market_6h": "6小时",
"market_attribution": "价格数据来自 NonKYC",
"market_btc_price": "BTC 价格",
"market_cap": "市值",
"market_no_history": "无价格历史",
"market_no_price": "无价格数据",
"market_now": "现在",
"market_pct_shielded": "%.0f%% 屏蔽",
"market_portfolio": "投资组合",
"market_price_unavailable": "价格数据不可用",
"market_refresh_price": "刷新价格数据",
"market_trade_on": "%s 交易",
"mature": "已成熟",
"max": "最大",
"memo": "备注(可选,加密)",
"memo_label": "备注:",
"memo_optional": "备注(可选)",
"memo_upper": "备注",
"memo_z_only": "注意:备注仅在发送到屏蔽 (z) 地址时可用",
"merge_description": "将多个 UTXO 合并到一个屏蔽地址。这可以帮助减小钱包大小并提高隐私性。",
"merge_funds": "合并资金",
"merge_started": "合并操作已开始",
"merge_title": "合并到地址",
"mine_when_idle": "空闲时挖矿",
"mined": "已挖得",
"mined_filter": "已挖得",
"mined_type": "已挖得",
"mined_upper": "已挖得",
"miner_fee": "矿工费",
"mining": "挖矿",
"mining_active": "活跃",
"mining_address_copied": "挖矿地址已复制",
"mining_all_time": "所有时间",
"mining_already_saved": "矿池 URL 已保存",
"mining_block_copied": "区块哈希已复制",
"mining_chart_1m_ago": "1分钟前",
"mining_chart_5m_ago": "5分钟前",
"mining_chart_now": "现在",
"mining_chart_start": "开始",
"mining_click": "点击",
"mining_click_copy_address": "点击复制地址",
"mining_click_copy_block": "点击复制区块哈希",
"mining_click_copy_difficulty": "点击复制难度",
"mining_connected": "已连接",
"mining_connecting": "连接中...",
"mining_control": "挖矿控制",
"mining_difficulty_copied": "难度已复制",
"mining_est_block": "预计区块",
"mining_est_daily": "预计日收益",
"mining_filter_all": "全部",
"mining_filter_tip_all": "显示所有收益",
"mining_filter_tip_pool": "仅显示矿池收益",
"mining_filter_tip_solo": "仅显示单人收益",
"mining_idle_off_tooltip": "启用空闲挖矿",
"mining_idle_on_tooltip": "禁用空闲挖矿",
"mining_local_hashrate": "本地算力",
"mining_mine": "挖矿",
"mining_mining_addr": "挖矿地址",
"mining_network": "网络",
"mining_no_blocks_yet": "尚未找到区块",
"mining_no_payouts_yet": "尚无矿池支付",
"mining_no_saved_addresses": "没有保存的地址",
"mining_no_saved_pools": "没有保存的矿池",
"mining_off": "挖矿已关闭",
"mining_on": "挖矿已开启",
"mining_open_in_explorer": "在浏览器中打开",
"mining_payout_address": "支付地址",
"mining_payout_tooltip": "接收挖矿奖励的地址",
"mining_pool": "矿池",
"mining_pool_hashrate": "矿池算力",
"mining_pool_url": "矿池 URL",
"mining_recent_blocks": "最近区块",
"mining_recent_payouts": "最近矿池支付",
"mining_remove": "移除",
"mining_reset_defaults": "重置默认值",
"mining_save_payout_address": "保存支付地址",
"mining_save_pool_url": "保存矿池 URL",
"mining_saved_addresses": "已保存地址:",
"mining_saved_pools": "已保存矿池:",
"mining_shares": "份额",
"mining_show_chart": "图表",
"mining_show_log": "日志",
"mining_solo": "单人",
"mining_starting": "启动中...",
"mining_starting_tooltip": "矿工正在启动...",
"mining_statistics": "挖矿统计",
"mining_stop": "停止",
"mining_stop_solo_for_pool": "启动矿池挖矿前请先停止单人挖矿",
"mining_stop_solo_for_pool_settings": "请停止单人挖矿以更改矿池设置",
"mining_stopping": "停止中...",
"mining_stopping_tooltip": "矿工正在停止...",
"mining_syncing_tooltip": "区块链同步中...",
"mining_threads": "挖矿线程",
"mining_to_save": "保存",
"mining_today": "今天",
"mining_uptime": "运行时间",
"mining_yesterday": "昨天",
"network": "网络",
"network_fee": "网络手续费",
"network_hashrate": "全网算力",
"new": "+ 新建",
"new_shielded_created": "新屏蔽地址已创建",
"new_t_address": "新 T 地址",
"new_t_transparent": "新 t 地址(透明)",
"new_transparent_created": "新透明地址已创建",
"new_z_address": "新 Z 地址",
"new_z_shielded": "新 z 地址(屏蔽)",
"no_addresses": "未找到地址。请使用上方按钮创建一个。",
"no_addresses_available": "无可用地址",
"no_addresses_match": "没有匹配过滤器的地址",
"no_addresses_with_balance": "没有有余额的地址",
"no_matching": "没有匹配的交易",
"no_recent_receives": "没有最近的接收",
"no_recent_sends": "没有最近的发送",
"no_transactions": "未找到交易",
"node": "节点",
"node_security": "节点与安全",
"noise": "噪点",
"not_connected": "未连接到守护进程...",
"not_connected_to_daemon": "未连接到守护进程",
"notes": "备注",
"notes_optional": "备注(可选):",
"output_filename": "输出文件名:",
"overview": "概览",
"paste": "粘贴",
"paste_from_clipboard": "从剪贴板粘贴",
"pay_from": "付款来源",
"payment_request": "付款请求",
"payment_request_copied": "付款请求已复制",
"payment_uri_copied": "付款 URI 已复制",
"peers": "节点",
"peers_avg_ping": "平均延迟",
"peers_ban_24h": "封禁节点 24 小时",
"peers_ban_score": "封禁评分:%d",
"peers_banned": "已封禁",
"peers_banned_count": "已封禁:%d",
"peers_best_block": "最佳区块",
"peers_blockchain": "区块链",
"peers_blocks": "区块",
"peers_blocks_left": "剩余 %d 个区块",
"peers_clear_all_bans": "解除所有封禁",
"peers_click_copy": "点击复制",
"peers_connected": "已连接",
"peers_connected_count": "已连接:%d",
"peers_copy_ip": "复制 IP",
"peers_dir_in": "",
"peers_dir_out": "",
"peers_hash_copied": "哈希已复制",
"peers_hashrate": "算力",
"peers_in_out": "入/出",
"peers_longest": "最长",
"peers_longest_chain": "最长链",
"peers_memory": "内存",
"peers_no_banned": "无已封禁节点",
"peers_no_connected": "无已连接节点",
"peers_no_tls": "无 TLS",
"peers_notarized": "已公证",
"peers_p2p_port": "P2P 端口",
"peers_protocol": "协议",
"peers_received": "已接收",
"peers_refresh": "刷新",
"peers_refresh_tooltip": "刷新节点列表",
"peers_refreshing": "刷新中...",
"peers_sent": "已发送",
"peers_tt_id": "ID%d",
"peers_tt_received": "已接收:%s",
"peers_tt_sent": "已发送:%s",
"peers_tt_services": "服务:%s",
"peers_tt_start_height": "起始高度:%d",
"peers_tt_synced": "已同步 H/B%d/%d",
"peers_tt_tls_cipher": "TLS%s",
"peers_unban": "解除封禁",
"peers_upper": "节点",
"peers_version": "版本",
"pending": "待处理",
"ping": "延迟",
"price_chart": "价格图表",
"qr_code": "二维码",
"qr_failed": "无法生成二维码",
"qr_title": "二维码",
"qr_unavailable": "二维码不可用",
"receive": "接收",
"received": "已接收",
"received_filter": "已接收",
"received_label": "已接收",
"received_upper": "已接收",
"receiving_addresses": "您的接收地址",
"recent_received": "最近接收",
"recent_sends": "最近发送",
"recipient": "收款方",
"recv_type": "接收",
"refresh": "刷新",
"refresh_now": "立即刷新",
"report_bug": "报告错误",
"request_amount": "金额(可选):",
"request_copy_uri": "复制 URI",
"request_description": "生成一个付款请求,他人可以扫描或复制。二维码包含您的地址和可选的金额/备注。",
"request_label": "标签(可选):",
"request_memo": "备注(可选):",
"request_payment": "请求付款",
"request_payment_uri": "付款 URI",
"request_receive_address": "接收地址:",
"request_select_address": "选择地址...",
"request_shielded_addrs": "-- 屏蔽地址 --",
"request_title": "请求付款",
"request_transparent_addrs": "-- 透明地址 --",
"request_uri_copied": "付款 URI 已复制到剪贴板",
"rescan": "重新扫描",
"reset_to_defaults": "重置为默认值",
"review_send": "审核发送",
"rpc_host": "RPC 主机",
"rpc_pass": "密码",
"rpc_port": "端口",
"rpc_user": "用户名",
"save": "保存",
"save_settings": "保存设置",
"save_z_transactions": "将 Z 交易保存到列表",
"search_placeholder": "搜索...",
"security": "安全",
"select_address": "选择地址...",
"select_receiving_address": "选择接收地址...",
"select_source_address": "选择来源地址...",
"send": "发送",
"send_amount": "金额",
"send_amount_details": "金额详情",
"send_amount_upper": "金额",
"send_clear_fields": "清除所有表单字段?",
"send_copy_error": "复制错误",
"send_dismiss": "关闭",
"send_error_copied": "错误已复制到剪贴板",
"send_error_prefix": "错误:%s",
"send_exceeds_available": "超过可用额 (%.8f)",
"send_fee": "手续费",
"send_fee_high": "",
"send_fee_low": "",
"send_fee_normal": "普通",
"send_form_restored": "表单已恢复",
"send_from_this_address": "从此地址发送",
"send_go_to_receive": "前往接收",
"send_keep": "保留",
"send_network_fee": "网络手续费",
"send_no_balance": "无余额",
"send_no_recent": "没有最近的发送",
"send_recent_sends": "最近发送",
"send_recipient": "收款方",
"send_select_source": "选择来源地址...",
"send_sending_from": "发送来源",
"send_submitting": "正在提交交易...",
"send_switch_to_receive": "切换到接收页面获取您的地址并开始接收资金。",
"send_to": "发送至",
"send_tooltip_enter_amount": "请输入发送金额",
"send_tooltip_exceeds_balance": "金额超过可用余额",
"send_tooltip_in_progress": "交易正在进行中",
"send_tooltip_invalid_address": "请输入有效的收款地址",
"send_tooltip_not_connected": "未连接到守护进程",
"send_tooltip_select_source": "请先选择来源地址",
"send_tooltip_syncing": "请等待区块链同步",
"send_total": "合计",
"send_transaction": "发送交易",
"send_tx_failed": "交易失败",
"send_tx_sent": "交易已发送!",
"send_tx_success": "交易发送成功!",
"send_txid_copied": "交易ID 已复制到剪贴板",
"send_txid_label": "TxID%s",
"send_valid_shielded": "有效的屏蔽地址",
"send_valid_transparent": "有效的透明地址",
"send_wallet_empty": "您的钱包是空的",
"send_yes_clear": "是,清除",
"sending": "正在发送交易",
"sending_from": "发送来源",
"sent": "已发送",
"sent_filter": "已发送",
"sent_type": "已发送",
"sent_upper": "已发送",
"settings": "设置",
"setup_wizard": "设置向导",
"share": "分享",
"shield_check_status": "检查状态",
"shield_completed": "操作成功完成!",
"shield_description": "通过将透明地址的 coinbase 输出发送到屏蔽地址来屏蔽您的挖矿奖励。这可以隐藏您的挖矿收入,提高隐私性。",
"shield_from_address": "从地址:",
"shield_funds": "屏蔽资金",
"shield_in_progress": "操作进行中...",
"shield_max_utxos": "每次操作最大 UTXO 数",
"shield_merge_done": "屏蔽/合并完成!",
"shield_select_z": "选择 z 地址...",
"shield_started": "屏蔽操作已开始",
"shield_title": "屏蔽 Coinbase 奖励",
"shield_to_address": "至地址(屏蔽):",
"shield_utxo_limit": "UTXO 限制:",
"shield_wildcard_hint": "使用 '*' 从所有透明地址屏蔽",
"shielded": "屏蔽",
"shielded_to": "屏蔽至",
"shielded_type": "屏蔽",
"show": "显示",
"show_qr_code": "显示二维码",
"showing_transactions": "显示第 %d\xe2\x80\x93%d 笔,共 %d 笔交易(总计:%zu",
"simple_background": "简单背景",
"start_mining": "开始挖矿",
"status": "状态",
"stop_external": "停止外部守护进程",
"stop_mining": "停止挖矿",
"submitting_transaction": "正在提交交易...",
"success": "成功",
"summary": "摘要",
"syncing": "同步中...",
"t_addresses": "T 地址",
"test_connection": "测试",
"theme": "主题",
"theme_effects": "主题效果",
"time_days_ago": "%d 天前",
"time_hours_ago": "%d 小时前",
"time_minutes_ago": "%d 分钟前",
"time_seconds_ago": "%d 秒前",
"to": "",
"to_upper": "",
"tools": "工具",
"total": "合计",
"transaction_id": "交易 ID",
"transaction_sent": "交易发送成功",
"transaction_sent_msg": "交易已发送!",
"transaction_url": "交易 URL",
"transactions": "交易",
"transactions_upper": "交易",
"transparent": "透明",
"tx_confirmations": "%d 次确认",
"tx_details_title": "交易详情",
"tx_from_address": "发送地址:",
"tx_id_label": "交易 ID",
"tx_immature": "未成熟",
"tx_mined": "已挖得",
"tx_received": "已接收",
"tx_sent": "已发送",
"tx_to_address": "接收地址:",
"tx_view_explorer": "在浏览器中查看",
"txs_count": "%d 笔交易",
"type": "类型",
"ui_opacity": "界面透明度",
"unban": "解除封禁",
"unconfirmed": "未确认",
"undo_clear": "撤销清除",
"unknown": "未知",
"use_embedded_daemon": "使用内置 dragonxd",
"use_tor": "使用 Tor",
"validate_btn": "验证",
"validate_description": "输入一个 DragonX 地址来检查它是否有效以及是否属于此钱包。",
"validate_invalid": "无效",
"validate_is_mine": "此钱包拥有该地址",
"validate_not_mine": "不属于此钱包",
"validate_ownership": "所有权:",
"validate_results": "结果:",
"validate_shielded_type": "屏蔽z 地址)",
"validate_status": "状态:",
"validate_title": "验证地址",
"validate_transparent_type": "透明t 地址)",
"validate_type": "类型:",
"validate_valid": "有效",
"validating": "验证中...",
"verbose_logging": "详细日志",
"version": "版本",
"view": "查看",
"view_details": "查看详情",
"view_on_explorer": "在浏览器中查看",
"waiting_for_daemon": "等待守护进程连接...",
"wallet": "钱包",
"wallet_empty": "您的钱包是空的",
"wallet_empty_hint": "切换到接收页面获取您的地址并开始接收资金。",
"warning": "警告",
"warning_upper": "警告!",
"website": "网站",
"window_opacity": "窗口透明度",
"yes_clear": "是,清除",
"your_addresses": "您的地址",
"z_addresses": "Z 地址",
}
out = os.path.join(os.path.dirname(__file__), "..", "res", "lang", "zh.json")
with open(out, "w", encoding="utf-8") as f:
json.dump(translations, f, indent=4, ensure_ascii=False, sort_keys=True)
print(f"Wrote {len(translations)} Chinese translations to {os.path.abspath(out)}")

View File

@@ -33,6 +33,7 @@
#include "ui/windows/network_tab.h"
#include "ui/windows/console_command_executor.h"
#include "ui/windows/explorer_tab.h"
#include "ui/windows/seed_display.h"
#include "ui/windows/market_tab.h"
#include "ui/windows/settings_window.h"
#include "ui/windows/about_dialog.h"
@@ -118,7 +119,14 @@ App::App()
// deterministic across launches.
balance_rng_.seed(std::random_device{}());
}
App::~App() = default;
App::~App()
{
// Scrub any seed/phrase secret still resident (e.g. app quit with a backup/migration modal open).
if (!seed_migration_seed_.empty())
sodium_memzero(&seed_migration_seed_[0], seed_migration_seed_.size());
if (!seed_backup_phrase_.empty())
sodium_memzero(&seed_backup_phrase_[0], seed_backup_phrase_.size());
}
namespace {
// How often auto-balance re-evaluates the pool while active. Long, because switching
@@ -715,6 +723,20 @@ void App::update()
// it can act; compiled away when the feature is off (constexpr gate inside).
maybeProvisionChatIdentity();
// One-time reminder to back up the wallet's seed phrase (mnemonic wallets only).
maybeRemindSeedBackup();
// Pick up progress/result from a running seed-wallet migration (create/sweep/adopt).
pumpSeedMigration();
// While confirming the sweep, poll the tx confirmations + legacy balance every ~5s.
if (show_seed_migration_ && seed_migration_step_ == SeedMigrationStep::Confirming) {
seed_migration_poll_timer_ -= ImGui::GetIO().DeltaTime;
if (seed_migration_poll_timer_ <= 0.0f) {
seed_migration_poll_timer_ = 5.0f;
pollSweepStatus();
}
}
// Auto-lock check (only when connected + encrypted + unlocked)
if (state_.connected && state_.isUnlocked()) {
checkAutoLock();
@@ -1893,6 +1915,14 @@ void App::render()
renderBackupDialog();
}
if (show_seed_backup_) {
renderSeedBackupDialog();
}
if (show_seed_migration_) {
renderSeedMigrationDialog();
}
// Security overlay dialogs (encrypt, decrypt, PIN) are rendered AFTER ImGui::End()
// to ensure they appear on top of all other content
@@ -2921,10 +2951,344 @@ void App::renderBackupDialog()
backup_status_.clear();
s_backup_confirm_overwrite = false;
}
ui::material::EndOverlayDialog();
}
void App::renderSeedBackupDialog()
{
// Wipe the revealed phrase and reset the dialog's state.
auto closeAndWipe = [this]() {
if (!seed_backup_phrase_.empty())
sodium_memzero(&seed_backup_phrase_[0], seed_backup_phrase_.size());
seed_backup_phrase_.clear();
seed_backup_status_.clear();
seed_backup_fetch_started_ = false;
seed_backup_loading_ = false;
seed_backup_no_mnemonic_ = false;
show_seed_backup_ = false;
};
// Kick off the async z_exportmnemonic fetch once, and only while unlocked.
if (!seed_backup_fetch_started_ && !state_.isLocked()) {
seed_backup_fetch_started_ = true;
seed_backup_loading_ = true;
seed_backup_no_mnemonic_ = false;
seed_backup_status_.clear();
exportSeedPhrase([this](bool ok, bool noMnemonic, const std::string& phrase,
const std::string& error) {
if (!show_seed_backup_) return; // dialog closed while the fetch was in flight
seed_backup_loading_ = false;
if (ok) {
seed_backup_phrase_ = phrase; // working copy — wiped on close
} else if (noMnemonic) {
seed_backup_no_mnemonic_ = true;
} else {
seed_backup_status_ = error.empty() ? std::string(TR("seed_backup_load_failed")) : error;
}
});
}
if (!ui::material::BeginOverlayDialog(TR("seed_backup_title"), &show_seed_backup_, 540.0f, 0.94f)) {
if (seed_backup_fetch_started_) closeAndWipe();
return;
}
// BeginOverlayDialog flips show_seed_backup_ to false on an Esc / outside-click / X dismiss but
// still returns true this frame — catch that here so the revealed secret is always scrubbed.
if (!show_seed_backup_) {
closeAndWipe();
ui::material::EndOverlayDialog();
return;
}
ui::material::Type().text(ui::material::TypeStyle::H6, TR("seed_backup_title"));
ImGui::Dummy(ImVec2(0, ui::Layout::spacingSm()));
if (state_.isLocked()) {
ImGui::TextWrapped("%s", TR("seed_backup_locked"));
} else if (seed_backup_loading_) {
ImGui::TextWrapped("%s", TR("seed_backup_loading"));
} else if (seed_backup_no_mnemonic_) {
ImGui::TextWrapped("%s", TR("seed_backup_none"));
} else if (!seed_backup_phrase_.empty()) {
ImGui::TextWrapped("%s", TR("seed_backup_intro"));
ImGui::Spacing();
ImGui::PushStyleColor(ImGuiCol_Text, ui::material::Error());
ImGui::TextWrapped("%s", TR("seed_backup_warning"));
ImGui::PopStyleColor();
ImGui::Spacing();
ui::RenderSeedWordGrid(ui::SplitSeedWords(seed_backup_phrase_));
ImGui::Spacing();
if (!seed_backup_status_.empty()) {
ImGui::TextColored(ImVec4(0.3f, 0.8f, 0.3f, 1.0f), "%s", seed_backup_status_.c_str());
ImGui::Spacing();
}
ImGui::Separator();
if (ui::material::StyledButton(TR("seed_backup_copy"), ImVec2(120, 0))) {
copySecretToClipboard(seed_backup_phrase_);
}
ImGui::SameLine();
if (ui::material::StyledButton(TR("seed_backup_save"), ImVec2(150, 0))) {
std::string path = util::Platform::getConfigDir() + "/dragonx-seed-backup.txt";
std::string content = seed_backup_phrase_ + "\n";
const bool ok = util::Platform::writeFileAtomically(path, content,
/*restrictPermissions=*/true);
sodium_memzero(&content[0], content.size());
seed_backup_status_ = (ok ? std::string(TR("seed_backup_saved"))
: std::string(TR("seed_backup_save_failed"))) + path;
}
ImGui::SameLine();
if (ui::material::StyledButton(TR("seed_backup_close"), ImVec2(120, 0))) {
closeAndWipe();
ui::material::EndOverlayDialog();
return;
}
ui::material::EndOverlayDialog();
return;
} else if (!seed_backup_status_.empty()) {
ImGui::TextColored(ImVec4(0.8f, 0.3f, 0.3f, 1.0f), "%s", seed_backup_status_.c_str());
}
ImGui::Spacing();
ImGui::Separator();
if (ui::material::StyledButton(TR("seed_backup_close"), ImVec2(120, 0))) {
closeAndWipe();
}
ui::material::EndOverlayDialog();
}
void App::renderSeedMigrationDialog()
{
auto wipeSeed = [this]() {
if (!seed_migration_seed_.empty())
sodium_memzero(&seed_migration_seed_[0], seed_migration_seed_.size());
seed_migration_seed_.clear();
};
auto close = [this, &wipeSeed]() { wipeSeed(); show_seed_migration_ = false; };
// A background op (create/sweep/adopt) can't be cancelled cleanly, so the modal must not be
// dismissed mid-op.
const bool busy = seed_migration_in_flight_
|| 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 (!busy) wipeSeed();
return;
}
// BeginOverlayDialog flips show_seed_migration_ to false on an Esc / outside-click / X dismiss
// (but still returns true this frame). Veto the dismiss while busy; otherwise it's handled by
// 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");
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::Spacing();
ImGui::Separator();
if (ui::material::StyledButton("Create seed wallet", ImVec2(180, 0)))
beginCreateSeedWallet();
ImGui::SameLine();
if (ui::material::StyledButton("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::Spacing();
if (!seed_migration_status_.empty())
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(ui::material::OnSurfaceMedium()), "%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::PopStyleColor();
ImGui::Spacing();
ui::RenderSeedWordGrid(ui::SplitSeedWords(seed_migration_seed_));
ImGui::Spacing();
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(ui::material::OnSurfaceMedium()), "New wallet receive address:");
ImGui::TextWrapped("%s", seed_migration_dest_.c_str());
ImGui::Spacing();
if (ui::material::StyledButton("Copy seed", ImVec2(120, 0)))
copySecretToClipboard(seed_migration_seed_);
ImGui::SameLine();
if (ui::material::StyledButton("Save to file", 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;
}
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::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::PopStyleColor();
ImGui::Separator();
if (!seed_migration_backed_up_) ImGui::BeginDisabled();
if (ui::material::StyledButton("Continue to 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))) {
// Throw away the isolated new wallet + clear the pending state.
if (!seed_migration_temp_dir_.empty()) {
std::error_code ec;
std::filesystem::remove_all(seed_migration_temp_dir_, ec);
}
if (settings_) {
settings_->setSeedMigrationPending(false);
settings_->setSeedMigrationDest("");
settings_->setSeedMigrationTempDir("");
settings_->save();
}
seed_migration_temp_dir_.clear();
seed_migration_dest_.clear();
close();
}
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.");
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());
if (state_.isLocked()) {
ImGui::Spacing();
ImGui::PushStyleColor(ImGuiCol_Text, ui::material::Error());
ImGui::TextWrapped("Unlock your wallet first to spend from it.");
ImGui::PopStyleColor();
}
ImGui::Spacing();
ImGui::Separator();
{
const bool canSweep = !state_.isLocked() && seed_migration_balance_ > 0.0;
if (!canSweep) ImGui::BeginDisabled();
if (ui::material::StyledButton("Sweep all funds", ImVec2(170, 0)))
beginSweepToSeedWallet();
if (!canSweep) ImGui::EndDisabled();
}
ImGui::SameLine();
if (ui::material::StyledButton("Refresh", ImVec2(110, 0)))
refreshSeedMigrationBalance();
ImGui::SameLine();
if (ui::material::StyledButton("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::Spacing();
if (!seed_migration_status_.empty())
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(ui::material::OnSurfaceMedium()),
"%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::Spacing();
ImGui::TextColored(medium, "Sweep confirmations: %d", seed_migration_sweep_confs_);
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::Spacing();
ImGui::Separator();
if (confirmed && legacyEmpty) {
if (ui::material::StyledButton("Make this my wallet", 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::PopStyleColor();
if (ui::material::StyledButton("Sweep remaining", ImVec2(180, 0)))
beginSweepToSeedWallet();
} else {
ImGui::TextColored(medium, "Waiting for the sweep transaction to be mined…");
}
ImGui::SameLine();
if (ui::material::StyledButton("Refresh", ImVec2(110, 0)))
pollSweepStatus();
ImGui::SameLine();
if (ui::material::StyledButton("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::Spacing();
if (!seed_migration_status_.empty())
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(ui::material::OnSurfaceMedium()),
"%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::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.");
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());
ImGui::TextWrapped("%s", seed_migration_status_.c_str());
ImGui::PopStyleColor();
}
ImGui::Spacing();
ImGui::Separator();
if (ui::material::StyledButton("Done", ImVec2(120, 0)))
close();
break;
case SeedMigrationStep::Error:
ImGui::PushStyleColor(ImGuiCol_Text, ui::material::Error());
ImGui::TextWrapped("%s", seed_migration_status_.c_str());
ImGui::PopStyleColor();
ImGui::Spacing();
ImGui::Separator();
if (ui::material::StyledButton("Close", ImVec2(120, 0)))
close();
break;
}
ui::material::EndOverlayDialog();
// A real dismiss (Esc/outside/X) or a button close() leaves the flag false — scrub the seed.
if (!show_seed_migration_) wipeSeed();
}
void App::renderAntivirusHelpDialog()
{
#ifdef _WIN32
@@ -3471,7 +3835,12 @@ void App::beginShutdown()
shutdown_timer_ = 0.0f;
shutdown_start_time_ = std::chrono::steady_clock::now();
async_tasks_.cancelAll();
// The seed-migration adopt task drives daemon stop/start and swaps wallet.dat; let it finish
// before shutdown touches the daemon, so the two never race. shutting_down_ is already set, so
// the adopt task will NOT restart the daemon (it checks shutting_down_ before startEmbeddedDaemon).
if (async_tasks_.isRunning("Adopt seed wallet"))
async_tasks_.join("Adopt seed wallet");
// Signal the RPC worker to stop accepting new tasks (non-blocking), and abort any call
// already in flight so the later join() doesn't wait out a request timeout.
// The actual thread join + rpc disconnect happen in shutdown() after

View File

@@ -9,6 +9,7 @@
#include <functional>
#include <thread>
#include <atomic>
#include <mutex>
#include <chrono>
#include <unordered_map>
#include <unordered_set>
@@ -295,6 +296,13 @@ public:
// Wallet backup
void backupWallet(const std::string& destination, std::function<void(bool, const std::string&)> callback);
// Export the wallet's BIP39 seed phrase (z_exportmnemonic). The callback receives
// (ok, noMnemonic, phrase, error): ok+phrase on success; noMnemonic=true when the
// wallet's seed is not mnemonic-derived (legacy wallet). Full-node only; the phrase
// is a secret and is wiped after the callback returns.
void exportSeedPhrase(std::function<void(bool ok, bool noMnemonic,
const std::string& phrase,
const std::string& error)> callback);
// Transaction operations
void sendTransaction(const std::string& from, const std::string& to,
@@ -344,6 +352,8 @@ public:
void showImportKeyDialog() { show_import_key_ = true; }
void showExportKeyDialog() { show_export_key_ = true; }
void showBackupDialog() { show_backup_ = true; }
void showSeedBackupDialog() { show_seed_backup_ = true; }
void showSeedMigrationDialog(); // opens the migration modal (resumes a pending one at Sweep)
void showAboutDialog() { show_about_ = true; }
// Legacy tab compat — maps int to NavPage
@@ -599,6 +609,18 @@ private:
// variants); derives via deriveChatIdentityFromSecret and wipes the secret. No-op when the
// feature is off, already provisioned, in flight, or unavailable.
void maybeProvisionChatIdentity();
// One-time nudge: on a full-node wallet that has a mnemonic, remind the user (once per
// install) to back up their seed phrase. Cheap early-outs keep it idle until it can act.
void maybeRemindSeedBackup();
// Seed-wallet migration (Phase 1: create a new mnemonic wallet in isolation, no funds moved).
void beginCreateSeedWallet(); // starts the isolated create on a background thread
void pumpSeedMigration(); // main thread: pick up background progress/result each frame
// Phase 2: sweep all legacy funds into the new wallet, then adopt it as the primary wallet.
void refreshSeedMigrationBalance(); // query the legacy total (shown on the Sweep step)
void beginSweepToSeedWallet(); // z_mergetoaddress ["ANY_TADDR","ANY_ZADDR"] -> dest
void pollSweepStatus(); // Confirming step: poll sweep confirmations + legacy balance
void beginAdoptSeedWallet(); // stop daemon -> swap wallet.dat -> restart with -rescan
void provisionChatIdentityFromSecret(std::string secret);
std::string chatReplyZaddr(); // a stable (persisted) wallet z-addr for chat
std::string generateChatLocalId(const char* prefix, int numBytes) const; // unique echo id / cid
@@ -656,6 +678,43 @@ private:
bool show_import_key_ = false;
bool show_export_key_ = false;
bool show_backup_ = false;
bool show_seed_backup_ = false;
// Seed-phrase backup dialog state. seed_backup_phrase_ holds a SECRET (the revealed
// mnemonic) and is wiped with sodium_memzero when the dialog closes.
std::string seed_backup_phrase_;
std::string seed_backup_status_;
bool seed_backup_fetch_started_ = false;
bool seed_backup_loading_ = false;
bool seed_backup_no_mnemonic_ = false;
bool seed_backup_reminder_in_flight_ = false; // guards the one-time backup nudge probe
// --- Seed-wallet migration (Phase 1: create; Phase 2: sweep + adopt) ---
enum class SeedMigrationStep { Intro, Working, ShowSeed, Sweep, Sweeping, Confirming, Adopting, Done, Error };
bool show_seed_migration_ = false;
SeedMigrationStep seed_migration_step_ = SeedMigrationStep::Intro;
bool seed_migration_in_flight_ = false; // main-thread guard while the bg create task runs
std::string seed_migration_seed_; // SECRET — the revealed phrase, wiped on close
std::string seed_migration_dest_; // new shielded z-address (Phase 2 sweep target)
std::string seed_migration_temp_dir_; // temp datadir root holding the new wallet (kept)
bool seed_migration_backed_up_ = false; // "I've written it down" confirmation
std::string seed_migration_status_; // main-thread display (progress / error text)
double seed_migration_balance_ = 0.0; // legacy total to sweep (shown on the Sweep step)
std::string seed_migration_sweep_txid_; // the z_mergetoaddress sweep transaction id
int seed_migration_sweep_confs_ = 0; // confirmations of the sweep tx (adopt gate: >= 1)
double seed_migration_legacy_remaining_ = -1.0; // legacy balance after sweep (-1 = unknown)
float seed_migration_poll_timer_ = 0.0f; // throttles the Confirming-step poll
bool seed_migration_confirm_in_flight_ = false; // guards the confirm poll
// Cross-thread handoff from the background create task (guarded by seed_migration_mutex_).
std::mutex seed_migration_mutex_;
std::string seed_migration_progress_; // latest progress line
bool seed_migration_done_ = false; // create result ready to consume
bool seed_migration_ok_ = false;
std::string seed_migration_r_seed_, seed_migration_r_dest_, seed_migration_r_tmp_, seed_migration_r_err_;
// Cross-thread handoff from the background adopt task (guarded by seed_migration_mutex_).
bool seed_migration_adopt_done_ = false;
bool seed_migration_adopt_ok_ = false;
std::string seed_migration_adopt_err_;
// Embedded daemon state
bool use_embedded_daemon_ = wallet::supportsEmbeddedDaemon(wallet::currentWalletCapabilities());
@@ -918,6 +977,8 @@ private:
void renderImportKeyDialog();
void renderExportKeyDialog();
void renderBackupDialog();
void renderSeedBackupDialog(); // full-node "Back up seed phrase" modal (z_exportmnemonic)
void renderSeedMigrationDialog(); // "Migrate to a seed wallet" guided modal (Phase 1: create)
void renderFirstRunWizard();
void renderLockScreen();
void renderEncryptWalletDialog();

View File

@@ -39,8 +39,10 @@
#include "config/settings.h"
#include "wallet/lite_wallet_controller.h" // lite send/new-address routing
#include "wallet/lite_wallet_state_mapper.h" // LiteWalletAppRefreshModel for lite chat harvest
#include "config/version.h"
#include "daemon/daemon_controller.h"
#include "daemon/embedded_daemon.h"
#include "daemon/seed_wallet_creator.h"
#include "daemon/xmrig_manager.h"
#include "util/pool_registry.h"
#include "ui/notifications.h"
@@ -59,6 +61,8 @@
#include <cmath>
#include <ctime>
#include <filesystem>
#include <thread>
#include <chrono>
#include <fstream>
#include <utility>
@@ -109,7 +113,9 @@ const char* tracePageName(ui::NavPage page)
case ui::NavPage::Mining: return "Mining tab";
case ui::NavPage::Market: return "Market tab";
case ui::NavPage::Console: return "Console tab";
case ui::NavPage::LiteConsole: return "Console tab"; // lite-only sibling of Console
case ui::NavPage::Peers: return "Network tab";
case ui::NavPage::LiteNetwork: return "Network tab"; // lite-only sibling of Peers
case ui::NavPage::Explorer: return "Explorer tab";
case ui::NavPage::Settings: return "Settings";
case ui::NavPage::Count_: break;
@@ -207,6 +213,10 @@ void App::tryConnect()
if (connection_in_progress_) return;
// Don't fight an in-progress restart/adopt orchestration: while it stops the daemon, swaps
// wallet.dat (seed migration), and restarts, tryConnect must NOT start the daemon underneath it.
if (daemon_restarting_) return;
static int connect_attempt = 0;
++connect_attempt;
@@ -2861,6 +2871,377 @@ void App::importPrivateKey(const std::string& rawKey, std::function<void(bool, c
});
}
void App::exportSeedPhrase(std::function<void(bool, bool, const std::string&, const std::string&)> callback)
{
if (!state_.connected || !rpc_ || !worker_) {
if (callback) callback(false, false, std::string(), "Not connected to the daemon.");
return;
}
worker_->post([this, callback]() -> rpc::RPCWorker::MainCb {
std::string phrase; // SECRET — wiped after the callback runs
std::string err;
bool ok = false;
bool noMnemonic = false;
rpc::RPCClient::TraceScope trace("Settings / Export seed phrase");
try {
auto response = rpc_->call("z_exportmnemonic");
if (response.contains("mnemonic") && response["mnemonic"].is_string()) {
auto& m = response["mnemonic"].get_ref<std::string&>();
phrase = m;
if (!m.empty()) sodium_memzero(&m[0], m.size()); // scrub the json's own copy
ok = !phrase.empty();
} else {
err = "The daemon returned no seed phrase.";
}
} catch (const rpc::RpcError& e) {
err = e.what();
// The daemon errors with this specific message when the wallet's seed is not
// mnemonic-derived (a legacy wallet). Any other error (e.g. locked) stays generic.
if (err.find("not derived from a mnemonic") != std::string::npos)
noMnemonic = true;
} catch (const std::exception& e) {
err = e.what();
}
return [callback, ok, noMnemonic, phrase = std::move(phrase), err]() mutable {
if (callback) callback(ok, noMnemonic, phrase, err);
if (!phrase.empty()) sodium_memzero(&phrase[0], phrase.size());
};
});
}
// One-time nudge to back up the seed phrase on a mnemonic-backed full-node wallet. Fires at
// most one z_exportmnemonic probe per install; the phrase is not retained (the probe only
// learns whether a mnemonic exists). Legacy (non-mnemonic) wallets are not nagged.
void App::maybeRemindSeedBackup()
{
if (lite_wallet_) return; // lite has its own seed UX
if (!settings_ || settings_->getSeedBackupReminded()) return;
if (!state_.connected || !state_.encryption_state_known) return;
if (state_.isLocked()) return; // wait until unlocked to read it
if (seed_backup_reminder_in_flight_) return;
seed_backup_reminder_in_flight_ = true;
exportSeedPhrase([this](bool ok, bool noMnemonic, const std::string& /*phrase*/,
const std::string& /*error*/) {
seed_backup_reminder_in_flight_ = false;
// Only mark "reminded" once we have a definitive answer, so a transient failure retries
// next session rather than silently suppressing the reminder forever.
if (ok || noMnemonic) {
settings_->setSeedBackupReminded(true);
settings_->save();
}
if (ok)
ui::Notifications::instance().info(TR("seed_backup_reminder"), 12.0f);
});
}
void App::beginCreateSeedWallet()
{
if (seed_migration_in_flight_) return;
seed_migration_in_flight_ = true;
seed_migration_step_ = SeedMigrationStep::Working;
{
std::lock_guard<std::mutex> lk(seed_migration_mutex_);
seed_migration_done_ = false;
seed_migration_progress_ = "Starting…";
}
// Runs the isolated create on a background thread; the main thread picks up progress + the
// result in pumpSeedMigration(). No funds move and the real wallet is never touched.
async_tasks_.submit("Create seed wallet", [this](const util::AsyncTaskManager::Token&) {
auto res = daemon::SeedWalletCreator::create(/*keepDatadir=*/true,
[this](const std::string& msg) {
std::lock_guard<std::mutex> lk(seed_migration_mutex_);
seed_migration_progress_ = msg;
});
std::lock_guard<std::mutex> lk(seed_migration_mutex_);
seed_migration_ok_ = res.ok;
seed_migration_r_seed_ = res.seedPhrase;
seed_migration_r_dest_ = res.destAddress;
seed_migration_r_tmp_ = res.tempDatadir;
seed_migration_r_err_ = res.error;
seed_migration_done_ = true;
if (!res.seedPhrase.empty()) sodium_memzero(&res.seedPhrase[0], res.seedPhrase.size());
});
}
void App::showSeedMigrationDialog()
{
show_seed_migration_ = true;
// Resume a pending migration. If a sweep was already submitted (txid persisted), resume at the
// confirm/adopt stage — re-derived from the chain — rather than sweeping again; otherwise start
// at the Sweep step. With no pending migration, start fresh at the intro.
if (settings_ && settings_->getSeedMigrationPending() && !settings_->getSeedMigrationDest().empty()) {
seed_migration_dest_ = settings_->getSeedMigrationDest();
seed_migration_temp_dir_ = settings_->getSeedMigrationTempDir();
seed_migration_sweep_txid_ = settings_->getSeedMigrationSweepTxid();
if (!seed_migration_sweep_txid_.empty()) {
seed_migration_sweep_confs_ = 0;
seed_migration_legacy_remaining_ = -1.0;
seed_migration_poll_timer_ = 0.0f; // poll immediately
seed_migration_step_ = SeedMigrationStep::Confirming;
} else {
seed_migration_step_ = SeedMigrationStep::Sweep;
refreshSeedMigrationBalance();
}
} else {
seed_migration_step_ = SeedMigrationStep::Intro;
}
}
void App::refreshSeedMigrationBalance()
{
if (!rpc_ || !worker_ || !state_.connected) return;
worker_->post([this]() -> rpc::RPCWorker::MainCb {
double total = 0.0; bool ok = false;
rpc::RPCClient::TraceScope trace("Migrate / balance");
try {
auto res = rpc_->call("z_gettotalbalance");
if (res.contains("total") && res["total"].is_string())
total = std::stod(res["total"].get<std::string>());
ok = true;
} catch (...) {}
return [this, total, ok]() { if (ok) seed_migration_balance_ = total; };
});
}
// Phase 2 step 1: sweep ALL legacy funds (transparent + shielded) into the new seed wallet's
// address. z_mergetoaddress with 0,0 limits merges as many inputs as fit in one transaction; a
// huge-input wallet may leave a small remainder in the (preserved) legacy backup.
void App::beginSweepToSeedWallet()
{
if (!rpc_ || !worker_ || !state_.connected) {
seed_migration_status_ = "Not connected to the daemon.";
seed_migration_step_ = SeedMigrationStep::Error; return;
}
if (seed_migration_dest_.empty()) {
seed_migration_status_ = "No destination address for the sweep.";
seed_migration_step_ = SeedMigrationStep::Error; return;
}
seed_migration_step_ = SeedMigrationStep::Sweeping;
seed_migration_status_ = "Building the sweep transaction…";
const std::string dest = seed_migration_dest_;
worker_->post([this, dest]() -> rpc::RPCWorker::MainCb {
std::string opid, err;
rpc::RPCClient::TraceScope trace("Migrate / sweep");
try {
json fromAddrs = json::array({"ANY_TADDR", "ANY_ZADDR"});
auto res = rpc_->call("z_mergetoaddress", {fromAddrs, dest, DRAGONX_DEFAULT_FEE, 0, 0});
opid = res.value("opid", std::string());
if (opid.empty()) err = "The daemon returned no operation id for the sweep.";
} catch (const std::exception& e) { err = e.what(); }
return [this, opid, err]() {
if (!err.empty() || opid.empty()) {
seed_migration_status_ = err.empty() ? "The sweep failed to start." : err;
seed_migration_step_ = SeedMigrationStep::Error;
return;
}
pending_send_callbacks_[opid] = [this](bool ok, const std::string& result) {
if (ok) {
seed_migration_sweep_txid_ = result;
// Persist the txid so a restart resumes at the confirm/adopt stage and never
// re-sweeps from scratch. The Confirming step gates adopt on this tx being mined
// (>= 1 confirmation) AND the legacy balance dropping to ~0.
if (settings_) { settings_->setSeedMigrationSweepTxid(result); settings_->save(); }
seed_migration_sweep_confs_ = 0;
seed_migration_legacy_remaining_ = -1.0;
seed_migration_poll_timer_ = 0.0f;
seed_migration_status_.clear();
seed_migration_step_ = SeedMigrationStep::Confirming;
} else {
seed_migration_status_ = result.empty() ? "The sweep transaction failed." : result;
seed_migration_step_ = SeedMigrationStep::Error;
}
};
trackOperation(opid);
seed_migration_status_ = "Waiting for the sweep transaction to be accepted…";
};
});
}
// Confirming step: poll the sweep tx's confirmations + the legacy wallet's remaining balance. The
// adopt step is gated on the tx being mined (confs >= 1) AND the legacy balance being ~0, so we
// never swap wallet.dat while the funds could still bounce back (dropped/reorged tx) or while a
// remainder is left behind (a sweep too big for one transaction).
void App::pollSweepStatus()
{
if (!rpc_ || !worker_ || !state_.connected) return;
if (seed_migration_confirm_in_flight_ || seed_migration_sweep_txid_.empty()) return;
seed_migration_confirm_in_flight_ = true;
const std::string txid = seed_migration_sweep_txid_;
worker_->post([this, txid]() -> rpc::RPCWorker::MainCb {
int confs = 0; double remaining = -1.0; bool ok = false;
rpc::RPCClient::TraceScope trace("Migrate / confirm");
try {
auto tx = rpc_->call("gettransaction", {txid});
if (tx.contains("confirmations") && tx["confirmations"].is_number())
confs = tx["confirmations"].get<int>();
auto bal = rpc_->call("z_gettotalbalance");
if (bal.contains("total") && bal["total"].is_string())
remaining = std::stod(bal["total"].get<std::string>());
ok = true;
} catch (...) {}
return [this, confs, remaining, ok]() {
seed_migration_confirm_in_flight_ = false;
if (ok) {
seed_migration_sweep_confs_ = confs;
seed_migration_legacy_remaining_ = remaining;
}
};
});
}
// Phase 2 step 2: adopt the new seed wallet as the primary wallet. Stop the daemon, move the
// legacy wallet.dat aside to a timestamped backup (NEVER delete it), copy the new wallet in, and
// restart with -rescan so the new keys pick up the swept funds. Runs on a background thread.
void App::beginAdoptSeedWallet()
{
seed_migration_step_ = SeedMigrationStep::Adopting;
seed_migration_status_ = "Restarting with your new wallet — this rescan can take a while…";
{ std::lock_guard<std::mutex> lk(seed_migration_mutex_); seed_migration_adopt_done_ = false; }
// Gate the main-loop reconnect so tryConnect can't start the daemon while we swap wallet.dat.
daemon_restarting_ = true;
if (rpc_ && rpc_->isConnected()) rpc_->disconnect();
onDisconnected("Adopting seed wallet");
const std::string base = seed_migration_temp_dir_;
async_tasks_.submit("Adopt seed wallet", [this, base](const util::AsyncTaskManager::Token&) {
namespace fs = std::filesystem;
std::string err; // fatal (swap did not happen; migration incomplete)
std::string warn; // non-fatal (swap done but the daemon did not restart)
bool swapDone = false;
try {
std::error_code ec;
// 1. Stop the main daemon and wait for it to fully exit.
stopEmbeddedDaemon();
for (int i = 0; i < 60 && isEmbeddedDaemonRunning(); ++i)
std::this_thread::sleep_for(std::chrono::milliseconds(500));
if (isEmbeddedDaemonRunning()) {
err = "The daemon did not stop in time; your wallet was not changed.";
} else {
// 2. Swap wallet.dat. Move the legacy one aside to a timestamped backup (NEVER
// delete), then copy the new seed wallet in. On any failure, restore the legacy.
const std::string datadir = util::Platform::getDragonXDataDir();
const std::string legacy = datadir + "/wallet.dat";
const std::string newWallet = base + "/DRAGONX/wallet.dat";
std::time_t t = std::time(nullptr);
std::tm tmv{}; localtime_r(&t, &tmv); // thread-safe (the UI thread also uses localtime)
char ts[32]; std::strftime(ts, sizeof(ts), "%Y%m%d-%H%M%S", &tmv);
const std::string backup = legacy + ".legacy-migrated-" + ts + ".bak";
if (!fs::exists(newWallet)) {
err = "The new wallet file is missing; your wallet was not changed.";
} else {
bool movedLegacy = false;
if (fs::exists(legacy)) {
fs::rename(legacy, backup, ec);
if (ec) err = "Could not back up your current wallet; nothing was changed.";
else movedLegacy = true;
}
if (err.empty()) {
fs::copy_file(newWallet, legacy, fs::copy_options::overwrite_existing, ec);
if (ec) {
if (movedLegacy) { std::error_code ec2; fs::rename(backup, legacy, ec2); }
err = "Could not install the new wallet; your original wallet was restored.";
} else {
swapDone = true;
}
}
}
}
// 3. Rescan on next start (only if the swap happened) and bring the daemon back up —
// unless we're quitting, in which case don't resurrect it.
if (swapDone && daemon_controller_) daemon_controller_->setRescanOnNextStart(true);
if (!shutting_down_) {
if (!startEmbeddedDaemon() && swapDone)
warn = "Your wallet was swapped, but the daemon did not restart — start it from Settings.";
}
} catch (const std::exception& e) {
err = std::string("Migration failed: ") + e.what();
} catch (...) {
err = "Migration failed due to an unexpected error.";
}
daemon_restarting_ = false; // ALWAYS re-arm the reconnect gate, even on a throw
std::lock_guard<std::mutex> lk(seed_migration_mutex_);
// Migration counts as done once the swap succeeded (funds already moved + wallet installed);
// a restart hiccup is only a warning. If the swap never happened, it's a full error and the
// pending state is kept so the user can retry.
seed_migration_adopt_ok_ = swapDone;
seed_migration_adopt_err_ = swapDone ? warn : err;
seed_migration_adopt_done_ = true;
});
}
void App::pumpSeedMigration()
{
// --- Adopt handoff (Phase 2, background daemon swap) ---
{
bool done = false, ok = false; std::string err;
{
std::lock_guard<std::mutex> lk(seed_migration_mutex_);
if (seed_migration_adopt_done_) {
done = true; ok = seed_migration_adopt_ok_; err = seed_migration_adopt_err_;
seed_migration_adopt_done_ = false;
}
}
if (done) {
if (ok) {
if (!seed_migration_temp_dir_.empty()) {
std::error_code ec; std::filesystem::remove_all(seed_migration_temp_dir_, ec);
}
if (settings_) {
settings_->setSeedMigrationPending(false);
settings_->setSeedMigrationDest("");
settings_->setSeedMigrationTempDir("");
settings_->setSeedMigrationSweepTxid("");
settings_->save();
}
seed_migration_status_ = err; // a non-empty warning here (e.g. restart hiccup) is shown on Done
seed_migration_step_ = SeedMigrationStep::Done;
} else {
seed_migration_status_ = err.empty() ? "Adopting the new wallet failed." : err;
seed_migration_step_ = SeedMigrationStep::Error;
}
}
}
// --- Create handoff (Phase 1, background isolated create) ---
if (!seed_migration_in_flight_) return;
bool done = false, ok = false;
std::string seed, dest, tmp, err;
{
std::lock_guard<std::mutex> lk(seed_migration_mutex_);
seed_migration_status_ = seed_migration_progress_; // live progress for the Working step
done = seed_migration_done_;
if (done) {
ok = seed_migration_ok_;
seed = std::move(seed_migration_r_seed_);
dest = std::move(seed_migration_r_dest_);
tmp = std::move(seed_migration_r_tmp_);
err = std::move(seed_migration_r_err_);
seed_migration_done_ = false;
seed_migration_r_seed_.clear();
}
}
if (!done) return;
seed_migration_in_flight_ = false;
if (ok) {
seed_migration_seed_ = std::move(seed);
seed_migration_dest_ = std::move(dest);
seed_migration_temp_dir_ = std::move(tmp);
seed_migration_backed_up_ = false;
seed_migration_step_ = SeedMigrationStep::ShowSeed;
// Persist the pending migration so a later sweep/adopt step can find the new wallet.
if (settings_) {
settings_->setSeedMigrationPending(true);
settings_->setSeedMigrationDest(seed_migration_dest_);
settings_->setSeedMigrationTempDir(seed_migration_temp_dir_);
settings_->save();
}
} else {
seed_migration_status_ = err.empty() ? std::string("Could not create the seed wallet.") : err;
seed_migration_step_ = SeedMigrationStep::Error;
}
}
void App::backupWallet(const std::string& destination, std::function<void(bool, const std::string&)> callback)
{
if (!state_.connected || !rpc_) {

View File

@@ -199,6 +199,11 @@ bool Settings::load(const std::string& path)
}
}
loadScalar(j, "wizard_completed", wizard_completed_);
loadScalar(j, "seed_backup_reminded", seed_backup_reminded_);
loadScalar(j, "seed_migration_pending", seed_migration_pending_);
loadScalar(j, "seed_migration_dest", seed_migration_dest_);
loadScalar(j, "seed_migration_temp_dir", seed_migration_temp_dir_);
loadScalar(j, "seed_migration_sweep_txid", seed_migration_sweep_txid_);
loadScalar(j, "auto_lock_timeout", auto_lock_timeout_);
loadScalar(j, "unlock_duration", unlock_duration_);
loadScalar(j, "pin_enabled", pin_enabled_);
@@ -432,6 +437,11 @@ bool Settings::save(const std::string& path)
j["address_meta"] = meta_obj;
}
j["wizard_completed"] = wizard_completed_;
j["seed_backup_reminded"] = seed_backup_reminded_;
j["seed_migration_pending"] = seed_migration_pending_;
j["seed_migration_dest"] = seed_migration_dest_;
j["seed_migration_temp_dir"] = seed_migration_temp_dir_;
j["seed_migration_sweep_txid"] = seed_migration_sweep_txid_;
j["auto_lock_timeout"] = auto_lock_timeout_;
j["unlock_duration"] = unlock_duration_;
j["pin_enabled"] = pin_enabled_;

View File

@@ -246,6 +246,23 @@ public:
bool getWizardCompleted() const { return wizard_completed_; }
void setWizardCompleted(bool v) { wizard_completed_ = v; }
// Whether the one-time "back up your seed phrase" reminder has already been shown.
bool getSeedBackupReminded() const { return seed_backup_reminded_; }
void setSeedBackupReminded(bool v) { seed_backup_reminded_ = v; }
// Pending "migrate to a seed wallet" state (Phase 1 created the wallet; a later sweep/adopt
// step consumes it). dest = the new wallet's sweep-target z-address; tempDir = its datadir.
bool getSeedMigrationPending() const { return seed_migration_pending_; }
void setSeedMigrationPending(bool v) { seed_migration_pending_ = v; }
std::string getSeedMigrationDest() const { return seed_migration_dest_; }
void setSeedMigrationDest(const std::string& v) { seed_migration_dest_ = v; }
std::string getSeedMigrationTempDir() const { return seed_migration_temp_dir_; }
void setSeedMigrationTempDir(const std::string& v) { seed_migration_temp_dir_ = v; }
// The sweep transaction id, persisted once the sweep is submitted — non-empty means the
// migration is past the sweep, so a resume goes to the confirm/adopt stage (not sweep again).
std::string getSeedMigrationSweepTxid() const { return seed_migration_sweep_txid_; }
void setSeedMigrationSweepTxid(const std::string& v) { seed_migration_sweep_txid_ = v; }
// Security — auto-lock timeout (seconds; 0 = disabled)
int getAutoLockTimeout() const { return auto_lock_timeout_; }
void setAutoLockTimeout(int seconds) { auto_lock_timeout_ = seconds; }
@@ -444,6 +461,11 @@ private:
std::set<std::string> favorite_addresses_;
std::map<std::string, AddressMeta> address_meta_;
bool wizard_completed_ = false;
bool seed_backup_reminded_ = false;
bool seed_migration_pending_ = false;
std::string seed_migration_dest_;
std::string seed_migration_temp_dir_;
std::string seed_migration_sweep_txid_;
int auto_lock_timeout_ = 900; // 15 minutes
int unlock_duration_ = 600; // 10 minutes
bool pin_enabled_ = false;

View File

@@ -212,6 +212,11 @@ std::vector<std::string> EmbeddedDaemon::getChainParams()
"-addnode=node4.dragonx.is",
"-experimentalfeatures",
"-developerencryptwallet",
// Create fresh wallets from a BIP39 mnemonic so their 24-word phrase can be
// exported (z_exportmnemonic) and is portable to SDXLite/ObsidianDragonLite.
// The daemon reads this ONLY inside GenerateNewSeed() when a wallet has no seed
// yet, so it is inert on existing wallets — safe to pass unconditionally.
"-usemnemonic=1",
dbcache_arg
};
}
@@ -443,9 +448,10 @@ bool EmbeddedDaemon::start(const std::string& binary_path)
return true;
}
// Check if something is already listening on the RPC port
// Check if something is already listening on the RPC port. An isolated instance (migrate-to-
// seed) runs on its own non-default port alongside the main daemon, so it skips this bail.
int rpc_port = std::atoi(DRAGONX_DEFAULT_RPC_PORT);
if (isPortInUse(rpc_port)) {
if (!skip_port_check_ && isPortInUse(rpc_port)) {
std::string owner = getPortOwnerInfo(rpc_port);
VERBOSE_LOGF("[INFO] Port %d is already in use by %s — external daemon detected, will connect to it.\\n", rpc_port, owner.c_str());
external_daemon_detected_ = true;
@@ -493,7 +499,20 @@ bool EmbeddedDaemon::start(const std::string& binary_path)
DEBUG_LOGF("[INFO] Adding -rescan flag for blockchain rescan\n");
args.push_back("-rescan");
}
// One-shot isolated-datadir override (migrate-to-seed flow): run this start against a
// throwaway datadir, plus any extra args (e.g. -connect=0). Consumed here so later starts
// revert to the normal datadir. The datadir's basename MUST be the assetchain name (DRAGONX)
// or the daemon mis-resolves its conf/port; it reads <datadir>/DRAGONX.conf automatically, so
// no -conf is passed (an explicit -conf confuses the Komodo/Hush path resolution).
if (!override_datadir_.empty()) {
DEBUG_LOGF("[INFO] Isolated start override: -datadir=%s\n", override_datadir_.c_str());
args.push_back("-datadir=" + override_datadir_);
}
for (const auto& a : override_extra_args_) args.push_back(a);
override_datadir_.clear();
override_extra_args_.clear();
if (!startProcess(daemon_path, args)) {
DEBUG_LOGF("[ERROR] Failed to start dragonxd process: %s\\n", last_error_.c_str());
setState(State::Error, "Failed to start dragonxd process");
@@ -1215,5 +1234,10 @@ bool EmbeddedDaemon::isRpcPortInUse()
return isPortInUse(port);
}
bool EmbeddedDaemon::tcpPortInUse(int port)
{
return isPortInUse(port);
}
} // namespace daemon
} // namespace dragonx

View File

@@ -191,6 +191,29 @@ public:
void setZapOnNextStart(bool v) { zap_on_next_start_ = v; }
bool zapOnNextStart() const { return zap_on_next_start_.load(); }
/**
* @brief One-shot isolated-datadir override for the NEXT start(): run the daemon against a
* different datadir (with its own DRAGONX.conf) plus the given extra args. Used by the
* "migrate to a seed wallet" flow to mint a fresh mnemonic wallet in a throwaway datadir
* without touching the real one. Consumed on the next start(); later starts are normal.
* The caller must serialize this with start() (no concurrent starts).
*/
void setNextStartOverride(const std::string& datadir, std::vector<std::string> extraArgs) {
override_datadir_ = datadir;
override_extra_args_ = std::move(extraArgs);
}
void clearNextStartOverride() { override_datadir_.clear(); override_extra_args_.clear(); }
/**
* @brief Skip the "default RPC port already in use → external daemon" bail in start().
* Set true only for an isolated instance running on its OWN (non-default) port
* alongside the main daemon (migrate-to-seed flow).
*/
void setSkipPortCheck(bool v) { skip_port_check_ = v; }
/** @brief Is an arbitrary TCP port currently in use on localhost? (used to pick a free port) */
static bool tcpPortInUse(int port);
/** Get number of consecutive daemon crashes (resets on successful start or manual reset) */
int getCrashCount() const { return crash_count_.load(); }
/** Reset crash counter (call on successful connection or manual restart) */
@@ -231,6 +254,9 @@ private:
std::atomic<int> crash_count_{0}; // consecutive crash counter
std::atomic<bool> rescan_on_next_start_{false}; // -rescan flag for next start
std::atomic<bool> zap_on_next_start_{false}; // -zapwallettxes=2 flag for next start
std::string override_datadir_; // one-shot: -datadir for the next start
std::vector<std::string> override_extra_args_; // one-shot: extra args for the next start
bool skip_port_check_ = false; // isolated instance on a non-default port
};
} // namespace daemon

View File

@@ -0,0 +1,138 @@
#include "daemon/seed_wallet_creator.h"
#include <chrono>
#include <filesystem>
#include <thread>
#include <sodium.h>
#include "daemon/embedded_daemon.h"
#include "rpc/rpc_client.h"
#include "util/platform.h"
namespace fs = std::filesystem;
namespace dragonx {
namespace daemon {
namespace {
// Random alphanumeric token for the isolated node's throwaway RPC credentials (libsodium CSPRNG;
// sodium_init() has already run at app startup for the chat crypto).
std::string randomToken(int n)
{
static const char cs[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
std::string s;
s.reserve(n);
for (int i = 0; i < n; ++i)
s.push_back(cs[randombytes_uniform(sizeof(cs) - 1)]);
return s;
}
// A free localhost port for the isolated node — just above the default so it never collides with
// the main daemon (which keeps running on the default port throughout).
int pickFreePort()
{
for (int p = 21770; p < 21900; ++p)
if (!EmbeddedDaemon::tcpPortInUse(p))
return p;
return 0;
}
} // namespace
SeedWalletResult SeedWalletCreator::create(bool keepDatadir,
const std::function<void(const std::string&)>& progress)
{
auto report = [&](const std::string& m) { if (progress) progress(m); };
SeedWalletResult r;
std::error_code ec;
// 1. Isolated throwaway datadir. The Komodo/Hush daemon requires the datadir's basename to be
// the assetchain name (DRAGONX) — mirroring ~/.hush/DRAGONX — or it mis-resolves its conf and
// RPC port. So the wallet lives in <base>/DRAGONX; `base` is the migration root we clean up.
const std::string base = util::Platform::getConfigDir() + "/seed-migrate";
const std::string dataDir = base + "/DRAGONX";
fs::remove_all(base, ec);
fs::create_directories(dataDir, ec);
if (ec) { r.error = "Could not create the temporary wallet directory."; return r; }
// 2. Free port + fresh throwaway RPC credentials for the isolated node.
const int port = pickFreePort();
if (port <= 0) { r.error = "No free local port for the isolated node."; return r; }
const std::string user = randomToken(16);
const std::string pass = randomToken(32);
// 3. Minimal conf for the isolated node (own creds/port). The DRAGONX RPC is plaintext HTTP on
// localhost — `-tls=only` applies to P2P, not the RPC — so the client below connects without
// TLS, exactly as the main GUI does (its conf has no rpctls key either).
const std::string conf = "rpcuser=" + user + "\n"
"rpcpassword=" + pass + "\n"
"rpcport=" + std::to_string(port) + "\n"
"server=1\n";
if (!util::Platform::writeFileAtomically(dataDir + "/DRAGONX.conf", conf,
/*restrictPermissions=*/true)) {
r.error = "Could not write the isolated node config.";
fs::remove_all(base, ec);
return r;
}
// 4. Start the isolated daemon: fresh mnemonic wallet (-usemnemonic=1), no network/sync.
report("Starting an isolated node…");
EmbeddedDaemon temp;
temp.setSkipPortCheck(true); // runs on `port`, beside the main daemon on the default port
temp.setNextStartOverride(dataDir, {"-usemnemonic=1", "-connect=0", "-listen=0",
"-maxconnections=0"});
if (!temp.start("")) {
r.error = "Could not start the isolated node: " + temp.getLastError();
fs::remove_all(base, ec);
return r;
}
// 5. Connect to it, retrying until the RPC is responsive and past warmup.
report("Creating your new seed wallet…");
rpc::RPCClient cli;
bool ready = false;
for (int i = 0; i < 90 && !ready; ++i) {
if (cli.connect("127.0.0.1", std::to_string(port), user, pass, /*useTls=*/false)) {
try { cli.call("getinfo"); ready = true; } // succeeds only once past warmup (-28)
catch (...) { cli.disconnect(); }
}
if (!ready) std::this_thread::sleep_for(std::chrono::seconds(1));
}
if (!ready) {
r.error = "The isolated node did not become ready in time.";
temp.stop(20000);
fs::remove_all(base, ec);
return r;
}
// 6. Export the new seed phrase + a fresh shielded receive address (the future sweep target).
try {
auto m = cli.call("z_exportmnemonic");
if (m.contains("mnemonic") && m["mnemonic"].is_string())
r.seedPhrase = m["mnemonic"].get<std::string>();
r.destAddress = cli.call("z_getnewaddress").get<std::string>();
r.ok = !r.seedPhrase.empty() && !r.destAddress.empty();
if (!r.ok) r.error = "The isolated node returned an empty seed or address.";
} catch (const std::exception& e) {
r.error = std::string("Seed export failed: ") + e.what();
}
// 7. Stop the isolated node (graceful; it flushes its tiny empty chain quickly).
cli.disconnect();
temp.stop(20000);
// 8. Keep the temp wallet for a later sweep/adopt step, or scrub it. tempDatadir is the
// migration root `base`; the new wallet.dat lives in <base>/DRAGONX.
r.tempDatadir = base;
if (!keepDatadir || !r.ok) {
fs::remove_all(base, ec);
r.tempDatadir.clear();
}
return r;
}
} // namespace daemon
} // namespace dragonx

View File

@@ -0,0 +1,32 @@
#pragma once
#include <functional>
#include <string>
namespace dragonx {
namespace daemon {
struct SeedWalletResult {
bool ok = false;
std::string seedPhrase; // SECRET — the caller must wipe it after use
std::string destAddress; // new shielded z-address (the Phase 2 sweep target)
std::string tempDatadir; // datadir holding the new wallet.dat (kept iff keepDatadir + ok)
std::string error;
};
// Mint a fresh BIP39 mnemonic wallet in an ISOLATED throwaway datadir by running a second
// dragonxd on its own port with no network, export its seed + a new z-address, then stop it.
//
// This is the safe first step of "migrate to a seed wallet": it moves no funds and never touches
// the main daemon or the real wallet.dat. Blocking — call it on a background thread.
//
// keepDatadir: keep the temp datadir + its wallet.dat so a later sweep/adopt step can use it, or
// delete it immediately (used when only the seed itself is wanted).
class SeedWalletCreator {
public:
static SeedWalletResult create(bool keepDatadir,
const std::function<void(const std::string&)>& progress = {});
};
} // namespace daemon
} // namespace dragonx

View File

@@ -25,7 +25,9 @@
#include "ui/effects/theme_effects.h"
#include "util/texture_loader.h"
#include "util/platform.h"
#include "daemon/seed_wallet_creator.h"
#include "resources/embedded_resources.h"
#include <sodium.h>
// Backend-specific headers
#ifdef DRAGONX_USE_DX11
@@ -652,6 +654,22 @@ int main(int argc, char* argv[])
DEBUG_LOGF("Built with Dear ImGui %s\n", IMGUI_VERSION);
fflush(stdout);
// Env-gated headless smoke for the isolated seed-wallet creator (migrate-to-seed Phase 1).
// Exercises SeedWalletCreator::create() end-to-end without the GUI, then exits. Secret-safe:
// it never prints the seed words — only ok/word-count/address/error. Run with an isolated HOME.
if (const char* smk = std::getenv("DRAGONX_SEED_CREATE_SMOKE"); smk && std::string(smk) == "1") {
sodium_init();
printf("[seed-create-smoke] starting isolated create...\n"); fflush(stdout);
auto r = dragonx::daemon::SeedWalletCreator::create(/*keepDatadir=*/false,
[](const std::string& m) { printf("[seed-create-smoke] %s\n", m.c_str()); fflush(stdout); });
int words = 0; bool inWord = false;
for (char c : r.seedPhrase) { bool sp = (c == ' '); if (!sp && !inWord) { inWord = true; ++words; } else if (sp) inWord = false; }
printf("[seed-create-smoke] ok=%d words=%d addr=%s err=%s\n",
r.ok ? 1 : 0, words, r.destAddress.c_str(), r.error.c_str());
if (!r.seedPhrase.empty()) sodium_memzero(&r.seedPhrase[0], r.seedPhrase.size());
return r.ok ? 0 : 1;
}
// Check for existing instance
if (!g_single_instance.tryLock()) {
fprintf(stderr, "Another instance of ObsidianDragon is already running.\n");

View File

@@ -1304,8 +1304,11 @@ void RenderSettingsPage(App* app) {
naturalW += ImGui::CalcTextSize(r1[i]).x + btnPadX;
float wizW = showFullNodeLifecycleActions ? ImGui::CalcTextSize(wizLabel).x + btnPadX : 0.0f;
float bsW = showFullNodeLifecycleActions ? ImGui::CalcTextSize(bsLabel).x + btnPadX : 0.0f;
// Full-node-only "Seed phrase" + "Migrate to seed" buttons trail the Backup button.
float seedW = showFullNodeLifecycleActions ? ImGui::CalcTextSize(TR("seed_backup_button")).x + btnPadX : 0.0f;
float migrateW = showFullNodeLifecycleActions ? ImGui::CalcTextSize(TR("seed_migrate_button")).x + btnPadX : 0.0f;
float totalW = naturalW + sp * 5;
if (showFullNodeLifecycleActions) totalW += wizW + bsW + sp * 2;
if (showFullNodeLifecycleActions) totalW += wizW + bsW + seedW + migrateW + sp * 4;
float scale = (totalW > contentW) ? contentW / totalW : 1.0f;
if (scale < 1.0f) ImGui::SetWindowFontScale(scale);
@@ -1326,6 +1329,18 @@ void RenderSettingsPage(App* app) {
if (TactileButton(r1[3], ImVec2(0, 0), btnFont))
app->showBackupDialog();
if (ImGui::IsItemHovered()) material::Tooltip("%s", t1[3]);
if (showFullNodeLifecycleActions) {
// Back up the wallet's BIP39 seed phrase (full-node mnemonic wallets).
ImGui::SameLine(0, scaledSp);
if (TactileButton(TR("seed_backup_button"), ImVec2(0, 0), btnFont))
app->showSeedBackupDialog();
if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_seed_backup"));
// Migrate to a new seed-phrase wallet (create in isolation, then sweep funds).
ImGui::SameLine(0, scaledSp);
if (TactileButton(TR("seed_migrate_button"), ImVec2(0, 0), btnFont))
app->showSeedMigrationDialog();
if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_seed_migrate"));
}
ImGui::SameLine(0, scaledSp);
if (TactileButton(r1[4], ImVec2(0, 0), btnFont))
ExportTransactionsDialog::show();

View File

@@ -0,0 +1,46 @@
#pragma once
// Shared helpers for rendering a BIP39 seed phrase as a numbered word grid and for
// splitting a whitespace-separated phrase into words. Used by the full-node seed-phrase
// backup dialog and the "migrate to a seed wallet" flow so both present the phrase the
// same way the lite welcome wizard does.
#include <cstdio>
#include <string>
#include <vector>
#include "imgui.h"
namespace dragonx {
namespace ui {
// Split a whitespace-separated seed phrase into its individual words.
inline std::vector<std::string> SplitSeedWords(const std::string& phrase)
{
std::vector<std::string> words;
std::string cur;
for (char c : phrase) {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
if (!cur.empty()) { words.push_back(cur); cur.clear(); }
} else {
cur.push_back(c);
}
}
if (!cur.empty()) words.push_back(cur);
return words;
}
// Render the words as a numbered 4-column grid (matches the lite welcome wizard layout).
inline void RenderSeedWordGrid(const std::vector<std::string>& words, float colSpacingPx = 130.0f)
{
for (size_t i = 0; i < words.size(); ++i) {
char cell[96];
std::snprintf(cell, sizeof(cell), "%2zu. %s", i + 1, words[i].c_str());
ImGui::TextUnformatted(cell);
if ((i % 4) != 3 && i + 1 < words.size())
ImGui::SameLine(((i % 4) + 1) * colSpacingPx);
}
}
} // namespace ui
} // namespace dragonx

View File

@@ -233,6 +233,24 @@ void I18n::loadBuiltinEnglish()
strings_["chat_toast_compose_failed"] = "Could not compose the message (too long?).";
strings_["chat_toast_request_compose_failed"] = "Could not compose the contact request (invalid address / text?).";
strings_["chat_toast_request_queued"] = "Contact request queued.";
// Seed-phrase backup (full-node)
strings_["seed_backup_button"] = "Seed phrase";
strings_["tt_seed_backup"] = "Show and back up your wallet's 24-word recovery seed phrase";
strings_["seed_backup_title"] = "Back up seed phrase";
strings_["seed_backup_intro"] = "These words are the master backup of your wallet. Anyone who has them controls your funds.";
strings_["seed_backup_warning"] = "Write them down in order, store them offline, and never share or photograph them. If you lose them, your funds cannot be recovered.";
strings_["seed_backup_loading"] = "Loading your seed phrase…";
strings_["seed_backup_locked"] = "Unlock your wallet to reveal its seed phrase.";
strings_["seed_backup_none"] = "This wallet predates seed phrases, so it has no 24-word phrase. Back it up with \"Backup wallet\" or by exporting your private keys instead.";
strings_["seed_backup_load_failed"] = "Could not load the seed phrase.";
strings_["seed_backup_copy"] = "Copy";
strings_["seed_backup_save"] = "Save to file…";
strings_["seed_backup_saved"] = "Saved to ";
strings_["seed_backup_save_failed"] = "Could not write ";
strings_["seed_backup_close"] = "Close";
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";
strings_["contacts_search_placeholder"] = "Search contacts...";
strings_["contacts_search_no_match"] = "No matching contacts";
strings_["address_book_confirm_delete"] = "Confirm delete?";