diff --git a/res/fonts/NotoSansCJK-Subset.ttf b/res/fonts/NotoSansCJK-Subset.ttf index 03f8277..67c8994 100644 Binary files a/res/fonts/NotoSansCJK-Subset.ttf and b/res/fonts/NotoSansCJK-Subset.ttf differ diff --git a/res/lang/de.json b/res/lang/de.json index 95ca511..85302ae 100644 --- a/res/lang/de.json +++ b/res/lang/de.json @@ -1369,6 +1369,61 @@ "warning_upper": "WARNUNG!", "website": "Webseite", "window_opacity": "Fenster-Transparenz", + "wiz_acrylic": "Acryl-Glaseffekte", + "wiz_acrylic_desc": "Transparente Unschärfe auf Panels (Aus deaktiviert)", + "wiz_already_encrypted": "Wallet ist bereits verschlüsselt", + "wiz_already_encrypted_desc": "Ihr Wallet ist mit einer Passphrase geschützt. Es sind keine weiteren Schritte erforderlich.", + "wiz_appearance": "Darstellung", + "wiz_bootstrap": "Bootstrap", + "wiz_bootstrap_desc": "Laden Sie ein Blockchain-Bootstrap herunter, um die anfängliche Synchronisierung erheblich zu beschleunigen.\n\nIhre vorhandene wallet.dat wird NICHT verändert oder ersetzt.", + "wiz_bootstrap_failed": "Bootstrap fehlgeschlagen", + "wiz_confirm": "Bestätigen:", + "wiz_continue": "Weiter", + "wiz_daemon_sending_stop": "Stopp-Befehl wird gesendet...", + "wiz_daemon_stop_failed": "Daemon wurde nicht gestoppt — manuell versuchen.", + "wiz_daemon_stopped_ok": "Daemon gestoppt.", + "wiz_daemon_waiting_stop": "Warten, bis der Daemon herunterfährt...", + "wiz_download_failed": "Download fehlgeschlagen", + "wiz_encrypt_bg": "Die Verschlüsselung wird im Hintergrund abgeschlossen", + "wiz_encrypt_continue": "Verschlüsseln & Weiter", + "wiz_encrypt_desc": "Verschlüsseln Sie Ihr Wallet, um private Schlüssel mit einer Passphrase zu schützen.", + "wiz_encrypt_warning": "Wenn Sie Ihre Passphrase verlieren, verlieren Sie den Zugriff auf Ihr Guthaben.", + "wiz_encryption": "Verschlüsselung", + "wiz_ext_daemon_running": "Externer Daemon läuft", + "wiz_ext_daemon_warning": "Er muss gestoppt werden, bevor ein Bootstrap heruntergeladen wird, sonst könnten Chain-Daten beschädigt werden.", + "wiz_level": "Stufe:", + "wiz_lowspec_desc": "Alle aufwendigen visuellen Effekte deaktivieren", + "wiz_off": "Aus", + "wiz_pass_mismatch": "Passphrasen stimmen nicht überein", + "wiz_pass_spaces": "Passphrase hat führende/nachfolgende Leerzeichen — entfernen Sie diese", + "wiz_pass_too_short": "Passphrase muss mindestens 8 Zeichen lang sein (%zu/8)", + "wiz_passphrase": "Passphrase:", + "wiz_pin_confirm": "PIN bestätigen:", + "wiz_pin_invalid": "PIN muss 4-8 Ziffern haben", + "wiz_pin_label": "PIN (4-8 Ziffern):", + "wiz_pin_mismatch": "PINs stimmen nicht überein", + "wiz_pin_optional": "Schnellentsperr-PIN (optional)", + "wiz_pin_title": "Schnellentsperr-PIN", + "wiz_scanline_desc": "CRT-Scanline-Effekt in der Konsole", + "wiz_skip": "Überspringen", + "wiz_skip_confirm": "OHNE Verschlüsselung fortfahren? Schlüssel werden unverschlüsselt gespeichert — klicken Sie erneut auf Überspringen, um zu bestätigen.", + "wiz_step1": "Schritt 1", + "wiz_step2": "Schritt 2", + "wiz_step3": "Schritt 3", + "wiz_stop_daemon": "Daemon stoppen", + "wiz_strength": "Stärke: %s", + "wiz_strength_fair": "Mäßig", + "wiz_strength_good": "Gut", + "wiz_strength_strong": "Stark", + "wiz_strength_weak": "Schwach", + "wiz_theme_builtin": "Integriert", + "wiz_theme_custom": "Benutzerdefiniert", + "wiz_theme_effects": "Visuelle Theme-Effekte", + "wiz_theme_effects_desc": "Animierte Ränder, Farbverlauf", + "wiz_theme_invalid": " (ungültig)", + "wiz_ui_opacity_desc": "Transparenz von Karten & Seitenleiste (1.0 = deckend)", + "wiz_welcome_sub": "Ein paar schnelle Einstellungen und Ihr Full Node ist bereit.", + "wiz_welcome_title": "Willkommen bei ObsidianDragon!", "wizard_daemon_start_failed": "Daemon-Start fehlgeschlagen — wird automatisch wiederholt", "xmrig_browse_releases": "Alle Releases durchsuchen…", "xmrig_checking": "Nach dem neuesten Miner wird gesucht…", diff --git a/res/lang/es.json b/res/lang/es.json index 2350c49..36cb94d 100644 --- a/res/lang/es.json +++ b/res/lang/es.json @@ -1369,6 +1369,61 @@ "warning_upper": "¡ADVERTENCIA!", "website": "Sitio Web", "window_opacity": "Opacidad de ventana", + "wiz_acrylic": "Efectos de vidrio acrílico", + "wiz_acrylic_desc": "Desenfoque translúcido en paneles (Desactivado lo apaga)", + "wiz_already_encrypted": "La cartera ya está cifrada", + "wiz_already_encrypted_desc": "Tu cartera está protegida con una frase de contraseña. No es necesaria ninguna acción adicional.", + "wiz_appearance": "Apariencia", + "wiz_bootstrap": "Bootstrap", + "wiz_bootstrap_desc": "Descarga un bootstrap de la cadena de bloques para acelerar drásticamente la sincronización inicial.\\n\\nTu wallet.dat existente NO se modificará ni se reemplazará.", + "wiz_bootstrap_failed": "Error en el bootstrap", + "wiz_confirm": "Confirmar:", + "wiz_continue": "Continuar", + "wiz_daemon_sending_stop": "Enviando comando de detención...", + "wiz_daemon_stop_failed": "El daemon no se detuvo — inténtalo manualmente.", + "wiz_daemon_stopped_ok": "Daemon detenido.", + "wiz_daemon_waiting_stop": "Esperando a que el daemon se cierre...", + "wiz_download_failed": "Error de descarga", + "wiz_encrypt_bg": "El cifrado se completará en segundo plano", + "wiz_encrypt_continue": "Cifrar y continuar", + "wiz_encrypt_desc": "Cifra tu cartera para proteger las claves privadas con una frase de contraseña.", + "wiz_encrypt_warning": "Si pierdes tu frase de contraseña, pierdes el acceso a tus fondos.", + "wiz_encryption": "Cifrado", + "wiz_ext_daemon_running": "Daemon externo en ejecución", + "wiz_ext_daemon_warning": "Debe detenerse antes de descargar un bootstrap; de lo contrario, los datos de la cadena podrían corromperse.", + "wiz_level": "Nivel:", + "wiz_lowspec_desc": "Desactivar todos los efectos visuales pesados", + "wiz_off": "Desactivado", + "wiz_pass_mismatch": "Las frases de contraseña no coinciden", + "wiz_pass_spaces": "La frase de contraseña tiene espacios al inicio o al final — elimínalos", + "wiz_pass_too_short": "La frase de contraseña debe tener al menos 8 caracteres (%zu/8)", + "wiz_passphrase": "Frase de contraseña:", + "wiz_pin_confirm": "Confirmar PIN:", + "wiz_pin_invalid": "El PIN debe tener entre 4 y 8 dígitos", + "wiz_pin_label": "PIN (4-8 dígitos):", + "wiz_pin_mismatch": "Los PIN no coinciden", + "wiz_pin_optional": "PIN de desbloqueo rápido (opcional)", + "wiz_pin_title": "PIN de desbloqueo rápido", + "wiz_scanline_desc": "Efecto de líneas de barrido CRT en la consola", + "wiz_skip": "Omitir", + "wiz_skip_confirm": "¿Continuar SIN cifrado? Las claves se almacenarán sin cifrar — haz clic en Omitir de nuevo para confirmar.", + "wiz_step1": "Paso 1", + "wiz_step2": "Paso 2", + "wiz_step3": "Paso 3", + "wiz_stop_daemon": "Detener daemon", + "wiz_strength": "Seguridad: %s", + "wiz_strength_fair": "Aceptable", + "wiz_strength_good": "Buena", + "wiz_strength_strong": "Fuerte", + "wiz_strength_weak": "Débil", + "wiz_theme_builtin": "Integrado", + "wiz_theme_custom": "Personalizado", + "wiz_theme_effects": "Efectos visuales del tema", + "wiz_theme_effects_desc": "Bordes animados, capa de color", + "wiz_theme_invalid": " (no válido)", + "wiz_ui_opacity_desc": "Transparencia de tarjetas y barra lateral (1.0 = sólido)", + "wiz_welcome_sub": "Unas cuantas opciones rápidas y tu nodo completo estará listo.", + "wiz_welcome_title": "¡Bienvenido a ObsidianDragon!", "wizard_daemon_start_failed": "Error al iniciar el daemon — se reintentará automáticamente", "xmrig_browse_releases": "Ver todos los lanzamientos…", "xmrig_checking": "Buscando el minero más reciente…", diff --git a/res/lang/fr.json b/res/lang/fr.json index c088f6e..2fab1c6 100644 --- a/res/lang/fr.json +++ b/res/lang/fr.json @@ -1369,6 +1369,61 @@ "warning_upper": "ATTENTION !", "website": "Site web", "window_opacity": "Opacité de la fenêtre", + "wiz_acrylic": "Effets de verre acrylique", + "wiz_acrylic_desc": "Flou translucide sur les panneaux (Désactivé les coupe)", + "wiz_already_encrypted": "Le portefeuille est déjà chiffré", + "wiz_already_encrypted_desc": "Votre portefeuille est protégé par une phrase secrète. Aucune autre action n'est nécessaire.", + "wiz_appearance": "Apparence", + "wiz_bootstrap": "Amorçage", + "wiz_bootstrap_desc": "Téléchargez un amorçage de la blockchain pour accélérer considérablement la synchronisation initiale.\n\nVotre fichier wallet.dat existant NE sera PAS modifié ni remplacé.", + "wiz_bootstrap_failed": "Échec de l'amorçage", + "wiz_confirm": "Confirmer :", + "wiz_continue": "Continuer", + "wiz_daemon_sending_stop": "Envoi de la commande d'arrêt...", + "wiz_daemon_stop_failed": "Le démon ne s'est pas arrêté — essayez manuellement.", + "wiz_daemon_stopped_ok": "Démon arrêté.", + "wiz_daemon_waiting_stop": "En attente de l'arrêt du démon...", + "wiz_download_failed": "Échec du téléchargement", + "wiz_encrypt_bg": "Le chiffrement se terminera en arrière-plan", + "wiz_encrypt_continue": "Chiffrer et continuer", + "wiz_encrypt_desc": "Chiffrez votre portefeuille pour protéger les clés privées avec une phrase secrète.", + "wiz_encrypt_warning": "Si vous perdez votre phrase secrète, vous perdez l'accès à vos fonds.", + "wiz_encryption": "Chiffrement", + "wiz_ext_daemon_running": "Démon externe en cours d'exécution", + "wiz_ext_daemon_warning": "Il doit être arrêté avant de télécharger un amorçage, sinon les données de la chaîne pourraient être corrompues.", + "wiz_level": "Niveau :", + "wiz_lowspec_desc": "Désactiver tous les effets visuels lourds", + "wiz_off": "Désactivé", + "wiz_pass_mismatch": "Les phrases secrètes ne correspondent pas", + "wiz_pass_spaces": "La phrase secrète comporte des espaces en début/fin — supprimez-les", + "wiz_pass_too_short": "La phrase secrète doit comporter au moins 8 caractères (%zu/8)", + "wiz_passphrase": "Phrase secrète :", + "wiz_pin_confirm": "Confirmer le PIN :", + "wiz_pin_invalid": "Le PIN doit comporter 4 à 8 chiffres", + "wiz_pin_label": "PIN (4 à 8 chiffres) :", + "wiz_pin_mismatch": "Les PIN ne correspondent pas", + "wiz_pin_optional": "PIN de déverrouillage rapide (facultatif)", + "wiz_pin_title": "PIN de déverrouillage rapide", + "wiz_scanline_desc": "Effet de lignes de balayage CRT dans la console", + "wiz_skip": "Ignorer", + "wiz_skip_confirm": "Continuer SANS chiffrement ? Les clés seront stockées non chiffrées — cliquez à nouveau sur Ignorer pour confirmer.", + "wiz_step1": "Étape 1", + "wiz_step2": "Étape 2", + "wiz_step3": "Étape 3", + "wiz_stop_daemon": "Arrêter le démon", + "wiz_strength": "Robustesse : %s", + "wiz_strength_fair": "Moyenne", + "wiz_strength_good": "Bonne", + "wiz_strength_strong": "Forte", + "wiz_strength_weak": "Faible", + "wiz_theme_builtin": "Intégré", + "wiz_theme_custom": "Personnalisé", + "wiz_theme_effects": "Effets visuels du thème", + "wiz_theme_effects_desc": "Bordures animées, voile de couleur", + "wiz_theme_invalid": " (non valide)", + "wiz_ui_opacity_desc": "Transparence des cartes et de la barre latérale (1.0 = opaque)", + "wiz_welcome_sub": "Quelques choix rapides et votre nœud complet est prêt.", + "wiz_welcome_title": "Bienvenue dans ObsidianDragon !", "wizard_daemon_start_failed": "Échec du démarrage du daemon — sera réessayé automatiquement", "xmrig_browse_releases": "Parcourir toutes les versions…", "xmrig_checking": "Recherche du dernier mineur…", diff --git a/res/lang/ja.json b/res/lang/ja.json index 6ffc0ee..2a3cf5d 100644 --- a/res/lang/ja.json +++ b/res/lang/ja.json @@ -1369,6 +1369,61 @@ "warning_upper": "警告!", "website": "ウェブサイト", "window_opacity": "ウィンドウ透明度", + "wiz_acrylic": "アクリルガラス効果", + "wiz_acrylic_desc": "パネルの半透明ぼかし(オフで無効化)", + "wiz_already_encrypted": "ウォレットはすでに暗号化されています", + "wiz_already_encrypted_desc": "ウォレットはパスフレーズで保護されています。これ以上の操作は不要です。", + "wiz_appearance": "外観", + "wiz_bootstrap": "ブートストラップ", + "wiz_bootstrap_desc": "ブロックチェーンのブートストラップをダウンロードして初回同期を大幅に高速化します。\\n\\n既存の wallet.dat は変更も置き換えもされません。", + "wiz_bootstrap_failed": "ブートストラップに失敗しました", + "wiz_confirm": "確認:", + "wiz_continue": "続行", + "wiz_daemon_sending_stop": "停止コマンドを送信中...", + "wiz_daemon_stop_failed": "デーモンが停止しませんでした — 手動でお試しください。", + "wiz_daemon_stopped_ok": "デーモンを停止しました。", + "wiz_daemon_waiting_stop": "デーモンの終了を待機中...", + "wiz_download_failed": "ダウンロードに失敗しました", + "wiz_encrypt_bg": "暗号化はバックグラウンドで完了します", + "wiz_encrypt_continue": "暗号化して続行", + "wiz_encrypt_desc": "ウォレットを暗号化して、パスフレーズで秘密鍵を保護します。", + "wiz_encrypt_warning": "パスフレーズを紛失すると、資金にアクセスできなくなります。", + "wiz_encryption": "暗号化", + "wiz_ext_daemon_running": "外部デーモンが実行中です", + "wiz_ext_daemon_warning": "ブートストラップをダウンロードする前に停止する必要があります。停止しないとチェーンデータが破損する可能性があります。", + "wiz_level": "レベル:", + "wiz_lowspec_desc": "重い視覚効果をすべて無効にする", + "wiz_off": "オフ", + "wiz_pass_mismatch": "パスフレーズが一致しません", + "wiz_pass_spaces": "パスフレーズの先頭または末尾に空白があります — 削除してください", + "wiz_pass_too_short": "パスフレーズは 8 文字以上にしてください(%zu/8)", + "wiz_passphrase": "パスフレーズ:", + "wiz_pin_confirm": "PIN の確認:", + "wiz_pin_invalid": "PIN は 4〜8 桁にしてください", + "wiz_pin_label": "PIN(4〜8 桁):", + "wiz_pin_mismatch": "PIN が一致しません", + "wiz_pin_optional": "クイックロック解除 PIN(任意)", + "wiz_pin_title": "クイックロック解除 PIN", + "wiz_scanline_desc": "コンソールの CRT 走査線効果", + "wiz_skip": "スキップ", + "wiz_skip_confirm": "暗号化せずに続行しますか? 鍵は暗号化されずに保存されます — もう一度スキップをクリックして確認してください。", + "wiz_step1": "ステップ 1", + "wiz_step2": "ステップ 2", + "wiz_step3": "ステップ 3", + "wiz_stop_daemon": "デーモンを停止", + "wiz_strength": "強度:%s", + "wiz_strength_fair": "まずまず", + "wiz_strength_good": "良い", + "wiz_strength_strong": "強い", + "wiz_strength_weak": "弱い", + "wiz_theme_builtin": "内蔵", + "wiz_theme_custom": "カスタム", + "wiz_theme_effects": "テーマの視覚効果", + "wiz_theme_effects_desc": "枠のアニメーション、カラーウォッシュ", + "wiz_theme_invalid": " (無効)", + "wiz_ui_opacity_desc": "カードとサイドバーの透明度(1.0 = 不透明)", + "wiz_welcome_sub": "いくつか選ぶだけでフルノードの準備が整います。", + "wiz_welcome_title": "ObsidianDragon へようこそ!", "wizard_daemon_start_failed": "デーモンの起動に失敗しました — 自動的に再試行されます", "xmrig_browse_releases": "すべてのリリースを表示…", "xmrig_checking": "最新のマイナーを確認中…", diff --git a/res/lang/ko.json b/res/lang/ko.json index 5f87a6d..0b04f66 100644 --- a/res/lang/ko.json +++ b/res/lang/ko.json @@ -1369,6 +1369,61 @@ "warning_upper": "경고!", "website": "웹사이트", "window_opacity": "창 투명도", + "wiz_acrylic": "아크릴 유리 효과", + "wiz_acrylic_desc": "패널에 반투명 블러 적용 (끄면 비활성화)", + "wiz_already_encrypted": "지갑이 이미 암호화되어 있습니다", + "wiz_already_encrypted_desc": "지갑이 암호로 보호되어 있습니다. 추가 작업이 필요하지 않습니다.", + "wiz_appearance": "모양", + "wiz_bootstrap": "부트스트랩", + "wiz_bootstrap_desc": "블록체인 부트스트랩을 다운로드하여 초기 동기화 속도를 크게 높입니다.\\n\\n기존 wallet.dat은 수정되거나 교체되지 않습니다.", + "wiz_bootstrap_failed": "부트스트랩 실패", + "wiz_confirm": "확인:", + "wiz_continue": "계속", + "wiz_daemon_sending_stop": "중지 명령 전송 중...", + "wiz_daemon_stop_failed": "데몬이 중지되지 않았습니다 — 수동으로 시도하세요.", + "wiz_daemon_stopped_ok": "데몬이 중지되었습니다.", + "wiz_daemon_waiting_stop": "데몬 종료를 기다리는 중...", + "wiz_download_failed": "다운로드 실패", + "wiz_encrypt_bg": "암호화는 백그라운드에서 완료됩니다", + "wiz_encrypt_continue": "암호화 후 계속", + "wiz_encrypt_desc": "지갑을 암호화하여 암호로 개인 키를 보호합니다.", + "wiz_encrypt_warning": "암호를 분실하면 자금에 접근할 수 없게 됩니다.", + "wiz_encryption": "암호화", + "wiz_ext_daemon_running": "외부 데몬 실행 중", + "wiz_ext_daemon_warning": "부트스트랩을 다운로드하기 전에 데몬을 중지해야 합니다. 그렇지 않으면 체인 데이터가 손상될 수 있습니다.", + "wiz_level": "수준:", + "wiz_lowspec_desc": "모든 무거운 시각 효과 끄기", + "wiz_off": "끔", + "wiz_pass_mismatch": "암호가 일치하지 않습니다", + "wiz_pass_spaces": "암호 앞뒤에 공백이 있습니다 — 제거하세요", + "wiz_pass_too_short": "암호는 8자 이상이어야 합니다 (%zu/8)", + "wiz_passphrase": "암호:", + "wiz_pin_confirm": "PIN 확인:", + "wiz_pin_invalid": "PIN은 4-8자리여야 합니다", + "wiz_pin_label": "PIN (4-8자리):", + "wiz_pin_mismatch": "PIN이 일치하지 않습니다", + "wiz_pin_optional": "빠른 잠금 해제 PIN (선택 사항)", + "wiz_pin_title": "빠른 잠금 해제 PIN", + "wiz_scanline_desc": "콘솔의 CRT 스캔라인 효과", + "wiz_skip": "건너뛰기", + "wiz_skip_confirm": "암호화 없이 계속하시겠습니까? 키가 암호화되지 않은 채로 저장됩니다 — 확인하려면 건너뛰기를 다시 클릭하세요.", + "wiz_step1": "1단계", + "wiz_step2": "2단계", + "wiz_step3": "3단계", + "wiz_stop_daemon": "데몬 중지", + "wiz_strength": "강도: %s", + "wiz_strength_fair": "보통", + "wiz_strength_good": "양호", + "wiz_strength_strong": "강함", + "wiz_strength_weak": "약함", + "wiz_theme_builtin": "기본 제공", + "wiz_theme_custom": "사용자 지정", + "wiz_theme_effects": "테마 시각 효과", + "wiz_theme_effects_desc": "애니메이션 테두리, 컬러 워시", + "wiz_theme_invalid": " (잘못됨)", + "wiz_ui_opacity_desc": "카드 및 사이드바 투명도 (1.0 = 불투명)", + "wiz_welcome_sub": "몇 가지만 선택하면 풀 노드가 준비됩니다.", + "wiz_welcome_title": "ObsidianDragon에 오신 것을 환영합니다!", "wizard_daemon_start_failed": "데몬 시작 실패 — 자동으로 재시도됩니다", "xmrig_browse_releases": "모든 릴리스 보기…", "xmrig_checking": "최신 채굴기를 확인하는 중…", diff --git a/res/lang/pt.json b/res/lang/pt.json index 49ce80d..18fe9c4 100644 --- a/res/lang/pt.json +++ b/res/lang/pt.json @@ -1369,6 +1369,61 @@ "warning_upper": "AVISO!", "website": "Website", "window_opacity": "Opacidade da Janela", + "wiz_acrylic": "Efeitos de vidro acrílico", + "wiz_acrylic_desc": "Desfoque translúcido nos painéis (Desativado remove)", + "wiz_already_encrypted": "A carteira já está encriptada", + "wiz_already_encrypted_desc": "A sua carteira está protegida com uma frase-passe. Não é necessária nenhuma ação adicional.", + "wiz_appearance": "Aparência", + "wiz_bootstrap": "Bootstrap", + "wiz_bootstrap_desc": "Baixe um bootstrap da blockchain para acelerar drasticamente a sincronização inicial.\\n\\nO seu wallet.dat existente NÃO será modificado nem substituído.", + "wiz_bootstrap_failed": "Falha no bootstrap", + "wiz_confirm": "Confirmar:", + "wiz_continue": "Continuar", + "wiz_daemon_sending_stop": "A enviar comando de parada...", + "wiz_daemon_stop_failed": "O daemon não parou — tente manualmente.", + "wiz_daemon_stopped_ok": "Daemon parado.", + "wiz_daemon_waiting_stop": "A aguardar o encerramento do daemon...", + "wiz_download_failed": "Falha no download", + "wiz_encrypt_bg": "A encriptação será concluída em segundo plano", + "wiz_encrypt_continue": "Encriptar e continuar", + "wiz_encrypt_desc": "Encripte a sua carteira para proteger as chaves privadas com uma frase-passe.", + "wiz_encrypt_warning": "Se perder a sua frase-passe, perde o acesso aos seus fundos.", + "wiz_encryption": "Encriptação", + "wiz_ext_daemon_running": "Daemon externo em execução", + "wiz_ext_daemon_warning": "Deve ser parado antes de baixar um bootstrap, caso contrário os dados da cadeia podem ficar corrompidos.", + "wiz_level": "Nível:", + "wiz_lowspec_desc": "Desativar todos os efeitos visuais pesados", + "wiz_off": "Desativado", + "wiz_pass_mismatch": "As frases-passe não coincidem", + "wiz_pass_spaces": "A frase-passe tem espaços no início/fim — remova-os", + "wiz_pass_too_short": "A frase-passe deve ter pelo menos 8 caracteres (%zu/8)", + "wiz_passphrase": "Frase-passe:", + "wiz_pin_confirm": "Confirmar PIN:", + "wiz_pin_invalid": "O PIN deve ter 4-8 dígitos", + "wiz_pin_label": "PIN (4-8 dígitos):", + "wiz_pin_mismatch": "Os PINs não coincidem", + "wiz_pin_optional": "PIN de desbloqueio rápido (opcional)", + "wiz_pin_title": "PIN de desbloqueio rápido", + "wiz_scanline_desc": "Efeito de scanline CRT na consola", + "wiz_skip": "Ignorar", + "wiz_skip_confirm": "Continuar SEM encriptação? As chaves serão armazenadas sem encriptação — clique em Ignorar novamente para confirmar.", + "wiz_step1": "Passo 1", + "wiz_step2": "Passo 2", + "wiz_step3": "Passo 3", + "wiz_stop_daemon": "Parar daemon", + "wiz_strength": "Força: %s", + "wiz_strength_fair": "Razoável", + "wiz_strength_good": "Boa", + "wiz_strength_strong": "Forte", + "wiz_strength_weak": "Fraca", + "wiz_theme_builtin": "Integrado", + "wiz_theme_custom": "Personalizado", + "wiz_theme_effects": "Efeitos visuais do tema", + "wiz_theme_effects_desc": "Bordas animadas, matiz de cor", + "wiz_theme_invalid": " (inválido)", + "wiz_ui_opacity_desc": "Transparência de cartões e barra lateral (1.0 = sólido)", + "wiz_welcome_sub": "Algumas escolhas rápidas e o seu full node estará pronto.", + "wiz_welcome_title": "Bem-vindo ao ObsidianDragon!", "wizard_daemon_start_failed": "Falha ao iniciar o daemon — será tentado novamente automaticamente", "xmrig_browse_releases": "Navegar por todos os lançamentos…", "xmrig_checking": "Verificando o minerador mais recente…", diff --git a/res/lang/ru.json b/res/lang/ru.json index 1948d8d..06642a5 100644 --- a/res/lang/ru.json +++ b/res/lang/ru.json @@ -1369,6 +1369,61 @@ "warning_upper": "ПРЕДУПРЕЖДЕНИЕ!", "website": "Веб-сайт", "window_opacity": "Прозрачность окна", + "wiz_acrylic": "Эффект акрилового стекла", + "wiz_acrylic_desc": "Полупрозрачное размытие панелей (Выкл. отключает)", + "wiz_already_encrypted": "Кошелёк уже зашифрован", + "wiz_already_encrypted_desc": "Ваш кошелёк защищён парольной фразой. Дополнительных действий не требуется.", + "wiz_appearance": "Внешний вид", + "wiz_bootstrap": "Начальная загрузка", + "wiz_bootstrap_desc": "Загрузите начальный образ блокчейна, чтобы значительно ускорить первичную синхронизацию.\\n\\nВаш существующий файл wallet.dat НЕ будет изменён или заменён.", + "wiz_bootstrap_failed": "Ошибка начальной загрузки", + "wiz_confirm": "Подтверждение:", + "wiz_continue": "Продолжить", + "wiz_daemon_sending_stop": "Отправка команды остановки...", + "wiz_daemon_stop_failed": "Демон не остановился — попробуйте вручную.", + "wiz_daemon_stopped_ok": "Демон остановлен.", + "wiz_daemon_waiting_stop": "Ожидание завершения работы демона...", + "wiz_download_failed": "Ошибка загрузки", + "wiz_encrypt_bg": "Шифрование завершится в фоновом режиме", + "wiz_encrypt_continue": "Зашифровать и продолжить", + "wiz_encrypt_desc": "Зашифруйте кошелёк, чтобы защитить приватные ключи парольной фразой.", + "wiz_encrypt_warning": "Если вы потеряете парольную фразу, вы потеряете доступ к своим средствам.", + "wiz_encryption": "Шифрование", + "wiz_ext_daemon_running": "Запущен внешний демон", + "wiz_ext_daemon_warning": "Его необходимо остановить перед загрузкой начального образа, иначе данные цепочки могут быть повреждены.", + "wiz_level": "Уровень:", + "wiz_lowspec_desc": "Отключить все тяжёлые визуальные эффекты", + "wiz_off": "Выкл.", + "wiz_pass_mismatch": "Парольные фразы не совпадают", + "wiz_pass_spaces": "В парольной фразе есть пробелы в начале или конце — удалите их", + "wiz_pass_too_short": "Парольная фраза должна содержать не менее 8 символов (%zu/8)", + "wiz_passphrase": "Парольная фраза:", + "wiz_pin_confirm": "Подтвердите PIN:", + "wiz_pin_invalid": "PIN должен содержать 4–8 цифр", + "wiz_pin_label": "PIN (4–8 цифр):", + "wiz_pin_mismatch": "PIN-коды не совпадают", + "wiz_pin_optional": "PIN быстрой разблокировки (необязательно)", + "wiz_pin_title": "PIN быстрой разблокировки", + "wiz_scanline_desc": "Эффект строк развёртки CRT в консоли", + "wiz_skip": "Пропустить", + "wiz_skip_confirm": "Продолжить БЕЗ шифрования? Ключи будут храниться незашифрованными — нажмите «Пропустить» ещё раз для подтверждения.", + "wiz_step1": "Шаг 1", + "wiz_step2": "Шаг 2", + "wiz_step3": "Шаг 3", + "wiz_stop_daemon": "Остановить демон", + "wiz_strength": "Надёжность: %s", + "wiz_strength_fair": "Средняя", + "wiz_strength_good": "Хорошая", + "wiz_strength_strong": "Надёжная", + "wiz_strength_weak": "Слабая", + "wiz_theme_builtin": "Встроенная", + "wiz_theme_custom": "Своя", + "wiz_theme_effects": "Визуальные эффекты темы", + "wiz_theme_effects_desc": "Анимированные рамки, цветовая заливка", + "wiz_theme_invalid": " (недопустимая)", + "wiz_ui_opacity_desc": "Прозрачность карточек и боковой панели (1.0 = непрозрачно)", + "wiz_welcome_sub": "Несколько быстрых настроек — и ваш полный узел готов.", + "wiz_welcome_title": "Добро пожаловать в ObsidianDragon!", "wizard_daemon_start_failed": "Не удалось запустить демон — будет повторено автоматически", "xmrig_browse_releases": "Просмотреть все релизы…", "xmrig_checking": "Проверка наличия последней версии майнера…", diff --git a/res/lang/zh.json b/res/lang/zh.json index 0899d5a..674a8b1 100644 --- a/res/lang/zh.json +++ b/res/lang/zh.json @@ -1369,6 +1369,61 @@ "warning_upper": "警告!", "website": "网站", "window_opacity": "窗口透明度", + "wiz_acrylic": "亚克力玻璃效果", + "wiz_acrylic_desc": "面板上的半透明模糊(关闭则禁用)", + "wiz_already_encrypted": "钱包已加密", + "wiz_already_encrypted_desc": "您的钱包已使用密码短语进行保护。无需进一步操作。", + "wiz_appearance": "外观", + "wiz_bootstrap": "引导数据", + "wiz_bootstrap_desc": "下载区块链引导数据以大幅加快初始同步速度。\n\n您现有的 wallet.dat 不会被修改或替换。", + "wiz_bootstrap_failed": "引导数据失败", + "wiz_confirm": "确认:", + "wiz_continue": "继续", + "wiz_daemon_sending_stop": "正在发送停止命令…", + "wiz_daemon_stop_failed": "守护进程未停止——请尝试手动停止。", + "wiz_daemon_stopped_ok": "守护进程已停止。", + "wiz_daemon_waiting_stop": "正在等待守护进程关闭…", + "wiz_download_failed": "下载失败", + "wiz_encrypt_bg": "加密将在后台完成", + "wiz_encrypt_continue": "加密并继续", + "wiz_encrypt_desc": "加密您的钱包,用密码短语保护私钥。", + "wiz_encrypt_warning": "如果您丢失密码短语,将无法访问您的资金。", + "wiz_encryption": "加密", + "wiz_ext_daemon_running": "外部守护进程正在运行", + "wiz_ext_daemon_warning": "下载引导数据前必须先停止它,否则链数据可能会损坏。", + "wiz_level": "级别:", + "wiz_lowspec_desc": "禁用所有重度视觉效果", + "wiz_off": "关闭", + "wiz_pass_mismatch": "密码短语不匹配", + "wiz_pass_spaces": "密码短语含有首尾空格——请将其删除", + "wiz_pass_too_short": "密码短语至少需要 8 个字符 (%zu/8)", + "wiz_passphrase": "密码短语:", + "wiz_pin_confirm": "确认 PIN:", + "wiz_pin_invalid": "PIN 必须为 4-8 位数字", + "wiz_pin_label": "PIN(4-8 位数字):", + "wiz_pin_mismatch": "PIN 不匹配", + "wiz_pin_optional": "快速解锁 PIN(可选)", + "wiz_pin_title": "快速解锁 PIN", + "wiz_scanline_desc": "控制台中的 CRT 扫描线效果", + "wiz_skip": "跳过", + "wiz_skip_confirm": "确定不加密继续吗?私钥将以未加密方式存储——请再次点击“跳过”以确认。", + "wiz_step1": "第 1 步", + "wiz_step2": "第 2 步", + "wiz_step3": "第 3 步", + "wiz_stop_daemon": "停止守护进程", + "wiz_strength": "强度:%s", + "wiz_strength_fair": "一般", + "wiz_strength_good": "良好", + "wiz_strength_strong": "强", + "wiz_strength_weak": "弱", + "wiz_theme_builtin": "内置", + "wiz_theme_custom": "自定义", + "wiz_theme_effects": "主题视觉效果", + "wiz_theme_effects_desc": "动态边框、色彩渲染", + "wiz_theme_invalid": " (无效)", + "wiz_ui_opacity_desc": "卡片与侧边栏透明度(1.0 = 不透明)", + "wiz_welcome_sub": "只需几项快速设置,即可启用您的全节点。", + "wiz_welcome_title": "欢迎使用 ObsidianDragon!", "wizard_daemon_start_failed": "启动守护进程失败 — 将自动重试", "xmrig_browse_releases": "浏览所有版本…", "xmrig_checking": "正在检查最新的矿工程序…", diff --git a/src/app_wizard.cpp b/src/app_wizard.cpp index 9fcba07..d36c08c 100644 --- a/src/app_wizard.cpp +++ b/src/app_wizard.cpp @@ -189,14 +189,14 @@ void App::renderFirstRunWizard() { headerCy += logoSize + 8.0f * dp; { - const char* welcomeTitle = "Welcome to ObsidianDragon!"; + const char* welcomeTitle = TR("wiz_welcome_title"); ImVec2 wts = titleFont->CalcTextSizeA(titleFont->LegacySize, FLT_MAX, 0, welcomeTitle); dl->AddText(titleFont, titleFont->LegacySize, ImVec2(winPos.x + (winSize.x - wts.x) * 0.5f, headerCy), textCol, welcomeTitle); headerCy += wts.y + 6.0f * dp; // Warmer, less-sparse header: a one-line subtitle under the welcome (dimmed body). - const char* welcomeSub = "A few quick choices and your full node is ready."; + const char* welcomeSub = TR("wiz_welcome_sub"); ImVec2 sts = bodyFont->CalcTextSizeA(bodyFont->LegacySize, FLT_MAX, 0, welcomeSub); dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(winPos.x + (winSize.x - sts.x) * 0.5f, headerCy), dimCol, welcomeSub); @@ -274,13 +274,13 @@ void App::renderFirstRunWizard() { { float iconW = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, stepIcon(state)).x; dl->AddText(iconFont, iconFont->LegacySize, ImVec2(cx, cy), dimCol, stepIcon(state)); - dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx + iconW + 4.0f * dp, cy), dimCol, "Step 1"); + dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx + iconW + 4.0f * dp, cy), dimCol, TR("wiz_step1")); cy += captionFont->LegacySize + 6.0f * dp; } // Title { - const char* t = "Appearance"; + const char* t = TR("wiz_appearance"); dl->AddText(titleFont, titleFont->LegacySize, ImVec2(cx, cy), textCol, t); cy += titleFont->LegacySize + 10.0f * dp; } @@ -336,14 +336,14 @@ void App::renderFirstRunWizard() { for (const auto& skin : skins) { if (skin.id == skinMgr.activeSkinId()) { activePreview = skin.name; break; } } - dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy + 4.0f * dp), textCol, "Theme"); + dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy + 4.0f * dp), textCol, TR("theme")); float comboX = cx + 110.0f * dp; float comboW = contentW - 110.0f * dp; ImGui::SetCursorScreenPos(ImVec2(comboX, cy)); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f * dp); ImGui::SetNextItemWidth(comboW); if (ImGui::BeginCombo("##wiz_theme", activePreview.c_str())) { - ImGui::TextDisabled("Built-in"); + ImGui::TextDisabled(TR("wiz_theme_builtin")); ImGui::Separator(); for (const auto& skin : skins) { if (!skin.bundled) continue; @@ -359,7 +359,7 @@ void App::renderFirstRunWizard() { for (const auto& skin : skins) { if (!skin.bundled) { hasCustom = true; break; } } if (hasCustom) { ImGui::Spacing(); - ImGui::TextDisabled("Custom"); + ImGui::TextDisabled(TR("wiz_theme_custom")); ImGui::Separator(); for (const auto& skin : skins) { if (skin.bundled) continue; @@ -367,7 +367,7 @@ void App::renderFirstRunWizard() { if (!skin.valid) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1,0.3f,0.3f,1)); ImGui::BeginDisabled(true); - ImGui::Selectable((skin.name + " (invalid)").c_str(), false); + ImGui::Selectable((skin.name + TR("wiz_theme_invalid")).c_str(), false); ImGui::EndDisabled(); ImGui::PopStyleColor(); } else { @@ -395,7 +395,7 @@ void App::renderFirstRunWizard() { for (const auto& l : layouts) { if (l.id == wiz_balance_layout) { balPreview = l.name; break; } } - dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy + 4.0f * dp), textCol, "Balance Layout"); + dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy + 4.0f * dp), textCol, TR("balance_layout")); float comboX = cx + 110.0f * dp; float comboW = contentW - 110.0f * dp; ImGui::SetCursorScreenPos(ImVec2(comboX, cy)); @@ -426,7 +426,7 @@ void App::renderFirstRunWizard() { langNames.reserve(languages.size()); for (const auto& lang : languages) langNames.push_back(lang.second.c_str()); - dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy + 4.0f * dp), textCol, "Language"); + dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy + 4.0f * dp), textCol, TR("language")); float comboX = cx + 110.0f * dp; float comboW = contentW - 110.0f * dp; ImGui::SetCursorScreenPos(ImVec2(comboX, cy)); @@ -497,10 +497,10 @@ void App::renderFirstRunWizard() { ImGui::SameLine(); dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(ImGui::GetCursorScreenPos().x, cy + 2.0f * dp), textCol, - "Low-spec mode"); + TR("low_spec_mode")); cy += bodyFont->LegacySize + 6.0f * dp; dl->AddText(captionFont, captionFont->LegacySize, - ImVec2(cx + 28.0f * dp, cy), dimCol, "Disable all heavy visual effects"); + ImVec2(cx + 28.0f * dp, cy), dimCol, TR("wiz_lowspec_desc")); cy += captionFont->LegacySize + 16.0f * dp; ImGui::BeginDisabled(wiz_low_spec); @@ -508,15 +508,15 @@ void App::renderFirstRunWizard() { // Acrylic blur slider dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx, cy + 2.0f * dp), textCol, - "Acrylic glass effects"); + TR("wiz_acrylic")); cy += bodyFont->LegacySize + 4.0f * dp; dl->AddText(captionFont, captionFont->LegacySize, - ImVec2(cx, cy), dimCol, "Translucent blur on panels (Off disables)"); + ImVec2(cx, cy), dimCol, TR("wiz_acrylic_desc")); cy += captionFont->LegacySize + 10.0f * dp; { dl->AddText(captionFont, captionFont->LegacySize, - ImVec2(cx + 4.0f * dp, cy), textCol, "Level:"); + ImVec2(cx + 4.0f * dp, cy), textCol, TR("wiz_level")); ImGui::SetCursorScreenPos(ImVec2(cx + 72.0f * dp, cy - 2.0f * dp)); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f * dp); float sliderW = contentW - 72.0f * dp; @@ -524,7 +524,7 @@ void App::renderFirstRunWizard() { { char blur_fmt[16]; if (wiz_blur_amount < 0.01f) - snprintf(blur_fmt, sizeof(blur_fmt), "Off"); + snprintf(blur_fmt, sizeof(blur_fmt), TR("wiz_off")); else snprintf(blur_fmt, sizeof(blur_fmt), "%.0f%%%%", wiz_blur_amount * 25.0f); if (ImGui::SliderFloat("##wiz_blur", &wiz_blur_amount, 0.0f, 4.0f, blur_fmt, @@ -558,19 +558,19 @@ void App::renderFirstRunWizard() { ImGui::SameLine(); dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(ImGui::GetCursorScreenPos().x, cy + 2.0f * dp), textCol, - "Theme visual effects"); + TR("wiz_theme_effects")); cy += bodyFont->LegacySize + 6.0f * dp; dl->AddText(captionFont, captionFont->LegacySize, - ImVec2(cx + 28.0f * dp, cy), dimCol, "Animated borders, color wash"); + ImVec2(cx + 28.0f * dp, cy), dimCol, TR("wiz_theme_effects_desc")); cy += captionFont->LegacySize + 16.0f * dp; // UI Opacity slider dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx, cy + 2.0f * dp), textCol, - "UI Opacity"); + TR("ui_opacity")); cy += bodyFont->LegacySize + 4.0f * dp; dl->AddText(captionFont, captionFont->LegacySize, - ImVec2(cx, cy), dimCol, "Card & sidebar transparency (1.0 = solid)"); + ImVec2(cx, cy), dimCol, TR("wiz_ui_opacity_desc")); cy += captionFont->LegacySize + 10.0f * dp; { ImGui::SetCursorScreenPos(ImVec2(cx, cy - 2.0f * dp)); @@ -599,10 +599,10 @@ void App::renderFirstRunWizard() { ImGui::SameLine(); dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(ImGui::GetCursorScreenPos().x, cy + 2.0f * dp), textCol, - "Console scanline"); + TR("console_scanline")); cy += bodyFont->LegacySize + 6.0f * dp; dl->AddText(captionFont, captionFont->LegacySize, - ImVec2(cx + 28.0f * dp, cy), dimCol, "CRT scanline effect in console"); + ImVec2(cx + 28.0f * dp, cy), dimCol, TR("wiz_scanline_desc")); cy += captionFont->LegacySize + 24.0f * dp; ImGui::EndDisabled(); // low-spec @@ -620,7 +620,7 @@ void App::renderFirstRunWizard() { ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::ColorConvertU32ToFloat4(ui::material::PrimaryVariant())); ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(ui::material::OnPrimary())); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * dp); - if (ui::material::TactileButton("Continue##app", ImVec2(btnW, btnH))) { + if (ui::material::TactileButton(TR("wiz_continue"), ImVec2(btnW, btnH))) { // Save appearance choices, advance to Bootstrap settings_->setAcrylicEnabled(wiz_blur_amount > 0.001f); settings_->setAcrylicQuality(wiz_blur_amount > 0.001f @@ -667,23 +667,23 @@ void App::renderFirstRunWizard() { float iconW = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, stepIcon(state)).x; dl->AddText(iconFont, iconFont->LegacySize, ImVec2(cx, cy), dimCol, stepIcon(state)); float labelX = cx + iconW + 4.0f * dp; - dl->AddText(captionFont, captionFont->LegacySize, ImVec2(labelX, cy), dimCol, "Step 2"); - float step2W = captionFont->CalcTextSizeA(captionFont->LegacySize, FLT_MAX, 0, "Step 2").x; + dl->AddText(captionFont, captionFont->LegacySize, ImVec2(labelX, cy), dimCol, TR("wiz_step2")); + float step2W = captionFont->CalcTextSizeA(captionFont->LegacySize, FLT_MAX, 0, TR("wiz_step2")).x; float titleX = labelX + step2W + 12.0f * dp; - dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(titleX, cy), dimCol, "Bootstrap"); + dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(titleX, cy), dimCol, TR("wiz_bootstrap")); cy += captionFont->LegacySize + 4.0f * dp; } else { // Step indicator { float iconW = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, stepIcon(state)).x; dl->AddText(iconFont, iconFont->LegacySize, ImVec2(cx, cy), dimCol, stepIcon(state)); - dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx + iconW + 4.0f * dp, cy), dimCol, "Step 2"); + dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx + iconW + 4.0f * dp, cy), dimCol, TR("wiz_step2")); cy += captionFont->LegacySize + 4.0f * dp; } // Title { - const char* t = "Bootstrap"; + const char* t = TR("wiz_bootstrap"); dl->AddText(titleFont, titleFont->LegacySize, ImVec2(cx, cy), textCol, t); cy += titleFont->LegacySize + 6.0f * dp; } @@ -706,11 +706,11 @@ void App::renderFirstRunWizard() { const char* statusTitle; if (prog.state == util::Bootstrap::State::Downloading) - statusTitle = "Downloading bootstrap..."; + statusTitle = TR("bootstrap_downloading"); else if (prog.state == util::Bootstrap::State::Verifying) - statusTitle = "Verifying checksums..."; + statusTitle = TR("bootstrap_verifying"); else - statusTitle = "Extracting blockchain data..."; + statusTitle = TR("bootstrap_extracting"); dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx, cy), textCol, statusTitle); cy += bodyFont->LegacySize + 12.0f * dp; @@ -739,7 +739,7 @@ void App::renderFirstRunWizard() { if (prog.state == util::Bootstrap::State::Extracting) { dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), - dimCol, "(wallet.dat is protected)"); + dimCol, TR("bootstrap_wallet_protected")); cy += captionFont->LegacySize + 6.0f * dp; } @@ -755,9 +755,9 @@ void App::renderFirstRunWizard() { dl->AddCircleFilled(ImVec2(cx + dotR, cy + captionFont->LegacySize * 0.5f), dotR, dotCol); const char* label = daemonUp ? (dStatus.find("Stopping") != std::string::npos - ? "Daemon stopping..." - : "Daemon running") - : "Daemon stopped"; + ? TR("bootstrap_daemon_stopping") + : TR("bootstrap_daemon_running")) + : TR("bootstrap_daemon_stopped"); dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx + dotR * 2.0f + 6.0f * dp, cy), (dimCol & 0x00FFFFFF) | IM_COL32(0,0,0,140), label); @@ -772,7 +772,7 @@ void App::renderFirstRunWizard() { float cancelBX = rightX + (colW - cancelW) * 0.5f; ImGui::SetCursorScreenPos(ImVec2(cancelBX, cy)); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * dp); - if (ui::material::TactileButton("Cancel##bs", ImVec2(cancelW, cancelH))) { + if (ui::material::TactileButton(TR("cancel"), ImVec2(cancelW, cancelH))) { bootstrap_->cancel(); } ImGui::PopStyleVar(); @@ -799,10 +799,10 @@ void App::renderFirstRunWizard() { errMsg = bootstrap_->getProgress().error; bootstrap_.reset(); } - if (errMsg.empty()) errMsg = "Bootstrap failed"; + if (errMsg.empty()) errMsg = TR("wiz_bootstrap_failed"); dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx, cy), - ui::material::Error(), "Download Failed"); + ui::material::Error(), TR("wiz_download_failed")); cy += bodyFont->LegacySize + 8.0f * dp; dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), textCol, @@ -821,7 +821,7 @@ void App::renderFirstRunWizard() { ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(ui::material::OnPrimary())); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * dp); ImGui::BeginDisabled(!supportsFullNodeLifecycleActions()); - if (ui::material::TactileButton("Retry##bs", ImVec2(btnW2, btnH2))) { + if (ui::material::TactileButton(TR("retry"), ImVec2(btnW2, btnH2))) { // Stop embedded daemon before bootstrap to avoid chain data corruption stopDaemonForBootstrap(); bootstrap_ = std::make_unique(); @@ -835,7 +835,7 @@ void App::renderFirstRunWizard() { ImGui::SetCursorScreenPos(ImVec2(bx + btnW2 + 12.0f * dp, cy)); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * dp); - if (ui::material::TactileButton("Skip##bsfail", ImVec2(btnW2, btnH2))) { + if (ui::material::TactileButton(TR("wiz_skip"), ImVec2(btnW2, btnH2))) { wizard_phase_ = WizardPhase::EncryptOffer; } ImGui::PopStyleVar(); @@ -878,11 +878,11 @@ void App::renderFirstRunWizard() { { float iw = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, ICON_MD_WARNING).x; dl->AddText(iconFont, iconFont->LegacySize, ImVec2(cx, cy), warnCol, ICON_MD_WARNING); - dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx + iw + 4.0f * dp, cy), warnCol, "External daemon running"); + dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx + iw + 4.0f * dp, cy), warnCol, TR("wiz_ext_daemon_running")); } cy += bodyFont->LegacySize + 4.0f * dp; { - const char* warnBody = "It must be stopped before downloading a bootstrap, otherwise chain data could be corrupted."; + const char* warnBody = TR("wiz_ext_daemon_warning"); ImVec2 ws = captionFont->CalcTextSizeA(captionFont->LegacySize, FLT_MAX, contentW, warnBody); dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), textCol, warnBody, nullptr, contentW); cy += ws.y + 12.0f * dp; @@ -905,9 +905,9 @@ void App::renderFirstRunWizard() { IM_COL32(220, 60, 60, 255))); ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 255, 255, 255)); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * dp); - if (ui::material::TactileButton("Stop Daemon##wiz", ImVec2(stopW, btnH2))) { + if (ui::material::TactileButton(TR("wiz_stop_daemon"), ImVec2(stopW, btnH2))) { wizard_stopping_external_ = true; - wizard_stop_status_ = "Sending stop command..."; + wizard_stop_status_ = TR("wiz_daemon_sending_stop"); async_tasks_.submit("wizard-stop-external-daemon", [this](const util::AsyncTaskManager::Token& token) { auto config = rpc::Connection::autoDetectConfig(); if (!config.rpcuser.empty() && !config.rpcpassword.empty()) { @@ -919,17 +919,17 @@ void App::renderFirstRunWizard() { tmp_rpc->disconnect(); } } - wizard_stop_status_ = "Waiting for daemon to shut down..."; + wizard_stop_status_ = TR("wiz_daemon_waiting_stop"); for (int i = 0; i < 60 && !token.cancelled(); i++) { std::this_thread::sleep_for(std::chrono::seconds(1)); if (!daemon::EmbeddedDaemon::isRpcPortInUse()) { - wizard_stop_status_ = "Daemon stopped."; + wizard_stop_status_ = TR("wiz_daemon_stopped_ok"); wizard_stopping_external_ = false; return; } } if (token.cancelled()) return; - wizard_stop_status_ = "Daemon did not stop — try manually."; + wizard_stop_status_ = TR("wiz_daemon_stop_failed"); wizard_stopping_external_ = false; }); } @@ -938,7 +938,7 @@ void App::renderFirstRunWizard() { ImGui::SetCursorScreenPos(ImVec2(bx + stopW + 12.0f * dp, cy)); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * dp); - if (ui::material::TactileButton("Skip##extd", ImVec2(skipW2, btnH2))) { + if (ui::material::TactileButton(TR("wiz_skip"), ImVec2(skipW2, btnH2))) { wizard_phase_ = WizardPhase::EncryptOffer; } ImGui::PopStyleVar(); @@ -947,7 +947,7 @@ void App::renderFirstRunWizard() { } else { // --- Normal bootstrap offer --- { - const char* bsText = "Download a blockchain bootstrap to dramatically speed up initial sync.\n\nYour existing wallet.dat will NOT be modified or replaced."; + const char* bsText = TR("wiz_bootstrap_desc"); ImVec2 bsSize = bodyFont->CalcTextSizeA(bodyFont->LegacySize, FLT_MAX, contentW, bsText); dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx, cy), textCol, bsText, nullptr, contentW); cy += bsSize.y + 8.0f * dp; @@ -960,7 +960,7 @@ void App::renderFirstRunWizard() { ImU32 warnCol = (textCol & 0x00FFFFFF) | ((ImU32)(255 * warnOpacity) << 24); float iw = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, ICON_MD_WARNING).x; dl->AddText(iconFont, iconFont->LegacySize, ImVec2(cx, cy), warnCol, ICON_MD_WARNING); - const char* twText = "Only use bootstrap.dragonx.is or bootstrap2.dragonx.is. Using files from untrusted sources could compromise your node."; + const char* twText = TR("bootstrap_trust_warning"); float twWrap = contentW - iw - 4.0f * dp; ImVec2 twSize = captionFont->CalcTextSizeA(captionFont->LegacySize, FLT_MAX, twWrap, twText); dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx + iw + 4.0f * dp, cy), warnCol, twText, nullptr, twWrap); @@ -979,9 +979,9 @@ void App::renderFirstRunWizard() { dl->AddCircleFilled(ImVec2(cx + dotR, cy + captionFont->LegacySize * 0.5f), dotR, dotCol); const char* label = daemonUp ? (dStatus.find("Stopping") != std::string::npos - ? "Daemon stopping..." - : "Daemon running") - : "Daemon stopped"; + ? TR("bootstrap_daemon_stopping") + : TR("bootstrap_daemon_running")) + : TR("bootstrap_daemon_stopped"); dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx + dotR * 2.0f + 6.0f * dp, cy), (dimCol & 0x00FFFFFF) | IM_COL32(0,0,0,140), label); @@ -1004,7 +1004,7 @@ void App::renderFirstRunWizard() { ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(ui::material::OnPrimary())); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * dp); ImGui::BeginDisabled(!supportsFullNodeLifecycleActions()); - if (ui::material::TactileButton("Download##bs", ImVec2(dlBtnW, btnH2))) { + if (ui::material::TactileButton(TR("download"), ImVec2(dlBtnW, btnH2))) { // Stop embedded daemon before bootstrap to avoid chain data corruption stopDaemonForBootstrap(); bootstrap_ = std::make_unique(); @@ -1023,7 +1023,7 @@ void App::renderFirstRunWizard() { ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(ui::material::OnSurface())); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * dp); ImGui::BeginDisabled(!supportsFullNodeLifecycleActions()); - if (ui::material::TactileButton("Mirror##bs_mirror", ImVec2(mirrorW, btnH2))) { + if (ui::material::TactileButton(TR("bootstrap_mirror"), ImVec2(mirrorW, btnH2))) { stopDaemonForBootstrap(); bootstrap_ = std::make_unique(); std::string dataDir = util::Platform::getDragonXDataDir(); @@ -1033,7 +1033,7 @@ void App::renderFirstRunWizard() { } ImGui::EndDisabled(); if (ImGui::IsItemHovered()) { - ui::material::Tooltip("Download from mirror (bootstrap2.dragonx.is).\nUse this if the main download is slow or failing."); + ui::material::Tooltip(TR("bootstrap_mirror_tooltip")); } ImGui::PopStyleVar(); ImGui::PopStyleColor(3); @@ -1041,7 +1041,7 @@ void App::renderFirstRunWizard() { // --- Skip button --- ImGui::SetCursorScreenPos(ImVec2(bx + dlBtnW + 8.0f * dp + mirrorW + 8.0f * dp, cy)); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * dp); - if (ui::material::TactileButton("Skip##bs", ImVec2(skipW2, btnH2))) { + if (ui::material::TactileButton(TR("wiz_skip"), ImVec2(skipW2, btnH2))) { wizard_phase_ = WizardPhase::EncryptOffer; } ImGui::PopStyleVar(); @@ -1093,14 +1093,14 @@ void App::renderFirstRunWizard() { { float iconW = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, stepIcon(state)).x; dl->AddText(iconFont, iconFont->LegacySize, ImVec2(cx, cy), dimCol, stepIcon(state)); - dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx + iconW + 4.0f * dp, cy), dimCol, "Step 3"); + dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx + iconW + 4.0f * dp, cy), dimCol, TR("wiz_step3")); cy += captionFont->LegacySize + 4.0f * dp; } // Title (changes for PinSetup sub-state) { const char* t = (isFocused && wizard_phase_ == WizardPhase::PinSetup) - ? "Quick-Unlock PIN" : "Encryption"; + ? TR("wiz_pin_title") : TR("wiz_encryption"); dl->AddText(titleFont, titleFont->LegacySize, ImVec2(cx, cy), textCol, t); cy += titleFont->LegacySize + 6.0f * dp; } @@ -1117,11 +1117,11 @@ void App::renderFirstRunWizard() { ImU32 okCol = ui::material::Secondary(); float iw = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, ICON_MD_VERIFIED_USER).x; dl->AddText(iconFont, iconFont->LegacySize, ImVec2(cx, cy), okCol, ICON_MD_VERIFIED_USER); - dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx + iw + 6.0f * dp, cy), okCol, "Wallet is already encrypted"); + dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx + iw + 6.0f * dp, cy), okCol, TR("wiz_already_encrypted")); cy += bodyFont->LegacySize + 12.0f * dp; } { - const char* desc = "Your wallet is protected with a passphrase. No further action is needed."; + const char* desc = TR("wiz_already_encrypted_desc"); ImVec2 ds = bodyFont->CalcTextSizeA(bodyFont->LegacySize, FLT_MAX, contentW, desc); dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx, cy), textCol, desc, nullptr, contentW); cy += ds.y + 20.0f * dp; @@ -1136,7 +1136,7 @@ void App::renderFirstRunWizard() { ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::ColorConvertU32ToFloat4(ui::material::PrimaryVariant())); ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(ui::material::OnPrimary())); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * dp); - if (ui::material::TactileButton("Continue##encok", ImVec2(btnW2, btnH2))) { + if (ui::material::TactileButton(TR("wiz_continue"), ImVec2(btnW2, btnH2))) { wizard_phase_ = WizardPhase::Done; settings_->setWizardCompleted(true); settings_->save(); @@ -1148,7 +1148,7 @@ void App::renderFirstRunWizard() { } else if (isFocused) { // ---- Encryption offer + optional PIN (combined) ---- { - const char* encDesc = "Encrypt your wallet to protect private keys with a passphrase."; + const char* encDesc = TR("wiz_encrypt_desc"); ImVec2 edSize = bodyFont->CalcTextSizeA(bodyFont->LegacySize, FLT_MAX, contentW, encDesc); dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx, cy), textCol, encDesc, nullptr, contentW); cy += edSize.y + 6.0f * dp; @@ -1157,7 +1157,7 @@ void App::renderFirstRunWizard() { ImU32 warnCol2 = ui::material::Warning(); float iw = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, ICON_MD_WARNING).x; dl->AddText(iconFont, iconFont->LegacySize, ImVec2(cx, cy), warnCol2, ICON_MD_WARNING); - const char* warnLoss = "If you lose your passphrase, you lose access to your funds."; + const char* warnLoss = TR("wiz_encrypt_warning"); float wlWrap = contentW - iw - 4.0f * dp; ImVec2 wlSize = bodyFont->CalcTextSizeA(bodyFont->LegacySize, FLT_MAX, wlWrap, warnLoss); dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx + iw + 4.0f * dp, cy), warnCol2, warnLoss, nullptr, wlWrap); @@ -1165,7 +1165,7 @@ void App::renderFirstRunWizard() { } // Passphrase input - dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), dimCol, "Passphrase:"); + dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), dimCol, TR("wiz_passphrase")); cy += captionFont->LegacySize + 4.0f * dp; ImGui::SetCursorScreenPos(ImVec2(cx, cy)); @@ -1177,7 +1177,7 @@ void App::renderFirstRunWizard() { ImGui::PopItemWidth(); cy += 36.0f * dp + 6.0f * dp; - dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), dimCol, "Confirm:"); + dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), dimCol, TR("wiz_confirm")); cy += captionFont->LegacySize + 4.0f * dp; ImGui::SetCursorScreenPos(ImVec2(cx, cy)); @@ -1192,16 +1192,16 @@ void App::renderFirstRunWizard() { // Strength meter { size_t len = strlen(encrypt_pass_buf_); - const char* strengthLabel = "Weak"; + const char* strengthLabel = TR("wiz_strength_weak"); ImU32 strengthCol = ui::material::Error(); float strengthPct = 0.25f; if (len >= 16) { - strengthLabel = "Strong"; strengthCol = ui::material::Secondary(); strengthPct = 1.0f; + strengthLabel = TR("wiz_strength_strong"); strengthCol = ui::material::Secondary(); strengthPct = 1.0f; } else if (len >= 12) { - strengthLabel = "Good"; strengthCol = ui::material::Secondary(); strengthPct = 0.75f; + strengthLabel = TR("wiz_strength_good"); strengthCol = ui::material::Secondary(); strengthPct = 0.75f; } else if (len >= 8) { - strengthLabel = "Fair"; strengthCol = ui::material::Warning(); strengthPct = 0.5f; + strengthLabel = TR("wiz_strength_fair"); strengthCol = ui::material::Warning(); strengthPct = 0.5f; } float sBarH = 4.0f * dp, sBarR = 2.0f * dp; @@ -1214,7 +1214,7 @@ void App::renderFirstRunWizard() { cy += sBarH + 4.0f * dp; char slabel[64]; - snprintf(slabel, sizeof(slabel), "Strength: %s", strengthLabel); + snprintf(slabel, sizeof(slabel), TR("wiz_strength"), strengthLabel); dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), dimCol, slabel); cy += captionFont->LegacySize + 10.0f * dp; } @@ -1224,14 +1224,14 @@ void App::renderFirstRunWizard() { size_t pLen = strlen(encrypt_pass_buf_); if (pLen > 0 && pLen < 8) { char fb[80]; - snprintf(fb, sizeof(fb), "Passphrase must be at least 8 characters (%zu/8)", pLen); + snprintf(fb, sizeof(fb), TR("wiz_pass_too_short"), pLen); dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), ui::material::Error(), fb); cy += captionFont->LegacySize + 6.0f * dp; } else if (pLen >= 8 && strlen(encrypt_confirm_buf_) > 0 && strcmp(encrypt_pass_buf_, encrypt_confirm_buf_) != 0) { dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), - ui::material::Error(), "Passphrases do not match"); + ui::material::Error(), TR("wiz_pass_mismatch")); cy += captionFont->LegacySize + 6.0f * dp; } } @@ -1243,12 +1243,12 @@ void App::renderFirstRunWizard() { cy += 8.0f * dp; { - const char* pinTitle = "Quick-Unlock PIN (optional)"; + const char* pinTitle = TR("wiz_pin_optional"); dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), textCol, pinTitle); cy += captionFont->LegacySize + 4.0f * dp; } - dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), dimCol, "PIN (4-8 digits):"); + dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), dimCol, TR("wiz_pin_label")); cy += captionFont->LegacySize + 4.0f * dp; ImGui::SetCursorScreenPos(ImVec2(cx, cy)); @@ -1260,7 +1260,7 @@ void App::renderFirstRunWizard() { ImGui::PopItemWidth(); cy += 36.0f * dp + 6.0f * dp; - dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), dimCol, "Confirm PIN:"); + dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), dimCol, TR("wiz_pin_confirm")); cy += captionFont->LegacySize + 4.0f * dp; ImGui::SetCursorScreenPos(ImVec2(cx, cy)); @@ -1277,12 +1277,12 @@ void App::renderFirstRunWizard() { std::string pinStr(wizard_pin_buf_); if (!pinStr.empty() && !util::SecureVault::isValidPin(pinStr)) { dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), - ui::material::Error(), "PIN must be 4-8 digits"); + ui::material::Error(), TR("wiz_pin_invalid")); cy += captionFont->LegacySize + 6.0f * dp; } else if (!pinStr.empty() && strlen(wizard_pin_confirm_buf_) > 0 && pinStr != std::string(wizard_pin_confirm_buf_)) { dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), - ui::material::Error(), "PINs do not match"); + ui::material::Error(), TR("wiz_pin_mismatch")); cy += captionFont->LegacySize + 6.0f * dp; } } @@ -1303,7 +1303,7 @@ void App::renderFirstRunWizard() { } if (passEdgeSpace) { dl->AddText(captionFont, captionFont->LegacySize, ImVec2(cx, cy), - ui::material::Error(), "Passphrase has leading/trailing spaces — remove them"); + ui::material::Error(), TR("wiz_pass_spaces")); cy += captionFont->LegacySize + 6.0f * dp; } @@ -1333,7 +1333,7 @@ void App::renderFirstRunWizard() { ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(ui::material::OnPrimary())); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * dp); ImGui::BeginDisabled(!canEncrypt); - if (ui::material::TactileButton("Encrypt & Continue##wiz", ImVec2(encBtnW, btnH2))) { + if (ui::material::TactileButton(TR("wiz_encrypt_continue"), ImVec2(encBtnW, btnH2))) { // Save passphrase + optional PIN for background processing wallet_security_.beginDeferredEncryption( std::string(encrypt_pass_buf_), @@ -1356,7 +1356,7 @@ void App::renderFirstRunWizard() { wizard_phase_ = WizardPhase::Done; settings_->setWizardCompleted(true); settings_->save(); - ui::Notifications::instance().info("Encryption will complete in the background"); + ui::Notifications::instance().info(TR("wiz_encrypt_bg")); } ImGui::EndDisabled(); ImGui::PopStyleVar(); @@ -1364,12 +1364,12 @@ void App::renderFirstRunWizard() { ImGui::SetCursorScreenPos(ImVec2(bx + encBtnW + 12.0f * dp, cy)); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * dp); - if (ui::material::TactileButton("Skip##enc", ImVec2(skipW2, btnH2))) { + if (ui::material::TactileButton(TR("wiz_skip"), ImVec2(skipW2, btnH2))) { static bool s_skipEncConfirm = false; if (!s_skipEncConfirm) { // Skipping stores private keys UNENCRYPTED — require a confirming second click. s_skipEncConfirm = true; - encrypt_status_ = "Continue WITHOUT encryption? Keys will be stored unencrypted — click Skip again to confirm."; + encrypt_status_ = TR("wiz_skip_confirm"); } else { s_skipEncConfirm = false; wizard_phase_ = WizardPhase::Done; @@ -1389,7 +1389,7 @@ void App::renderFirstRunWizard() { } } else { // ---- Not focused: show static description ---- - const char* encDesc = "Encrypt your wallet to protect private keys with a passphrase."; + const char* encDesc = TR("wiz_encrypt_desc"); ImVec2 edSize = bodyFont->CalcTextSizeA(bodyFont->LegacySize, FLT_MAX, contentW, encDesc); dl->AddText(bodyFont, bodyFont->LegacySize, ImVec2(cx, cy), dimCol, encDesc, nullptr, contentW); cy += edSize.y + 6.0f * dp; diff --git a/src/util/i18n.cpp b/src/util/i18n.cpp index ac1bbf6..b51d52f 100644 --- a/src/util/i18n.cpp +++ b/src/util/i18n.cpp @@ -464,6 +464,63 @@ void I18n::loadBuiltinEnglish() strings_["tt_reduce_motion"] = "Disable animated transitions and balance lerp for accessibility"; strings_["ago"] = "ago"; strings_["wizard_daemon_start_failed"] = "Failed to start daemon \xe2\x80\x94 it will be retried automatically"; + // First-run wizard (app_wizard.cpp). Bootstrap/appearance labels reuse existing keys; these are + // the wizard-specific strings. + strings_["wiz_welcome_title"] = "Welcome to ObsidianDragon!"; + strings_["wiz_welcome_sub"] = "A few quick choices and your full node is ready."; + strings_["wiz_step1"] = "Step 1"; + strings_["wiz_step2"] = "Step 2"; + strings_["wiz_step3"] = "Step 3"; + strings_["wiz_appearance"] = "Appearance"; + strings_["wiz_theme_builtin"] = "Built-in"; + strings_["wiz_theme_custom"] = "Custom"; + strings_["wiz_theme_invalid"] = " (invalid)"; + strings_["wiz_lowspec_desc"] = "Disable all heavy visual effects"; + strings_["wiz_acrylic"] = "Acrylic glass effects"; + strings_["wiz_acrylic_desc"] = "Translucent blur on panels (Off disables)"; + strings_["wiz_level"] = "Level:"; + strings_["wiz_off"] = "Off"; + strings_["wiz_theme_effects"] = "Theme visual effects"; + strings_["wiz_theme_effects_desc"] = "Animated borders, color wash"; + strings_["wiz_ui_opacity_desc"] = "Card & sidebar transparency (1.0 = solid)"; + strings_["wiz_scanline_desc"] = "CRT scanline effect in console"; + strings_["wiz_bootstrap"] = "Bootstrap"; + strings_["wiz_bootstrap_desc"] = "Download a blockchain bootstrap to dramatically speed up initial sync.\n\nYour existing wallet.dat will NOT be modified or replaced."; + strings_["wiz_skip"] = "Skip"; + strings_["wiz_bootstrap_failed"] = "Bootstrap failed"; + strings_["wiz_download_failed"] = "Download Failed"; + strings_["wiz_ext_daemon_running"] = "External daemon running"; + strings_["wiz_ext_daemon_warning"] = "It must be stopped before downloading a bootstrap, otherwise chain data could be corrupted."; + strings_["wiz_stop_daemon"] = "Stop Daemon"; + strings_["wiz_daemon_sending_stop"] = "Sending stop command..."; + strings_["wiz_daemon_waiting_stop"] = "Waiting for daemon to shut down..."; + strings_["wiz_daemon_stopped_ok"] = "Daemon stopped."; + strings_["wiz_daemon_stop_failed"] = "Daemon did not stop \xe2\x80\x94 try manually."; + strings_["wiz_encryption"] = "Encryption"; + strings_["wiz_pin_title"] = "Quick-Unlock PIN"; + strings_["wiz_already_encrypted"] = "Wallet is already encrypted"; + strings_["wiz_already_encrypted_desc"] = "Your wallet is protected with a passphrase. No further action is needed."; + strings_["wiz_continue"] = "Continue"; + strings_["wiz_encrypt_desc"] = "Encrypt your wallet to protect private keys with a passphrase."; + strings_["wiz_encrypt_warning"] = "If you lose your passphrase, you lose access to your funds."; + strings_["wiz_passphrase"] = "Passphrase:"; + strings_["wiz_confirm"] = "Confirm:"; + strings_["wiz_strength_weak"] = "Weak"; + strings_["wiz_strength_fair"] = "Fair"; + strings_["wiz_strength_good"] = "Good"; + strings_["wiz_strength_strong"] = "Strong"; + strings_["wiz_strength"] = "Strength: %s"; + strings_["wiz_pass_too_short"] = "Passphrase must be at least 8 characters (%zu/8)"; + strings_["wiz_pass_mismatch"] = "Passphrases do not match"; + strings_["wiz_pass_spaces"] = "Passphrase has leading/trailing spaces \xe2\x80\x94 remove them"; + strings_["wiz_encrypt_continue"] = "Encrypt & Continue"; + strings_["wiz_encrypt_bg"] = "Encryption will complete in the background"; + strings_["wiz_skip_confirm"] = "Continue WITHOUT encryption? Keys will be stored unencrypted \xe2\x80\x94 click Skip again to confirm."; + strings_["wiz_pin_optional"] = "Quick-Unlock PIN (optional)"; + strings_["wiz_pin_label"] = "PIN (4-8 digits):"; + strings_["wiz_pin_confirm"] = "Confirm PIN:"; + strings_["wiz_pin_invalid"] = "PIN must be 4-8 digits"; + strings_["wiz_pin_mismatch"] = "PINs do not match"; strings_["settings_data_dir"] = "Data Dir:"; strings_["settings_wallet_size_label"] = "Wallet Size:"; strings_["settings_debug_changed"] = "Debug categories changed \xe2\x80\x94 restart daemon to apply";