From f3deccb6268d317620435ce221dba0cb3fe6ffcb Mon Sep 17 00:00:00 2001 From: svatantrya Date: Thu, 15 Oct 2026 21:55:03 -0400 Subject: [PATCH] gui+cli+core: anticipated-delivery warning, task #67 amount checks, CLI tools GUI - "Building your will" row (owner request): - when a rebuild anticipates the delivery date by one day, show "Anticipated - new delivery date: " on the "Building your will" row instead of a plain "Ok"; - the detection compares the will's minimum locktime BEFORE and AFTER the rebuild, so it also covers relative recipes ("1y"/"30d") that the previous stored-vs-built comparison missed; - the sign explanation stays on its own "Signing your will" row so it no longer overwrites the anticipation warning. Task #67 - "Checking variables" stuck on "Wait": - core: Will.check_amounts only requires a fixed amount to be funded when it is > 0, and only requires percentages to total 100% when the will actually has percentage heirs; fixed-only / empty-wallet wills no longer raise; - gui: the amount warning is written on the "Checking variables" row itself (COLOR_WARNING) instead of being overwritten by the next row; the redundant "adjustment of the amounts" sentence was dropped. CLI - will-executor helpers: - willexecutors_update accepts promo_code; - willexecutors_select supports bulk apply with only_valid; - willexecutors_export supports selected/valid subsets; - import overwrites existing records with sane defaults; - raise NoServersForChainError with a clear user-facing message; map NotCompleteWill / HeirChange / WillexecutorChange in _user_facing. Tests and docs: - tests for the anticipation row, the CLI helpers and the amount checks; - i18n catalogs refreshed; CHANGELOG section 67; agent task memory updated. --- .agent_memory_tasks.md | 4 +- .opencode/plans/plan_android_reader.md | 231 ----------- CHANGELOG.md | 61 +++ bal/cli/commands.py | 25 +- bal/cli/controller.py | 153 +++++-- bal/core/will.py | 14 +- bal/gui/qt/dialogs.py | 131 ++++-- bal/gui/qt/window.py | 6 +- bal/locale/bal.pot | 528 ++++++++++++++----------- bal/locale/es_ES/LC_MESSAGES/bal.po | 478 +++++++++++----------- bal/locale/it_IT/LC_MESSAGES/bal.po | 478 +++++++++++----------- tests/test_cli_controller_offline.py | 187 ++++++++- tests/test_gui_will_flows.py | 4 +- tests/test_sync_locktime_built_txs.py | 106 ++++- 14 files changed, 1396 insertions(+), 1010 deletions(-) delete mode 100644 .opencode/plans/plan_android_reader.md diff --git a/.agent_memory_tasks.md b/.agent_memory_tasks.md index db9bba0..fb10518 100644 --- a/.agent_memory_tasks.md +++ b/.agent_memory_tasks.md @@ -485,8 +485,8 @@ ROW LABELS and, for each, a variable STATUS text. |--------------------------------------------------------------------------------|--------|-------------| | Check Alive Threshold Passed: you have to Invalidate your old Will | RED | CheckAliveError + an invalidate tx exists (~559) | | No Heirs | RED | NoHeirsException (~564) | -| Ok | GREEN | check_amounts passed (~579) | -| In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts | (warning popup) | AmountException (~583) | +| Ok | GREEN | check_amounts passed | +| In the inheritance process, the entire wallet will always be fully emptied. | ORANGE | AmountException (warning on the row itself, not a popup) | ### ROW 2 — "Checking your will" outcomes (this is where "Heir not found" / "New" appear) | Status text shown | Color | When (code) | Triggers rebuild? | diff --git a/.opencode/plans/plan_android_reader.md b/.opencode/plans/plan_android_reader.md deleted file mode 100644 index 1f2ffc6..0000000 --- a/.opencode/plans/plan_android_reader.md +++ /dev/null @@ -1,231 +0,0 @@ -# PLAN_ANDROID_READER.md — BAL Reader: an Android QR will reader - -**Date:** 2026-09-09 · **Status:** proposed · **Ties into:** BAL plugin QR export (BALQR / BC-UR v1 / BC-UR v2 / BBQR) - -## 1. Goal - -Ship a minimal single-activity Android app that reads any QR will exported by the BAL -Electrum plugin, decodes all four supported wire formats, and lets the user view, copy, -share, or save the recovered will data. The app is a **reader only** — it never signs or -broadcasts. - -## 2. Scope - -**In scope** - -- Continuous camera capture (CameraX + ML Kit on-device barcode scanning, QR-only). -- Auto-detection of the four formats (`detect_format`: `"balqr" / "ur1" / "ur2" / "bbqr"`). -- Order-independent frame assembly: duplicates ignored, out-of-order accepted, UR v2 - XOR-fountain redundancy exploited, session-level reset on transfer switch. -- Whole-will JSON **and** tx-hex-list payloads, both decoded to a readable view. -- Copy raw transfer text / Share / Save via Storage Access Framework. -- Verified decode chain runnable on the dev machine (no Android needed). - -**Out of scope** - -- Signing, broadcasting, password handling, wallet integration. -- Export/authoring QR codes *from* the phone. -- Audio-modem transport (unchanged, plugin-only). - -## 3. Architecture - -### 3.1 Why Chaquopy (reuse the tested Python codecs) - -`bal/core/animated_qr.py` (1178 lines) and `bal/core/qrtransfer.py` (212 lines) are -**pure stdlib** (`base64`, `hashlib`, `zlib`), GUI-free, Python-3.8-clean (verified: no -walrus/match/`X|Y`/PEP-585 generics), and `bal/core/__init__.py` is an empty docstring. -Chaquopy bundles CPython into the APK, so **the exact, battle-tested codec modules run -unchanged on Android** with zero port risk. The Kotlin side is only camera glue + UI. - -### 3.2 Decode chain (mirror of the plugin's import tail) - -The plugin's `_review_and_sign` (dialogs.py:3792) does exactly: - -1. `session.resolve()` -> `(transfer_text, compressed: bool)` - (UR v1/v2/BBQR for the first pair; `(text, flag)` for BAL QR). -2. `decode_transfer(transfer_text, compressed)` -> list of parts (tx hexes, or the single - whole-will JSON). -3. `"\n".join(parts)` -> opaque payload. -4. `decode_will_payload(payload)` -> `("will", dict)` **or** `("txs", [strings])`. - -The app reuses all of it verbatim through the `AnimatedQrSession` facade (`add_part` -auto-detects per frame, dedups, tracks `received/total/done`). - -### 3.3 Data flow - -``` -CameraX ImageAnalysis -> ML Kit BarcodeScanning (QR) -> raw string - -> BalDecoder.add(text) [Chaquopy -> AnimatedQrSession.add_part] - -> status: format chip + received/total, duplicate-tolerant - -> when done: auto-stop -> BalDecoder.finish() (4-step decode) - -> ResultActivity: JSON view OR tx-list view + Copy/Share/Save -``` - -## 4. Repository layout (new `android/` subfolder) - -``` -android/ - README.md # build (Android Studio), usage, codec-sync rule, MIT note - settings.gradle.kts - build.gradle.kts # root: plugins (AGP 8.10, Kotlin 2.0.21, Chaquopy 17, apply false) - gradle.properties - gradlew, gradlew.bat - gradle/wrapper/ # gradle-wrapper.properties + gradle-wrapper.jar (fetched; see §7) - scripts/ - sync_codecs.py # copy bal/core/{__init__,animated_qr,qrtransfer}.py -> app python dir; import-check - test_chain/ - verify_chain.py # full decode-chain simulation, runs on dev machine - app/ - build.gradle.kts # com.android.application + com.chaquo.python; CameraX/ML Kit deps - src/main/ - AndroidManifest.xml # CAMERA permission - java/life/after/bitcoin/ - MainActivity.kt # permission + PreviewView + ImageAnalysis + status header - BalDecoder.kt # Chaquopy bridge (§5.1) - ResultActivity.kt # viewer + copy/share/save (§5.3) - res/layout/activity_main.xml, activity_result.xml - res/values/strings.xml - python/bal/core/ # SYNCED COPIES (committed, deterministic; regenerate with script) - __init__.py - animated_qr.py - qrtransfer.py -``` - -## 5. Component specifications - -### 5.1 `BalDecoder` (Kotlin, Chaquopy bridge) - -- Lazy init: `Python.start(AndroidPlatform(context))`, `getModule("bal.core.animated_qr")`. -- `fun add(text: String): String` -> `session.add_part(text)`; surfaces `"ok"`/`"dup"`; - maps `AnimatedQrError` subclasses to a result the UI can ignore (garbage frames) vs - reset (transfer switch -> `TransferConflictError` -> tell user to rescan). -- `val format: String?` (`"balqr"/"ur1"/"ur2"/"bbqr"`), `val received: Int`, - `val total: Int`, `val done: Boolean` (auto-converted by Chaquopy). -- `fun finish(): DecodedResult` - the 4-step chain; returns - `data class DecodedResult(kind: "will"|"txs", data: Map|List, rawTransfer: String)`. -- `fun reset()` -> new `AnimatedQrSession` (new scan). - -### 5.2 `MainActivity` (camera + scan loop) - -- Launches CameraX via `ProcessCameraProvider`; `PreviewView` fills screen; camera - permission via `ActivityResultContracts.RequestPermission`. -- `ImageAnalysis` `STRATEGY_KEEP_ONLY_LATEST`; analyzer throttled (~100 ms) calls ML Kit - `BarcodeScanning` with `Barcode.FORMAT_QR_CODE`. -- Thread-safe feed to `BalDecoder` (analyzer runs on a background executor); UI status - via `runOnUiThread`. -- Header row: format chip + `received/total`; on `done` -> stop analyzer -> launch - `ResultActivity` (results as Parcelable); "New scan" restarts. -- Garbage / incomplete frames silently ignored (same policy as the plugin); a - `TransferConflictError` mid-scan resets the session and signals the user to rescan. - -### 5.3 `ResultActivity` (viewer) - -- `kind == "will"`: whole-will JSON - each item's `tx` hex shown truncated with full view - on demand. -- `kind == "txs"`: list of tx hexes. -- Action bar: **Copy** (raw transfer text to clipboard), **Share** (ACTION_SEND - text/plain), **Save** (SAF `ACTION_CREATE_DOCUMENT` -> `will.json` / `will_tx.txt`). -- "Scan another" button -> finish -> back to camera. - -### 5.4 `scripts/sync_codecs.py` - -- Copies the 3 files from `bal/core/` -> `app/src/main/python/bal/core/` (idempotent). -- Post-copy check (dev machine): import `bal.core.animated_qr`, run one UR v2 frame + - decode cycle to prove the copy imports standalone. -- Documented as the rule after any codec change (README). - -### 5.5 `test_chain/verify_chain.py` - -Simulates the exact APK runtime path on the dev machine (no Android). Generates frames -precisely as the export page does, then feeds `AnimatedQrSession.add_part` in -scrambled/duplicated/dropped order and asserts correct results for: - -- BAL QR multi-frame, plain **and** compressed (`Z` flag): `split_frames(encode_transfer(...))`. -- UR v1 single-part (`ur1_frames` headerless) and `1ofN` multipart. -- UR v2 single-part and fountain multipart with >=1 frame dropped and >=1 duplicated - (exercises the XOR solve). -- BBQR `Z`/`H`/`2`: `bbqr_frames(..., encoding=...)`, with the `Z` auto-decompress branch. -- payload kinds: whole-will JSON **and** tx-hex list. -- transfer-switch: feed a frame of a different transfer mid-session -> expect conflict, as - the UI will. - -Runs under the runtime venv: -`source .../electrum/env/bin/activate && QT_QPA_PLATFORM=offscreen python3 android/test_chain/verify_chain.py` - -## 6. Wire-format reference (bundled codecs) - -- **BAL QR**: `BALQR1||||`, flags `""` or `Z` (zlib+base64). - Concatenate payloads 1..total -> transfer string -> `decode_transfer` splits on `\n`. -- **BC-UR v1**: multipart `ur:bytes/of//`; - single-part `ur:bytes/` (digest-less). BC32 = bech32_bis (XOR `0x3FFFFFFF`) - 5-bit alphabet. -- **BC-UR v2**: multipart `ur:bytes/-of-/` + - single-part headerless; part body = CBOR `[seq, seq_len, msg_len, crc32, data]` + - per-part CRC-32, bytewords-minimal; fountain via `choose_fragments` (xoshiro256** + - alias/threshold), mixed by XOR - decoder solves from any sufficient subset. -- **BBQR**: `B$`; encodings `H` - (upper hex), `2` (base32nal), `Z` (deflate `wbits=-10` -> base32). - -## 7. Toolchain & versions - -| Item | Version | Notes | -|---|---|---| -| Chaquopy | 17.0.0 | Python 3.10-3.14, AGP 7.3-9.2, minSdk 24 | -| AGP | 8.10.0 | in Chaquopy 17 range | -| Gradle wrapper | 8.14 | required by AGP 8.10 | -| Kotlin | 2.0.21 | | -| compile/target SDK | 35 / min 24 | | -| JDK | 17 (machine has OpenJDK 17) | | -| CameraX | 1.3.4 | `camera-core`, `camera-camera2`, `camera-lifecycle`, `camera-view` | -| ML Kit barcode | 17.3.0 | on-device, no API key | -| Python (codec) | 3.12 (Chaquopy) | codecs verified 3.8-clean | - -Dev machine: Android Studio + JDK 17 present; SDK platforms/build-tools/gradle absent -> -the **first real APK build happens in Android Studio with network**. `gradle-wrapper.jar` -is fetched via `curl` (canonical location) so `./gradlew` works; if network is blocked, -README documents Android Studio regenerating it. - -## 8. Build & run outline (for README) - -1. Open `android/` in Android Studio (or `./gradlew assembleDebug`). -2. Allow Gradle to fetch wrapper/deps (network). -3. Install on device; grant camera permission. -4. In the plugin: export dialog -> pick format (start with BAL QR default; also test - UR v1/UR v2/BBQR) -> show the animated QR on screen. -5. Point camera at screen; watch `received/total`; decoded result appears -> - Copy/Share/Save. - -## 9. Verification - -**On this machine (no Android needed)** - -1. `python3 android/scripts/sync_codecs.py` -> copy + import/roundtrip sanity. -2. `QT_QPA_PLATFORM=offscreen python3 android/test_chain/verify_chain.py` -> all - formats/payload kinds/conflict cases pass. -3. `ruff check android/scripts/sync_codecs.py android/test_chain/verify_chain.py` -> clean. -4. `pytest tests/test_core_*.py tests/test_gui_*.py` -> still **445 passed** - (payload code untouched; only new files). -5. `python3 build_zip.py` unaffected (no change under `bal/`). - -**On-device (manual, user)** - -- Walk the 4 formats against the plugin's export page, single- and multi-frame - (animated), on a real phone. -- Confirm format chip, progress, auto-finish, Copy/Share/Save. - -**Boundary** - no APK is produced by this machine's environment; the artifact is a -complete, independently buildable source tree + verified codec path. - -## 10. Risks & notes - -- First Gradle sync needs network (deps + wrapper). Pinned versions are conservative; - knobs documented. -- Bundled codec copies must be regenerated after any `bal/core/animated_qr.py` / - `qrtransfer.py` change - handled by `sync_codecs.py` + README note (copies are - committed for deterministic builds). -- Animated QR reading depends on the camera catching enough distinct frames (ML Kit - analyzer keeps scanning; the session dedups and accepts out-of-order). Slow phone - screens / glare may raise time-to-complete - expected, same as the plugin. -- App name/package (`life.after.bitcoin`, label "BAL Reader") are placeholders - trivial - to change. -- MIT: bundled codec files inherit the plugin's MIT license (noted in README). \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b295aa4..73256d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3759,3 +3759,64 @@ into children that are still present in the will. clean on the touched files. **Outcome:** DONE. + +--- + +## 67. "Checking variables" stuck on "Wait" + redundant amount-adjustment wording + +**Date:** 2026-10-14 + +**Symptom (owner report):** in the "Building Will" dialog the "Checking +variables" row always stayed on "Wait" and never became "Ok", even though the +will itself was fine ("Checking your will" showed "Ok"). It should show its +result before the "Checking your will" row is written. + +**Root cause (two bugs):** + +1. UI - when `Will.check_amounts` raised `AmountException` / + `WillExecutorFeeTooHighException`, `BalBuildWillDialog.task_phase1` wrote the + warning to the **"Checking your will"** row (`msg_set_checking(...)`) and the + very next `self.msg_set_checking()` call immediately overwrote it. So on an + amount warning the warning was lost AND the "Checking variables" row kept its + initial "Wait" forever (the success path set "Ok" only when the amount check + passed). +2. Core - `Will.check_amounts` had two false positives that made perfectly valid + wills raise: + - `fixed_amount >= wallet_balance` also fired when `fixed_amount == 0` + (all-percentage or empty/fully-committed wallet: `0 >= 0`); + - `perc_amount != 100` also fired when the will has NO percentage heirs at + all (a fixed-only will reports `perc_amount == 0`). + +**What changed:** + +- `bal/gui/qt/dialogs.py` (`task_phase1`, AmountException branch): the warning is + now written on the **"Checking variables"** row itself with `COLOR_WARNING`, so + the row always reaches a real outcome and the warning is never lost. The + wording was also reduced to the first sentence only - "In the inheritance + process, the entire wallet will always be fully emptied." - dropping + "Your settings require an adjustment of the amounts" (owner request). +- `bal/gui/qt/window.py` (`build_inheritance_transaction`, AmountException + branch): same message reduction; the appended exception detail (`.format(e)`) + was removed with the sentence it belonged to. +- `bal/core/will.py` (`check_amounts`): the fixed-amount checks now only apply + when `fixed_amount > 0`, and the 100% check only when the will actually has + percentage heirs (`perc_heirs`). Valid fixed-only / empty-wallet wills no + longer raise. +- i18n catalogs refreshed (`pybabel extract` + `update`); the new unified msgid + "In the inheritance process, the entire wallet will always be fully emptied." + is translated in `it_IT` and `es_ES`; the old + "...adjustment of the amounts.{}" entry is now obsolete. + +**Verification:** + +- `Will.check_amounts` matrix (fixed-only/percentage/empty wallet) behaves as + expected; core/offline suites plus `test_gui_prepare_will_history.py`, + `test_sync_locktime_built_txs.py`, `test_rebuild_on_close_setting.py`, + `test_translations.py` and the smoke test pass. +- Offscreen repro of `task_phase1`: "Checking variables" shows green "Ok" on + success and the (shortened) warning on the row on `AmountException` - never + "Wait". +- `py_compile` clean; `ruff check` adds no new violations (only the pre-existing + `I001` in `dialogs.py`). + +**Outcome:** DONE (pending the owner's test of the ZIP). diff --git a/bal/cli/commands.py b/bal/cli/commands.py index 0bdda14..6598ef3 100644 --- a/bal/cli/commands.py +++ b/bal/cli/commands.py @@ -238,24 +238,26 @@ async def willexecutors_update( wallet, "willexecutors_update", url, - address, - base_fee, - info, - promo_code, - rename_to, + address=address, + base_fee=base_fee, + info=info, + promo_code=promo_code, + rename_to=rename_to, ) @plugin_command("nw", plugin_name) async def willexecutors_select( - self, url, value=True, wallet=None, plugin=None + self, url=None, value=True, only_valid=False, wallet=None, plugin=None ): - """Select (or deselect) a will-executor. + """Select (or deselect) a will-executor, or bulk-apply a selection. - arg:str:url:The will-executor URL. + arg:str:url:The will-executor URL; omit to act on every executor. arg:bool:value:True to select, False to deselect. + arg:bool:only_valid:When selecting/deselecting all, only change the valid executors (the invalid ones are deselected/left alone). """ - return _call(plugin, wallet, "willexecutors_select", [url], value) + urls = [url] if url is not None else None + return _call(plugin, wallet, "willexecutors_select", urls, value, only_valid) @plugin_command("nw", plugin_name) @@ -298,12 +300,13 @@ async def willexecutors_import(self, path, wallet=None, plugin=None): @plugin_command("nw", plugin_name) -async def willexecutors_export(self, path, wallet=None, plugin=None): +async def willexecutors_export(self, path, subset=None, wallet=None, plugin=None): """Export the will-executors to a JSON file. arg:str:path:Destination file path. + arg:str:subset:Optional filter: ``selected`` (only selected executors) or ``valid`` (only valid ones); omit to export all. """ - return _call(plugin, wallet, "willexecutors_export", path) + return _call(plugin, wallet, "willexecutors_export", path, subset) # --------------------------------------------------------------------------- # diff --git a/bal/cli/controller.py b/bal/cli/controller.py index 5aecf0e..4f0112a 100644 --- a/bal/cli/controller.py +++ b/bal/cli/controller.py @@ -88,6 +88,27 @@ def _user_facing(e): return UserFacingException(_("Will-Executor not present")) if isinstance(e, will_mod.NoWillExecutorNotPresent): return UserFacingException(_("No backup transaction or will-executor selected")) + if isinstance(e, will_mod.HeirChangeException): + return UserFacingException(_("The heirs changed: a new will must be prepared.")) + if isinstance(e, will_mod.WillexecutorChangeException): + return UserFacingException( + _("A will-executor changed: a new will must be prepared.") + ) + if isinstance(e, will_mod.NotCompleteWillException): + # ``WillException.__init__`` stores the detail in ``self.msg`` but calls + # ``Exception.__init__(self)`` without it, so ``e.args`` is always empty; + # the default sentinel message is "WillException". + detail = getattr(e, "msg", None) + if detail and detail != "WillException": + return UserFacingException( + _( + "The wallet contains funds that the current will does not " + "cover yet: a new will must be prepared." + ) + ) + return UserFacingException( + _("The will contains no valid transaction: a new will must be prepared.") + ) if isinstance(e, will_mod.AmountException): return UserFacingException( _( @@ -121,6 +142,21 @@ def _user_facing(e): "but less than the locktime" ) ) + if isinstance(e, Willexecutors.NoServersForChainError): + if e.url: + return UserFacingException( + _( + "Could not reach the configured welist server.\n\n" + "Server: {url}\n" + "Error: {reason}\n\n" + "Please verify the welist server URL in the plugin settings." + ).format(url=e.url, reason=e.reason or "empty response") + ) + return UserFacingException( + _("No active will-executor found for the {chain} network.").format( + chain=e.chain + ) + ) return e @@ -352,6 +388,7 @@ class BalController: self.date_to_check = resolve_date_to_check( self.plugin.is_basic_mode(), self.will_settings, built_locktime=_new_locktime, + creation_date=Will.get_creation_time(self.willitems), ) self.willexecutors = Willexecutors.get_willexecutors( self.plugin, update=False, task=False @@ -472,6 +509,11 @@ class BalController: self.wallet.dust_threshold(), max_fee=self.plugin.MAX_WILLEXECUTOR_FEE.get(), ) + except will_mod.AmountException as e: + # Mirror the GUI (BalWindow.build_inheritance_transaction): an + # amount mismatch is only a WARNING here, the flow continues (the + # rebuild/normalisation below reconciles the shares). + _logger.warning(f"prepare will: check_amounts: {e}") except Exception as e: raise _user_facing(e) from e @@ -949,6 +991,8 @@ class BalController: heir.append(locktime) else: heir.append(self.will_settings["locktime"]) + if not self.plugin.ENABLE_MULTIVERSE.get(): + heir[3] = self.will_settings["locktime"] if is_op_return_address(address): heir[2] = "0" return Heirs.validate_heir(heir[0], heir[1:]) @@ -1034,7 +1078,7 @@ class BalController: return self.willexecutors_show(url) def willexecutors_update(self, url, address=None, base_fee=None, info=None, - rename_to=None): + promo_code=None, rename_to=None): if url not in self.willexecutors: raise UserFacingException(_("Will-Executor not found: {}").format(url)) we = self.willexecutors[url] @@ -1045,6 +1089,8 @@ class BalController: we["base_fee"] = int(base_fee) if info is not None: we["info"] = info.strip() or "New Will Executor" + if promo_code is not None: + we["promo_code"] = promo_code if rename_to and rename_to != url: if rename_to in self.willexecutors: raise UserFacingException( @@ -1065,17 +1111,38 @@ class BalController: Willexecutors.save(self.plugin, self.willexecutors) return {"deleted": deleted} - def willexecutors_select(self, urls=None, select=True): - """Select/deselect one, many or all will-executors.""" - selected = {} - targets = urls if urls is not None else list(self.willexecutors) + def willexecutors_select(self, urls=None, select=True, only_valid=False): + """Select or deselect will-executors. + + Mirrors the GUI's single-toggle and ``set_select_all(select, + only_valid)`` bulk actions. ``urls`` is the set of records to act on + (all of them when omitted); with ``only_valid`` the selection is + restricted by validity: selecting sets the valid ones to True and the + invalid ones to False, while deselecting only clears the invalid ones. + """ + targets = ( + list(self.willexecutors) + if urls is None + else [url for url in urls if url in self.willexecutors] + ) for url in targets: - if url not in self.willexecutors: - continue - self.willexecutors[url]["selected"] = bool(select) - selected[url] = bool(select) + we = self.willexecutors[url] + if only_valid: + is_valid = Willexecutors.is_valid( + we, + max_fee=self.plugin.MAX_WILLEXECUTOR_FEE.get(), + dust=self.wallet.dust_threshold(), + ) + if select: + we["selected"] = bool(is_valid) + elif not is_valid: + we["selected"] = False + else: + we["selected"] = bool(select) Willexecutors.save(self.plugin, self.willexecutors) - return selected + return { + url: bool(self.willexecutors[url].get("selected")) for url in targets + } def willexecutors_ping(self, urls=None): """Ping the (selected) will-executor servers and refresh their info. @@ -1125,10 +1192,12 @@ class BalController: result = {} last_error = None + any_server_reached = False try: resp = Willexecutors.send_request( "get", url, timeout=10, max_retries=1, retry_sleep=1 ) + any_server_reached = True if not isinstance(resp, dict): last_error = "invalid response format" _logger.warning( @@ -1154,12 +1223,17 @@ class BalController: last_error = str(e) _logger.error(f"fetch_will_executors_list: {url} -> {type(e).__name__}: {e}") - if not result and not basic: - raise UserFacingException( - _("Could not reach the configured welist server.\nServer: {}\nError: {}").format( - url, last_error or "empty response" + if not result: + if not basic: + # Advanced mode: always raise with full details. + raise Willexecutors.NoServersForChainError( + chainname, + url=url, + reason=last_error or "empty response", ) - ) + if any_server_reached: + # Basic mode: the server answered but has no data for this chain. + raise Willexecutors.NoServersForChainError(chainname) return result def willexecutors_download(self): @@ -1179,18 +1253,41 @@ class BalController: raise UserFacingException( _("Invalid entry {} in will-executors file").format(url) ) - if url not in self.willexecutors: - we = dict(we) - we.setdefault("selected", False) - we.setdefault("status", "New") - we.setdefault("promo_code", None) - self.willexecutors[url] = we + # Mirror the GUI import (``willexecutors_list.update(data)``): + # existing URLs are overwritten with the imported record, missing + # fields get sane defaults. + we = dict(we) + we.setdefault("selected", False) + we.setdefault("status", "New") + we.setdefault("promo_code", None) + self.willexecutors[url] = we Willexecutors.save(self.plugin, self.willexecutors) return {"imported": len(data), "total": len(self.willexecutors)} - def willexecutors_export(self, path): - write_json_file(path, self.willexecutors) - return {"exported": len(self.willexecutors), "path": path} + def willexecutors_export(self, path, subset=None): + """Export the will-executors to ``path``. + + ``subset`` mirrors the GUI export filter: ``"selected"`` writes only + the selected records, ``"valid"`` only the valid ones, anything else + (or ``None``) writes every record. + """ + data = self.willexecutors + if subset == "selected": + data = { + url: we for url, we in data.items() if Willexecutors.is_selected(we) + } + elif subset == "valid": + data = { + url: we + for url, we in data.items() + if Willexecutors.is_valid( + we, + max_fee=self.plugin.MAX_WILLEXECUTOR_FEE.get(), + dust=self.wallet.dust_threshold(), + ) + } + write_json_file(path, data) + return {"exported": len(data), "path": path} # ------------------------------------------------------------------ # # Settings @@ -1290,11 +1387,3 @@ class BalController: ) return value return str(raw) - - -def get_decimal_point(plugin): - """Standalone helper returning Electrum's configured BTC decimal point.""" - try: - return plugin.config.BTC_AMOUNTS_DECIMAL_POINT - except AttributeError: - return 8 diff --git a/bal/core/will.py b/bal/core/will.py index df6cfc4..8ee9b93 100644 --- a/bal/core/will.py +++ b/bal/core/will.py @@ -823,11 +823,19 @@ class Will: for utxo in all_utxos: wallet_balance += utxo.value_sats() - if fixed_amount >= wallet_balance: + if fixed_amount > 0 and fixed_amount >= wallet_balance: + # Only a REAL fixed amount needs to be funded: with no fixed heirs + # (all percentages) fixed_amount is 0 and ``0 >= 0`` would wrongly + # flag an empty/fully-committed wallet as an amount error. raise FixedAmountException( f"Fixed amount({fixed_amount}) >= {wallet_balance}" ) - if perc_amount != 100: + if perc_heirs and perc_amount != 100: + # Percentages only have to add up to 100% when the will actually + # uses percentage heirs. A will made ONLY of fixed-amount heirs has + # no percentages, so perc_amount is 0 - which used to raise here and + # left "Checking variables" stuck on "Wait" for every fixed-only + # will (the build normalises the fixed shares anyway). raise PercAmountException(f"Perc amount({perc_amount}) =! 100%") for url, wex in willexecutors.items(): @@ -835,7 +843,7 @@ class Will: if max_fee is not None and int(wex["base_fee"]) > max_fee: raise WillExecutorFeeTooHighException(wex, max_fee) temp_balance = wallet_balance - int(wex["base_fee"]) - if fixed_amount >= temp_balance: + if fixed_amount > 0 and fixed_amount >= temp_balance: raise FixedAmountException( f"Willexecutor{url} excess base fee({wex['base_fee']}), {fixed_amount} >={temp_balance}" ) diff --git a/bal/gui/qt/dialogs.py b/bal/gui/qt/dialogs.py index 21629e5..afed74a 100644 --- a/bal/gui/qt/dialogs.py +++ b/bal/gui/qt/dialogs.py @@ -691,11 +691,22 @@ class BalBuildWillDialog(BalDialog): # Manual next-steps hint (Sign / Broadcast) shown to the user after the # dialog finishes; None when nothing is left to do. self._next_steps_hint = None - # Set to True by _sync_locktime_to_built_txs when the delivery date was - # automatically anticipated during a rebuild. Used to explain to the - # user WHY signing is being requested (otherwise the sign prompt appears - # without any reason, as the owner reported). + # Set to True by _build_success_report when the rebuild moved the + # delivery date one day earlier than the previous will. Used both to + # show the "Anticipated" warning on the "Building your will" row and to + # explain WHY signing is being requested (otherwise the sign prompt + # appears without any reason, as the owner reported). self._date_was_anticipated = False + # The anticipated locktime (UNIX timestamp) captured by + # _build_success_report, formatted into the "Anticipated - new + # delivery date: ..." warning. None when the last build did not + # anticipate the delivery. + self._anticipated_locktime = None + # The will's minimum locktime captured BEFORE the rebuild (see + # task_phase1). _build_success_report compares it with the rebuilt one + # to tell whether the delivery was anticipated by one day. None when no + # build ran yet. + self._previous_min_locktime = None # Set to True right after we broadcast an automatic invalidation # transaction (the "postpone" path). On the very next phase-1 re-check # Electrum may not have seen the invalidation tx yet, so it would still @@ -789,18 +800,32 @@ class BalBuildWillDialog(BalDialog): _logger.debug("variables ok") self.msg_set_status(_("Checking variables"), varrow, _("Ok"), self.COLOR_OK) except AmountException: - self.msg_set_checking( - self.msg_warning( - _( - "In the inheritance process, " - "the entire wallet will always be fully emptied. \n" - "Your settings require an adjustment of the amounts" - ) - ) + # The amount check is a WARNING, not a hard failure: the build can + # still normalise the shares (see BalWindow.build_inheritance_ + # transaction, which shows the same warning and continues). Report + # it on the "Checking variables" row itself, with the warning colour. + # Previously this was routed to msg_set_checking(), i.e. the + # "Checking your will" row, and then immediately overwritten by the + # msg_set_checking() call below - so the warning was lost AND the + # "Checking variables" row stayed stuck on its initial "Wait". + self.msg_set_status( + _("Checking variables"), + varrow, + _( + "In the inheritance process, " + "the entire wallet will always be fully emptied." + ), + self.COLOR_WARNING, ) except WillExecutorFeeTooHighException as e: - self.msg_set_checking( - self.msg_warning(_("Will-executor fee too high: {}").format(e)) + # Same reasoning as the AmountException branch above: show the + # warning on the "Checking variables" row so it is neither lost nor + # left stuck on "Wait". + self.msg_set_status( + _("Checking variables"), + varrow, + _("Will-executor fee too high: {}").format(e), + self.COLOR_WARNING, ) self.msg_set_checking() @@ -897,6 +922,18 @@ class BalBuildWillDialog(BalDialog): if have_to_build: self.msg_set_building() + # Capture the delivery date of the CURRENT (previous) will BEFORE + # the rebuild overwrites it, so _build_success_report can tell + # whether the rebuild ANTICIPATED the delivery by one day. The core + # anticipates by moving the rebuilt txs one day EARLIER than the + # previous will that spends the same coins (Will.check_anticipate / + # Will.search_anticipate), so comparing the two is the only reliable + # signal: a relative recipe ("1y"/"30d") is anchored to the built tx, + # which is why comparing the built locktime with the STORED value + # (see _sync_locktime_to_built_txs) misses the anticipation. + self._previous_min_locktime = Will.get_min_locktime( + self.bal_window.willitems + ) try: txs = self.bal_window.build_will() if not txs: @@ -1085,7 +1122,40 @@ class BalBuildWillDialog(BalDialog): # auto-anticipated) transactions, otherwise the next Check would wrongly # ask to invalidate. See _sync_locktime_to_built_txs for the full why. self._sync_locktime_to_built_txs() - self.msg_set_building(self.msg_ok()) + # Detect an automatic anticipation by comparing the will's delivery date + # BEFORE the rebuild (captured in task_phase1) with the one AFTER it: + # the core anticipates by moving the rebuilt txs one day earlier than + # the previous will that spends the same coins (Will.check_anticipate). + # This is format-agnostic: it works whether the stored recipe is an + # absolute timestamp or a relative "1y"/"30d" recipe (anchoring makes a + # relative recipe unusable for a stored-vs-built comparison). + new_min_locktime = Will.get_min_locktime(self.bal_window.willitems) + previous_min_locktime = self._previous_min_locktime + self._date_was_anticipated = ( + previous_min_locktime is not None + and new_min_locktime is not None + and int(new_min_locktime) < int(previous_min_locktime) + ) + self._anticipated_locktime = ( + int(new_min_locktime) if self._date_was_anticipated else None + ) + # Owner request: when the rebuild anticipated the delivery, do NOT show + # a plain "Ok" on the "Building your will" row - show a warning that + # names the anticipation and the NEW delivery date, so the user is told + # the inheritance will be delivered one day earlier. The sign step then + # explains WHY signing is requested on its OWN row ("Signing your + # will"), leaving this warning visible. + if self._anticipated_locktime is not None: + new_date = BalTimestamp._safe_fromtimestamp( + self._anticipated_locktime + ).strftime("%Y-%m-%d") + self.msg_set_building( + self.msg_alert( + _("Anticipated - new delivery date: {}").format(new_date) + ) + ) + else: + self.msg_set_building(self.msg_ok()) # List EACH heir on its OWN line, green + bold (owner request: revert the # one-line "Heirs: a, b, c" form of v0.4.6). Heir names can be long, and # now that the report area scrolls (allegato1) there is no need to cram @@ -1177,10 +1247,10 @@ class BalBuildWillDialog(BalDialog): f"sync delivery date to built tx locktime: " f"{current} -> {min_locktime}" ) - # Remember that we anticipated the date, so the later sign - # prompt can explain WHY signing is needed - # (see on_success_phase1). - self._date_was_anticipated = True + # NOTE: this only SYNCS the stored date. Whether the rebuild + # ANTICIPATED the delivery is decided in _build_success_report + # by comparing the previous and the rebuilt locktimes (the only + # format-agnostic signal, see there). # update_setting_widgets stores the value, persists it and # refreshes the date widgets in all panels/wizard (the .ics # calendar too). @@ -1624,19 +1694,18 @@ class BalBuildWillDialog(BalDialog): # If the will was rebuilt with an automatically anticipated # delivery date, explain WHY we are now asking to sign: # otherwise the sign prompt appears with no reason (owner - # feedback). The note is shown on the "Building your will" - # row (orange warning) before the modal password prompt - # opens, so the user can read it. + # feedback). This note goes on its OWN "Signing your will" row + # so it does NOT overwrite the "Anticipated - new delivery + # date" warning already shown on the "Building your will" row, + # and it is readable before the modal password prompt opens. if self._date_was_anticipated: - self.msg_set_building( - "{}".format( - _( - "The delivery date was automatically moved " - "one day earlier so the updated will can " - "correctly replace the previous one.\n" - "Please sign (and broadcast) to confirm " - "the change." - ) + self.msg_set_signing( + _( + "The delivery date was automatically moved " + "one day earlier so the updated will can " + "correctly replace the previous one.\n" + "Please sign (and broadcast) to confirm " + "the change." ) ) password = self.bal_window.get_wallet_password( diff --git a/bal/gui/qt/window.py b/bal/gui/qt/window.py index 8ab73bb..3c03c79 100644 --- a/bal/gui/qt/window.py +++ b/bal/gui/qt/window.py @@ -835,11 +835,11 @@ class BalWindow: self.window.wallet.dust_threshold(), max_fee=self.bal_plugin.MAX_WILLEXECUTOR_FEE.get(), ) - except AmountException as e: + except AmountException: self.show_warning( _( - "In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts.{}" - ).format(e) + "In the inheritance process, the entire wallet will always be fully emptied." + ) ) except WillExecutorFeeTooHighException as e: self.show_error( diff --git a/bal/locale/bal.pot b/bal/locale/bal.pot index 529724f..80d7116 100644 --- a/bal/locale/bal.pot +++ b/bal/locale/bal.pot @@ -8,14 +8,14 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-10-10 15:53-0400\n" +"POT-Creation-Date: 2026-10-15 16:08-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: bal/core/plugin_base.py:378 msgid "" @@ -28,87 +28,88 @@ msgstr "" msgid "BAL -Will execution of $wallet_name" msgstr "" -#: bal/core/will.py:1502 +#: bal/core/will.py:1525 +#, python-brace-format msgid "NOT {}" msgstr "" -#: bal/core/will.py:1526 +#: bal/core/will.py:1549 msgid "Anticipated" msgstr "" -#: bal/core/will.py:1527 +#: bal/core/will.py:1550 msgid "Broadcasted" msgstr "" -#: bal/core/will.py:1528 +#: bal/core/will.py:1551 msgid "Checked" msgstr "" -#: bal/core/will.py:1529 +#: bal/core/will.py:1552 msgid "Check Failed" msgstr "" -#: bal/core/will.py:1530 +#: bal/core/will.py:1553 msgid "Signed" msgstr "" -#: bal/core/will.py:1531 +#: bal/core/will.py:1554 msgid "Confirmed" msgstr "" -#: bal/core/will.py:1532 bal/gui/qt/lists.py:1354 bal/gui/qt/lists.py:1368 +#: bal/core/will.py:1555 bal/gui/qt/lists.py:1354 bal/gui/qt/lists.py:1368 msgid "Error" msgstr "" -#: bal/core/will.py:1533 bal/gui/qt/dialogs.py:826 +#: bal/core/will.py:1556 bal/gui/qt/dialogs.py:846 msgid "Expired" msgstr "" -#: bal/core/will.py:1534 +#: bal/core/will.py:1557 msgid "Exported" msgstr "" -#: bal/core/will.py:1535 +#: bal/core/will.py:1558 msgid "Imported" msgstr "" -#: bal/core/will.py:1536 +#: bal/core/will.py:1559 msgid "Invalidated" msgstr "" -#: bal/core/will.py:1537 +#: bal/core/will.py:1560 msgid "Mempool" msgstr "" -#: bal/core/will.py:1538 +#: bal/core/will.py:1561 msgid "Push failed" msgstr "" -#: bal/core/will.py:1539 +#: bal/core/will.py:1562 msgid "Pushed" msgstr "" -#: bal/core/will.py:1540 +#: bal/core/will.py:1563 msgid "Partially Signed" msgstr "" -#: bal/core/will.py:1541 +#: bal/core/will.py:1564 msgid "Replaced" msgstr "" -#: bal/core/will.py:1542 +#: bal/core/will.py:1565 msgid "Restored" msgstr "" -#: bal/core/will.py:1543 +#: bal/core/will.py:1566 msgid "Updated" msgstr "" -#: bal/core/will.py:1544 bal/gui/qt/dialogs.py:2635 +#: bal/core/will.py:1567 bal/gui/qt/dialogs.py:2676 msgid "Valid" msgstr "" -#: bal/core/will.py:1550 +#: bal/core/will.py:1573 msgid "New" msgstr "" @@ -116,7 +117,8 @@ msgstr "" msgid "Waiting..." msgstr "" -#: bal/core/willexecutors.py:394 bal/gui/qt/window.py:245 bal/gui/qt/window.py:1667 +#: bal/core/willexecutors.py:394 bal/gui/qt/window.py:245 +#: bal/gui/qt/window.py:1667 msgid "Success" msgstr "" @@ -141,6 +143,7 @@ msgid "No reminders were saved: the delivery date is too close (or already passe msgstr "" #: bal/gui/qt/calendar.py:105 bal/gui/qt/calendar.py:126 +#, python-brace-format msgid "Could not open the calendar file: {}" msgstr "" @@ -157,12 +160,14 @@ msgid "Save calendar reminder (.ics)" msgstr "" #: bal/gui/qt/calendar.py:150 bal/gui/qt/widgets.py:1082 +#, python-brace-format msgid "" "Calendar file saved to:\n" "{}" msgstr "" #: bal/gui/qt/calendar.py:155 bal/gui/qt/widgets.py:1078 +#, python-brace-format msgid "Could not save the calendar file: {}" msgstr "" @@ -183,10 +188,12 @@ msgid "XL - ~1800 bytes/QR (high-res cameras)" msgstr "" #: bal/gui/qt/common.py:256 +#, python-brace-format msgid "Select file to save your {}" msgstr "" #: bal/gui/qt/common.py:271 +#, python-brace-format msgid "Your {0} were exported to '{1}'" msgstr "" @@ -194,15 +201,15 @@ msgstr "" msgid "Bal Wizard Setup" msgstr "" -#: bal/gui/qt/dialogs.py:325 bal/gui/qt/dialogs.py:2764 +#: bal/gui/qt/dialogs.py:325 bal/gui/qt/dialogs.py:2805 msgid "Previous" msgstr "" -#: bal/gui/qt/dialogs.py:329 bal/gui/qt/dialogs.py:2767 +#: bal/gui/qt/dialogs.py:329 bal/gui/qt/dialogs.py:2808 msgid "Next" msgstr "" -#: bal/gui/qt/dialogs.py:333 bal/gui/qt/dialogs.py:4050 +#: bal/gui/qt/dialogs.py:333 bal/gui/qt/dialogs.py:4091 msgid "Cancel" msgstr "" @@ -210,7 +217,7 @@ msgstr "" msgid "Bitcoin After Life Heirs" msgstr "" -#: bal/gui/qt/dialogs.py:360 +#: bal/gui/qt/dialogs.py:361 msgid "" "Please add your heirs\n" " remember that the wallet balance will be spent at 100%" @@ -220,11 +227,14 @@ msgstr "" msgid "Add" msgstr "" -#: bal/gui/qt/dialogs.py:372 bal/gui/qt/dialogs.py:2596 bal/gui/qt/lists.py:311 bal/gui/qt/lists.py:673 bal/gui/qt/lists.py:1237 +#: bal/gui/qt/dialogs.py:372 bal/gui/qt/dialogs.py:2637 bal/gui/qt/lists.py:311 +#: bal/gui/qt/lists.py:673 bal/gui/qt/lists.py:1237 msgid "Import" msgstr "" -#: bal/gui/qt/dialogs.py:374 bal/gui/qt/dialogs.py:2432 bal/gui/qt/dialogs.py:2600 bal/gui/qt/lists.py:312 bal/gui/qt/lists.py:672 bal/gui/qt/lists.py:1249 +#: bal/gui/qt/dialogs.py:374 bal/gui/qt/dialogs.py:2473 +#: bal/gui/qt/dialogs.py:2641 bal/gui/qt/lists.py:312 bal/gui/qt/lists.py:672 +#: bal/gui/qt/lists.py:1249 msgid "Export" msgstr "" @@ -276,117 +286,137 @@ msgstr "" msgid "Building Will:" msgstr "" -#: bal/gui/qt/dialogs.py:731 bal/gui/qt/dialogs.py:757 bal/gui/qt/dialogs.py:767 bal/gui/qt/dialogs.py:790 +#: bal/gui/qt/dialogs.py:737 bal/gui/qt/dialogs.py:763 +#: bal/gui/qt/dialogs.py:773 bal/gui/qt/dialogs.py:796 +#: bal/gui/qt/dialogs.py:807 bal/gui/qt/dialogs.py:820 msgid "Checking variables" msgstr "" -#: bal/gui/qt/dialogs.py:758 +#: bal/gui/qt/dialogs.py:764 msgid "Check Alive Threshold Passed: you have to Invalidate your old Will" msgstr "" -#: bal/gui/qt/dialogs.py:767 bal/gui/qt/dialogs.py:850 +#: bal/gui/qt/dialogs.py:773 bal/gui/qt/dialogs.py:870 msgid "No Heirs" msgstr "" -#: bal/gui/qt/dialogs.py:790 bal/gui/qt/dialogs.py:1338 bal/gui/qt/dialogs.py:2284 bal/gui/qt/window.py:2319 +#: bal/gui/qt/dialogs.py:796 bal/gui/qt/dialogs.py:1380 +#: bal/gui/qt/dialogs.py:2325 bal/gui/qt/window.py:2319 msgid "Ok" msgstr "" -#: bal/gui/qt/dialogs.py:794 -msgid "" -"In the inheritance process, the entire wallet will always be fully emptied. \n" -"Your settings require an adjustment of the amounts" +#: bal/gui/qt/dialogs.py:810 bal/gui/qt/window.py:841 +msgid "In the inheritance process, the entire wallet will always be fully emptied." msgstr "" -#: bal/gui/qt/dialogs.py:803 bal/gui/qt/window.py:846 +#: bal/gui/qt/dialogs.py:822 bal/gui/qt/window.py:846 +#, python-brace-format msgid "Will-executor fee too high: {}" msgstr "" -#: bal/gui/qt/dialogs.py:837 +#: bal/gui/qt/dialogs.py:857 msgid "Postponed: invalidating old will" msgstr "" -#: bal/gui/qt/dialogs.py:873 bal/gui/qt/dialogs.py:882 bal/gui/qt/dialogs.py:2244 +#: bal/gui/qt/dialogs.py:893 bal/gui/qt/dialogs.py:902 +#: bal/gui/qt/dialogs.py:2285 msgid "Checking your will" msgstr "" -#: bal/gui/qt/dialogs.py:875 +#: bal/gui/qt/dialogs.py:895 msgid "An inheritance of this wallet is already executed (on blockchain)" msgstr "" -#: bal/gui/qt/dialogs.py:884 +#: bal/gui/qt/dialogs.py:904 msgid "Inheritance in mempool (waiting confirmation)" msgstr "" -#: bal/gui/qt/dialogs.py:917 +#: bal/gui/qt/dialogs.py:937 msgid "Will-Executor excluded" msgstr "" -#: bal/gui/qt/dialogs.py:917 bal/gui/qt/dialogs.py:1011 bal/gui/qt/dialogs.py:2225 bal/gui/qt/dialogs.py:2236 +#: bal/gui/qt/dialogs.py:937 bal/gui/qt/dialogs.py:1031 +#: bal/gui/qt/dialogs.py:2266 bal/gui/qt/dialogs.py:2277 msgid "Skipped" msgstr "" -#: bal/gui/qt/dialogs.py:923 bal/gui/qt/dialogs.py:1708 bal/gui/qt/lists.py:345 bal/gui/qt/theme.py:116 +#: bal/gui/qt/dialogs.py:943 bal/gui/qt/dialogs.py:1749 bal/gui/qt/lists.py:345 +#: bal/gui/qt/theme.py:116 msgid "Will-Executor" msgstr "" -#: bal/gui/qt/dialogs.py:924 +#: bal/gui/qt/dialogs.py:944 msgid "Not present - select one or enable backup mode" msgstr "" -#: bal/gui/qt/dialogs.py:986 +#: bal/gui/qt/dialogs.py:1006 msgid "All heirs' shares are below the dust limit: the inheritance cannot be created. Increase the amounts or reduce the number of heirs." msgstr "" -#: bal/gui/qt/dialogs.py:1002 +#: bal/gui/qt/dialogs.py:1022 +#, python-brace-format msgid "Wallet balance is too low: {} satoshi available, but the miner and will-executor fees need {} satoshi (the minimum usable amount is {} satoshi). Add funds, or select fewer will-executors." msgstr "" -#: bal/gui/qt/dialogs.py:1045 +#: bal/gui/qt/dialogs.py:1065 +#, python-brace-format msgid "Heir {}" msgstr "" -#: bal/gui/qt/dialogs.py:1047 +#: bal/gui/qt/dialogs.py:1067 +#, python-brace-format msgid "{} is DUST - excluded (amount below dust limit)" msgstr "" -#: bal/gui/qt/dialogs.py:1103 +#: bal/gui/qt/dialogs.py:1120 +#, python-brace-format +msgid "Anticipated - new delivery date: {}" +msgstr "" + +#: bal/gui/qt/dialogs.py:1139 msgid "Heir" msgstr "" -#: bal/gui/qt/dialogs.py:1220 bal/gui/qt/dialogs.py:2273 +#: bal/gui/qt/dialogs.py:1262 bal/gui/qt/dialogs.py:2314 +#, python-brace-format msgid "Please wait {}secs" msgstr "" -#: bal/gui/qt/dialogs.py:1227 bal/gui/qt/dialogs.py:1279 bal/gui/qt/dialogs.py:1317 +#: bal/gui/qt/dialogs.py:1269 bal/gui/qt/dialogs.py:1321 +#: bal/gui/qt/dialogs.py:1359 msgid "Broadcasting" msgstr "" -#: bal/gui/qt/dialogs.py:1338 bal/gui/qt/window.py:2321 +#: bal/gui/qt/dialogs.py:1380 bal/gui/qt/window.py:2321 msgid "Ko" msgstr "" -#: bal/gui/qt/dialogs.py:1349 +#: bal/gui/qt/dialogs.py:1391 msgid "Timeout - no answer" msgstr "" -#: bal/gui/qt/dialogs.py:1391 +#: bal/gui/qt/dialogs.py:1433 +#, python-brace-format msgid "checking {} - {}" msgstr "" -#: bal/gui/qt/dialogs.py:1394 bal/gui/qt/dialogs.py:2242 bal/gui/qt/window.py:1695 +#: bal/gui/qt/dialogs.py:1436 bal/gui/qt/dialogs.py:2283 +#: bal/gui/qt/window.py:1695 msgid "Waiting" msgstr "" -#: bal/gui/qt/dialogs.py:1408 +#: bal/gui/qt/dialogs.py:1450 +#, python-brace-format msgid "checked {} - {}" msgstr "" -#: bal/gui/qt/dialogs.py:1458 bal/gui/qt/dialogs.py:2028 bal/gui/qt/dialogs.py:2039 +#: bal/gui/qt/dialogs.py:1500 bal/gui/qt/dialogs.py:2069 +#: bal/gui/qt/dialogs.py:2080 +#, python-brace-format msgid "Error: {}" msgstr "" -#: bal/gui/qt/dialogs.py:1519 +#: bal/gui/qt/dialogs.py:1562 msgid "" "Your will has expired and must be invalidated before it can be rebuilt.\n" "A transaction window will now open:\n" @@ -394,156 +424,163 @@ msgid "" "After the invalidation is confirmed, press the Check button to finish the will." msgstr "" -#: bal/gui/qt/dialogs.py:1549 bal/gui/qt/window.py:852 +#: bal/gui/qt/dialogs.py:1591 bal/gui/qt/window.py:852 msgid "Check Alive must be after today and before the delivery date, please update it" msgstr "" -#: bal/gui/qt/dialogs.py:1571 +#: bal/gui/qt/dialogs.py:1614 msgid "" "Your old will has been invalidated and the transaction was broadcast.\n" "Electrum may need a little time to register it.\n" "Please wait until the invalidation transaction is confirmed, then press the Check button again to finish updating your will." msgstr "" -#: bal/gui/qt/dialogs.py:1587 +#: bal/gui/qt/dialogs.py:1629 msgid "Invalidate your old will" msgstr "" -#: bal/gui/qt/dialogs.py:1601 bal/gui/qt/dialogs.py:1646 +#: bal/gui/qt/dialogs.py:1643 bal/gui/qt/dialogs.py:1687 msgid "Aborted" msgstr "" -#: bal/gui/qt/dialogs.py:1620 +#: bal/gui/qt/dialogs.py:1662 msgid "Auto-sign disabled — sign manually" msgstr "" -#: bal/gui/qt/dialogs.py:1633 +#: bal/gui/qt/dialogs.py:1676 msgid "" "The delivery date was automatically moved one day earlier so the updated will can correctly replace the previous one.\n" "Please sign (and broadcast) to confirm the change." msgstr "" -#: bal/gui/qt/dialogs.py:1643 +#: bal/gui/qt/dialogs.py:1684 msgid "Sign your will" msgstr "" -#: bal/gui/qt/dialogs.py:1648 bal/gui/qt/dialogs.py:1931 +#: bal/gui/qt/dialogs.py:1689 bal/gui/qt/dialogs.py:1972 msgid "Nothing to do" msgstr "" -#: bal/gui/qt/dialogs.py:1667 +#: bal/gui/qt/dialogs.py:1708 msgid "Finished" msgstr "" -#: bal/gui/qt/dialogs.py:1684 +#: bal/gui/qt/dialogs.py:1725 msgid "Calendar" msgstr "" -#: bal/gui/qt/dialogs.py:1686 bal/gui/qt/dialogs.py:1716 bal/gui/qt/dialogs.py:1783 bal/gui/qt/dialogs.py:2031 bal/gui/qt/dialogs.py:2978 bal/gui/qt/dialogs.py:3233 bal/gui/qt/dialogs.py:4069 +#: bal/gui/qt/dialogs.py:1727 bal/gui/qt/dialogs.py:1757 +#: bal/gui/qt/dialogs.py:1824 bal/gui/qt/dialogs.py:2072 +#: bal/gui/qt/dialogs.py:3019 bal/gui/qt/dialogs.py:3274 +#: bal/gui/qt/dialogs.py:4110 msgid "Close" msgstr "" -#: bal/gui/qt/dialogs.py:1712 bal/gui/qt/dialogs.py:1779 +#: bal/gui/qt/dialogs.py:1753 bal/gui/qt/dialogs.py:1820 msgid "🔮 Wizard" msgstr "" -#: bal/gui/qt/dialogs.py:1775 bal/gui/qt/dialogs.py:2583 +#: bal/gui/qt/dialogs.py:1816 bal/gui/qt/dialogs.py:2624 msgid "Heirs" msgstr "" -#: bal/gui/qt/dialogs.py:1884 bal/gui/qt/widgets.py:1150 +#: bal/gui/qt/dialogs.py:1925 bal/gui/qt/widgets.py:1150 +#, python-brace-format msgid "(reminder {idx}/{total})" msgstr "" -#: bal/gui/qt/dialogs.py:1948 +#: bal/gui/qt/dialogs.py:1989 msgid "All done" msgstr "" -#: bal/gui/qt/dialogs.py:2000 +#: bal/gui/qt/dialogs.py:2041 msgid "Next steps (manual): press 'Sign' to sign your will, then 'Broadcast' to send it to the will-executors." msgstr "" -#: bal/gui/qt/dialogs.py:2005 +#: bal/gui/qt/dialogs.py:2046 msgid "Next step (manual): press 'Sign' to sign your will." msgstr "" -#: bal/gui/qt/dialogs.py:2009 +#: bal/gui/qt/dialogs.py:2050 msgid "Next step (manual): press 'Broadcast' to send your will to the will-executors." msgstr "" -#: bal/gui/qt/dialogs.py:2104 +#: bal/gui/qt/dialogs.py:2145 +#, python-brace-format msgid "Miner fee rate changed (the will was built with {} sat/byte, now it is {}): a new will must be prepared." msgstr "" -#: bal/gui/qt/dialogs.py:2109 +#: bal/gui/qt/dialogs.py:2150 msgid "The miner fee rate changed: a new will must be prepared." msgstr "" -#: bal/gui/qt/dialogs.py:2112 +#: bal/gui/qt/dialogs.py:2154 +#, python-brace-format msgid "Will-executor \"{}\" is not covered by the current will: a new will must be prepared." msgstr "" -#: bal/gui/qt/dialogs.py:2118 +#: bal/gui/qt/dialogs.py:2159 msgid "Backup mode is enabled but the will has no backup transaction: a new will must be prepared." msgstr "" -#: bal/gui/qt/dialogs.py:2126 +#: bal/gui/qt/dialogs.py:2168 +#, python-brace-format msgid "Heir \"{}\" is not covered by the current will (it was added or removed, or its delivery date changed): a new will must be prepared." msgstr "" -#: bal/gui/qt/dialogs.py:2135 +#: bal/gui/qt/dialogs.py:2176 msgid "The heirs changed: a new will must be prepared." msgstr "" -#: bal/gui/qt/dialogs.py:2137 +#: bal/gui/qt/dialogs.py:2178 msgid "A will-executor changed: a new will must be prepared." msgstr "" -#: bal/gui/qt/dialogs.py:2147 +#: bal/gui/qt/dialogs.py:2188 msgid "The wallet contains funds that the current will does not cover yet: a new will must be prepared." msgstr "" -#: bal/gui/qt/dialogs.py:2151 +#: bal/gui/qt/dialogs.py:2192 msgid "The will contains no valid transaction: a new will must be prepared." msgstr "" -#: bal/gui/qt/dialogs.py:2157 +#: bal/gui/qt/dialogs.py:2198 msgid "The will is no longer coherent and must be rebuilt; the exact reason could not be determined." msgstr "" -#: bal/gui/qt/dialogs.py:2187 +#: bal/gui/qt/dialogs.py:2228 msgid "No heirs: add at least one heir before building the will." msgstr "" -#: bal/gui/qt/dialogs.py:2190 +#: bal/gui/qt/dialogs.py:2231 msgid "The wallet has no spendable funds, so no inheritance transaction can be created." msgstr "" -#: bal/gui/qt/dialogs.py:2194 +#: bal/gui/qt/dialogs.py:2235 msgid "No usable will-executor: none of the servers in the list is both selected and valid. Open the will-executor settings, select at least one server and check that it is reachable." msgstr "" -#: bal/gui/qt/dialogs.py:2199 +#: bal/gui/qt/dialogs.py:2240 msgid "No delivery date left to build: every heir's date is already covered by the existing will. Choose a later delivery date, or change an heir's date." msgstr "" -#: bal/gui/qt/dialogs.py:2204 +#: bal/gui/qt/dialogs.py:2245 msgid "The amount to send must cover the miner fees plus this will-executor's fee, and the wallet balance is not enough: select cheaper will-executors, or add funds to the wallet." msgstr "" -#: bal/gui/qt/dialogs.py:2209 +#: bal/gui/qt/dialogs.py:2250 msgid "A will-executor asks for more than the maximum fee you allowed: raise the maximum fee in the settings, or select a cheaper will-executor." msgstr "" -#: bal/gui/qt/dialogs.py:2214 +#: bal/gui/qt/dialogs.py:2255 msgid "The inheritance transactions could not be assembled from the available funds (the balance may not cover the miner fees)." msgstr "" -#: bal/gui/qt/dialogs.py:2218 +#: bal/gui/qt/dialogs.py:2259 msgid "An unexpected error stopped the transactions being prepared for a will-executor, so it was skipped. Try again, or select a different will-executor." msgstr "" -#: bal/gui/qt/dialogs.py:2228 +#: bal/gui/qt/dialogs.py:2270 msgid "" "Could not build the will, and the exact cause could not be determined. Please check that:\n" "- the wallet balance covers the miner and will-executor fees,\n" @@ -552,399 +589,424 @@ msgid "" "- at least one will-executor is selected and reachable." msgstr "" -#: bal/gui/qt/dialogs.py:2249 +#: bal/gui/qt/dialogs.py:2290 msgid "Invalidating old will" msgstr "" -#: bal/gui/qt/dialogs.py:2255 +#: bal/gui/qt/dialogs.py:2296 msgid "Building your will" msgstr "" -#: bal/gui/qt/dialogs.py:2261 +#: bal/gui/qt/dialogs.py:2302 msgid "Signing your will" msgstr "" -#: bal/gui/qt/dialogs.py:2267 +#: bal/gui/qt/dialogs.py:2308 msgid "Broadcasting your will to executors" msgstr "" -#: bal/gui/qt/dialogs.py:2315 +#: bal/gui/qt/dialogs.py:2356 msgid "Wait" msgstr "" -#: bal/gui/qt/dialogs.py:2418 +#: bal/gui/qt/dialogs.py:2459 msgid "Will Details" msgstr "" -#: bal/gui/qt/dialogs.py:2424 bal/gui/qt/dialogs.py:4044 bal/gui/qt/lists.py:668 +#: bal/gui/qt/dialogs.py:2465 bal/gui/qt/dialogs.py:4085 +#: bal/gui/qt/lists.py:668 msgid "Sign" msgstr "" -#: bal/gui/qt/dialogs.py:2428 bal/gui/qt/lists.py:675 +#: bal/gui/qt/dialogs.py:2469 bal/gui/qt/lists.py:675 msgid "Broadcast" msgstr "" -#: bal/gui/qt/dialogs.py:2435 bal/gui/qt/lists.py:677 +#: bal/gui/qt/dialogs.py:2476 bal/gui/qt/lists.py:677 msgid "Invalidate" msgstr "" -#: bal/gui/qt/dialogs.py:2440 bal/gui/qt/lists.py:674 +#: bal/gui/qt/dialogs.py:2481 bal/gui/qt/lists.py:674 msgid "Merge" msgstr "" -#: bal/gui/qt/dialogs.py:2448 +#: bal/gui/qt/dialogs.py:2489 +#, python-brace-format msgid "Expiration date: {}" msgstr "" -#: bal/gui/qt/dialogs.py:2454 +#: bal/gui/qt/dialogs.py:2495 +#, python-brace-format msgid "Valid Txs:{}" msgstr "" -#: bal/gui/qt/dialogs.py:2456 +#: bal/gui/qt/dialogs.py:2497 +#, python-brace-format msgid "Total Txs:{}" msgstr "" -#: bal/gui/qt/dialogs.py:2510 +#: bal/gui/qt/dialogs.py:2551 msgid "Hide replaced" msgstr "" -#: bal/gui/qt/dialogs.py:2512 +#: bal/gui/qt/dialogs.py:2553 msgid "Unhide replaced" msgstr "" -#: bal/gui/qt/dialogs.py:2518 +#: bal/gui/qt/dialogs.py:2559 msgid "Hide invalidated" msgstr "" -#: bal/gui/qt/dialogs.py:2520 +#: bal/gui/qt/dialogs.py:2561 msgid "Unhide invalidated" msgstr "" -#: bal/gui/qt/dialogs.py:2545 +#: bal/gui/qt/dialogs.py:2586 msgid "Will-Executor Service List" msgstr "" -#: bal/gui/qt/dialogs.py:2592 bal/gui/qt/lists.py:314 +#: bal/gui/qt/dialogs.py:2633 bal/gui/qt/lists.py:314 msgid "New Heir" msgstr "" -#: bal/gui/qt/dialogs.py:2634 +#: bal/gui/qt/dialogs.py:2675 msgid "All" msgstr "" -#: bal/gui/qt/dialogs.py:2637 +#: bal/gui/qt/dialogs.py:2678 msgid "Valid NC" msgstr "" -#: bal/gui/qt/dialogs.py:2775 bal/gui/qt/dialogs.py:2853 +#: bal/gui/qt/dialogs.py:2816 bal/gui/qt/dialogs.py:2894 msgid "Auto" msgstr "" -#: bal/gui/qt/dialogs.py:2777 +#: bal/gui/qt/dialogs.py:2818 msgid "Automatically advance through the QR codes." msgstr "" -#: bal/gui/qt/dialogs.py:2781 +#: bal/gui/qt/dialogs.py:2822 msgid "QR codes per second:" msgstr "" -#: bal/gui/qt/dialogs.py:2785 +#: bal/gui/qt/dialogs.py:2826 msgid " /s" msgstr "" -#: bal/gui/qt/dialogs.py:2787 +#: bal/gui/qt/dialogs.py:2828 msgid "Loop" msgstr "" -#: bal/gui/qt/dialogs.py:2790 +#: bal/gui/qt/dialogs.py:2831 msgid "When the last QR code is reached, keep cycling from the first one instead of stopping." msgstr "" -#: bal/gui/qt/dialogs.py:2799 +#: bal/gui/qt/dialogs.py:2840 msgid "QR code size:" msgstr "" -#: bal/gui/qt/dialogs.py:2847 +#: bal/gui/qt/dialogs.py:2888 msgid "Stop" msgstr "" -#: bal/gui/qt/dialogs.py:2868 +#: bal/gui/qt/dialogs.py:2910 +#, python-brace-format msgid "" "Scan the QR codes below with the will-opening device.\n" "{} codes carry the whole transfer (any order works, duplicates are ignored)." msgstr "" -#: bal/gui/qt/dialogs.py:2890 +#: bal/gui/qt/dialogs.py:2931 +#, python-brace-format msgid "Frame {} of {}" msgstr "" -#: bal/gui/qt/dialogs.py:2913 +#: bal/gui/qt/dialogs.py:2954 msgid "Export will" msgstr "" -#: bal/gui/qt/dialogs.py:2924 +#: bal/gui/qt/dialogs.py:2965 msgid "No will transaction to export." msgstr "" -#: bal/gui/qt/dialogs.py:2931 +#: bal/gui/qt/dialogs.py:2972 msgid "Export:" msgstr "" -#: bal/gui/qt/dialogs.py:2938 +#: bal/gui/qt/dialogs.py:2979 msgid "Whole will" msgstr "" -#: bal/gui/qt/dialogs.py:2942 +#: bal/gui/qt/dialogs.py:2983 msgid "Export the full will items (all details/statuses) as JSON, or only the serialized transactions." msgstr "" -#: bal/gui/qt/dialogs.py:2952 +#: bal/gui/qt/dialogs.py:2993 msgid "Send as:" msgstr "" -#: bal/gui/qt/dialogs.py:2954 bal/gui/qt/dialogs.py:3210 +#: bal/gui/qt/dialogs.py:2995 bal/gui/qt/dialogs.py:3251 msgid "File" msgstr "" -#: bal/gui/qt/dialogs.py:2955 bal/gui/qt/dialogs.py:3211 +#: bal/gui/qt/dialogs.py:2996 bal/gui/qt/dialogs.py:3252 msgid "QR Code" msgstr "" -#: bal/gui/qt/dialogs.py:2956 bal/gui/qt/dialogs.py:3212 +#: bal/gui/qt/dialogs.py:2997 bal/gui/qt/dialogs.py:3253 msgid "Audio" msgstr "" -#: bal/gui/qt/dialogs.py:3007 +#: bal/gui/qt/dialogs.py:3049 msgid "Export the will as a JSON file. Uncheck \"Whole will\" above to export only the serialized transactions (comma-separated)." msgstr "" -#: bal/gui/qt/dialogs.py:3016 +#: bal/gui/qt/dialogs.py:3057 msgid "Export…" msgstr "" -#: bal/gui/qt/dialogs.py:3034 bal/gui/qt/dialogs.py:3273 bal/gui/qt/window.py:1791 bal/gui/qt/window.py:1804 +#: bal/gui/qt/dialogs.py:3075 bal/gui/qt/dialogs.py:3314 +#: bal/gui/qt/window.py:1791 bal/gui/qt/window.py:1804 msgid "Audio MODEM plugin is not available." msgstr "" -#: bal/gui/qt/dialogs.py:3038 bal/gui/qt/dialogs.py:3277 +#: bal/gui/qt/dialogs.py:3079 bal/gui/qt/dialogs.py:3318 msgid "Speed (KB/sec):" msgstr "" -#: bal/gui/qt/dialogs.py:3049 +#: bal/gui/qt/dialogs.py:3090 msgid "Send" msgstr "" -#: bal/gui/qt/dialogs.py:3102 bal/gui/qt/dialogs.py:3136 bal/gui/qt/dialogs.py:3161 +#: bal/gui/qt/dialogs.py:3143 bal/gui/qt/dialogs.py:3177 +#: bal/gui/qt/dialogs.py:3202 msgid "No will transaction matches the selected filter." msgstr "" -#: bal/gui/qt/dialogs.py:3125 +#: bal/gui/qt/dialogs.py:3166 msgid "item(s)" msgstr "" -#: bal/gui/qt/dialogs.py:3125 +#: bal/gui/qt/dialogs.py:3166 msgid "transaction(s)" msgstr "" -#: bal/gui/qt/dialogs.py:3127 +#: bal/gui/qt/dialogs.py:3168 +#, python-brace-format msgid "{} {} will be exported." msgstr "" -#: bal/gui/qt/dialogs.py:3130 +#: bal/gui/qt/dialogs.py:3171 +#, python-brace-format msgid "{} {} will be sent." msgstr "" -#: bal/gui/qt/dialogs.py:3154 bal/gui/qt/dialogs.py:3157 bal/gui/qt/dialogs.py:3313 bal/gui/qt/dialogs.py:3316 +#: bal/gui/qt/dialogs.py:3195 bal/gui/qt/dialogs.py:3198 +#: bal/gui/qt/dialogs.py:3354 bal/gui/qt/dialogs.py:3357 msgid "Invalid audio speed." msgstr "" -#: bal/gui/qt/dialogs.py:3193 +#: bal/gui/qt/dialogs.py:3234 msgid "Import will" msgstr "" -#: bal/gui/qt/dialogs.py:3199 +#: bal/gui/qt/dialogs.py:3241 msgid "" "Choose how the will was exported: from a file, QR codes or audio.\n" "The import never touches the live will." msgstr "" -#: bal/gui/qt/dialogs.py:3208 +#: bal/gui/qt/dialogs.py:3249 msgid "Import from:" msgstr "" -#: bal/gui/qt/dialogs.py:3249 +#: bal/gui/qt/dialogs.py:3290 msgid "Import the JSON will file written by the Export ▶ File option. The will opens in a read-only preview window." msgstr "" -#: bal/gui/qt/dialogs.py:3255 +#: bal/gui/qt/dialogs.py:3296 msgid "Choose will file…" msgstr "" -#: bal/gui/qt/dialogs.py:3286 +#: bal/gui/qt/dialogs.py:3327 msgid "Waiting for the audio transfer…" msgstr "" -#: bal/gui/qt/dialogs.py:3289 +#: bal/gui/qt/dialogs.py:3330 msgid "Receive by audio…" msgstr "" -#: bal/gui/qt/dialogs.py:3330 +#: bal/gui/qt/dialogs.py:3371 msgid "Receiving…" msgstr "" -#: bal/gui/qt/dialogs.py:3350 +#: bal/gui/qt/dialogs.py:3391 msgid "No transaction data received." msgstr "" -#: bal/gui/qt/dialogs.py:3368 +#: bal/gui/qt/dialogs.py:3409 +#, python-brace-format msgid "Waiting for audio ({:.1f} kbps)…" msgstr "" -#: bal/gui/qt/dialogs.py:3441 +#: bal/gui/qt/dialogs.py:3482 +#, python-brace-format msgid "Could not parse a transferred will item: {}" msgstr "" -#: bal/gui/qt/dialogs.py:3461 +#: bal/gui/qt/dialogs.py:3502 +#, python-brace-format msgid "Could not parse a transferred transaction: {}" msgstr "" -#: bal/gui/qt/dialogs.py:3473 +#: bal/gui/qt/dialogs.py:3514 msgid "The imported will contains no valid transaction in this wallet." msgstr "" -#: bal/gui/qt/dialogs.py:3484 +#: bal/gui/qt/dialogs.py:3525 +#, python-brace-format msgid "{} imported transaction(s) are not valid in this wallet and were skipped." msgstr "" -#: bal/gui/qt/dialogs.py:3583 +#: bal/gui/qt/dialogs.py:3625 msgid "" "Show the will QR codes to the camera, one after another.\n" "After the first code, every new code is captured automatically.\n" "The first frame sets the total number of codes; duplicates are ignored." msgstr "" -#: bal/gui/qt/dialogs.py:3593 bal/gui/qt/dialogs.py:3771 +#: bal/gui/qt/dialogs.py:3634 bal/gui/qt/dialogs.py:3812 msgid "Waiting for the first frame…" msgstr "" -#: bal/gui/qt/dialogs.py:3610 +#: bal/gui/qt/dialogs.py:3651 msgid "…or paste/type the frame text here" msgstr "" -#: bal/gui/qt/dialogs.py:3614 +#: bal/gui/qt/dialogs.py:3655 msgid "Add frame" msgstr "" -#: bal/gui/qt/dialogs.py:3620 bal/gui/qt/dialogs.py:3863 +#: bal/gui/qt/dialogs.py:3661 bal/gui/qt/dialogs.py:3904 msgid "Scan with camera…" msgstr "" -#: bal/gui/qt/dialogs.py:3623 +#: bal/gui/qt/dialogs.py:3664 msgid "Start the live camera. While it runs, every new QR code shown to the camera is captured automatically." msgstr "" -#: bal/gui/qt/dialogs.py:3629 +#: bal/gui/qt/dialogs.py:3670 msgid "Reset" msgstr "" -#: bal/gui/qt/dialogs.py:3636 +#: bal/gui/qt/dialogs.py:3677 msgid "Review and Sign…" msgstr "" -#: bal/gui/qt/dialogs.py:3656 +#: bal/gui/qt/dialogs.py:3697 +#, python-brace-format msgid "The scanned code belongs to a different transfer ({} frames, {}). The import was reset; scan the first code again." msgstr "" -#: bal/gui/qt/dialogs.py:3746 +#: bal/gui/qt/dialogs.py:3787 +#, python-brace-format msgid "All {} frames stored." msgstr "" -#: bal/gui/qt/dialogs.py:3752 +#: bal/gui/qt/dialogs.py:3793 +#, python-brace-format msgid "Stored {} of {} frames." msgstr "" -#: bal/gui/qt/dialogs.py:3817 +#: bal/gui/qt/dialogs.py:3858 msgid "Cannot start QR scanner, no usable camera found." msgstr "" -#: bal/gui/qt/dialogs.py:3822 +#: bal/gui/qt/dialogs.py:3863 msgid "Stop scanning" msgstr "" -#: bal/gui/qt/dialogs.py:3869 +#: bal/gui/qt/dialogs.py:3910 +#, python-brace-format msgid "Camera error: {}" msgstr "" -#: bal/gui/qt/dialogs.py:3916 +#: bal/gui/qt/dialogs.py:3957 +#, python-brace-format msgid "The scanned code belongs to a different transfer ({} frames, {}). The import was reset; show the first code again." msgstr "" -#: bal/gui/qt/dialogs.py:3959 +#: bal/gui/qt/dialogs.py:4000 msgid "The transferred will contains no transactions." msgstr "" -#: bal/gui/qt/dialogs.py:3988 +#: bal/gui/qt/dialogs.py:4029 msgid "Review and sign imported will" msgstr "" -#: bal/gui/qt/dialogs.py:4001 +#: bal/gui/qt/dialogs.py:4042 msgid "Enter your wallet password to sign the imported transactions." msgstr "" -#: bal/gui/qt/dialogs.py:4047 +#: bal/gui/qt/dialogs.py:4088 msgid "Skip" msgstr "" -#: bal/gui/qt/dialogs.py:4063 +#: bal/gui/qt/dialogs.py:4104 msgid "Save signed file…" msgstr "" -#: bal/gui/qt/dialogs.py:4066 +#: bal/gui/qt/dialogs.py:4107 msgid "Show signed QR…" msgstr "" -#: bal/gui/qt/dialogs.py:4090 +#: bal/gui/qt/dialogs.py:4131 +#, python-brace-format msgid "Transaction {} of {}" msgstr "" -#: bal/gui/qt/dialogs.py:4092 +#: bal/gui/qt/dialogs.py:4133 +#, python-brace-format msgid "TXID: {}" msgstr "" -#: bal/gui/qt/dialogs.py:4095 +#: bal/gui/qt/dialogs.py:4136 msgid "unknown" msgstr "" -#: bal/gui/qt/dialogs.py:4101 +#: bal/gui/qt/dialogs.py:4142 msgid "(no outputs)" msgstr "" -#: bal/gui/qt/dialogs.py:4115 +#: bal/gui/qt/dialogs.py:4156 msgid "unknown (partial transaction)" msgstr "" -#: bal/gui/qt/dialogs.py:4117 +#: bal/gui/qt/dialogs.py:4158 +#, python-brace-format msgid "" "Total outputs: {}\n" "Fee: {}" msgstr "" -#: bal/gui/qt/dialogs.py:4128 +#: bal/gui/qt/dialogs.py:4170 +#, python-brace-format msgid "" "Signed {} of {} transactions.\n" "\n" "Save a signed file to carry to the broadcast device, or show the signed transactions as QR codes." msgstr "" -#: bal/gui/qt/dialogs.py:4147 +#: bal/gui/qt/dialogs.py:4188 +#, python-brace-format msgid "Could not sign the transaction: {}" msgstr "" -#: bal/gui/qt/dialogs.py:4166 +#: bal/gui/qt/dialogs.py:4207 msgid "Signed will saved." msgstr "" -#: bal/gui/qt/dialogs.py:4177 +#: bal/gui/qt/dialogs.py:4218 msgid "No signed transaction to show." msgstr "" @@ -952,7 +1014,8 @@ msgstr "" msgid "Name" msgstr "" -#: bal/gui/qt/lists.py:135 bal/gui/qt/lists.py:1432 bal/gui/qt/widgets.py:1420 bal/gui/qt/window.py:374 +#: bal/gui/qt/lists.py:135 bal/gui/qt/lists.py:1432 bal/gui/qt/widgets.py:1420 +#: bal/gui/qt/window.py:374 msgid "Address" msgstr "" @@ -961,10 +1024,12 @@ msgid "Amount" msgstr "" #: bal/gui/qt/lists.py:232 +#, python-brace-format msgid "Copy {}" msgstr "" #: bal/gui/qt/lists.py:240 bal/gui/qt/lists.py:1007 +#, python-brace-format msgid "Edit {}" msgstr "" @@ -1037,6 +1102,7 @@ msgid "Open transaction file" msgstr "" #: bal/gui/qt/lists.py:536 +#, python-brace-format msgid "Invalid transaction file: {}" msgstr "" @@ -1153,10 +1219,12 @@ msgid "Deselect only invalid" msgstr "" #: bal/gui/qt/lists.py:1288 bal/gui/qt/window.py:290 +#, python-brace-format msgid "Edit: {}" msgstr "" -#: bal/gui/qt/lists.py:1290 bal/gui/qt/lists.py:1302 bal/gui/qt/lists.py:1316 bal/gui/qt/lists.py:1476 +#: bal/gui/qt/lists.py:1290 bal/gui/qt/lists.py:1302 bal/gui/qt/lists.py:1316 +#: bal/gui/qt/lists.py:1476 msgid "New Will Executor" msgstr "" @@ -1165,10 +1233,12 @@ msgid "URL is required" msgstr "" #: bal/gui/qt/lists.py:1355 +#, python-brace-format msgid "Could not reach server at {}" msgstr "" #: bal/gui/qt/lists.py:1369 +#, python-brace-format msgid "Error contacting server: {}" msgstr "" @@ -1268,7 +1338,7 @@ msgstr "" msgid "Auto-sign on Check" msgstr "" -#: bal/gui/qt/plugin.py:702 +#: bal/gui/qt/plugin.py:705 msgid "" "When checking, automatically sign and broadcast the will transactions to their will-executors.\n" "The wallet password is requested only if the wallet is encrypted." @@ -1278,7 +1348,7 @@ msgstr "" msgid "Panel editable Date and Fee" msgstr "" -#: bal/gui/qt/plugin.py:720 +#: bal/gui/qt/plugin.py:723 msgid "" "When enabled, the delivery-time and check-alive date fields can be edited everywhere (toolbar / Heirs tab), not only in the will-building wizard.\n" "When disabled, those dates are display-only outside the wizard." @@ -1288,7 +1358,7 @@ msgstr "" msgid "Max Will-Executor Fee (satoshi)" msgstr "" -#: bal/gui/qt/plugin.py:735 +#: bal/gui/qt/plugin.py:738 msgid "" "Maximum fee (in satoshi) allowed to be paid to a single will-executor. If a will-executor charges more than this, the will will not be built.\n" "Default: 500,000 satoshi (0.005 BTC)." @@ -1298,7 +1368,7 @@ msgstr "" msgid "User Type" msgstr "" -#: bal/gui/qt/plugin.py:750 +#: bal/gui/qt/plugin.py:753 msgid "" "Choose how much detail the plugin shows.\n" "\n" @@ -1319,7 +1389,7 @@ msgstr "" msgid "Event summary" msgstr "" -#: bal/gui/qt/plugin.py:776 +#: bal/gui/qt/plugin.py:779 msgid "" "Default message to be used in event summary\n" "Variables:\n" @@ -1332,7 +1402,7 @@ msgstr "" msgid "Event description" msgstr "" -#: bal/gui/qt/plugin.py:790 +#: bal/gui/qt/plugin.py:793 msgid "" "Default message to be used in event description\n" "Variables:\n" @@ -1353,7 +1423,7 @@ msgstr "" msgid "Calendar app command" msgstr "" -#: bal/gui/qt/plugin.py:816 +#: bal/gui/qt/plugin.py:819 msgid "" "Command used to open .ics calendar files.\n" "Leave empty to use the system default (xdg-open/open/start).\n" @@ -1364,7 +1434,8 @@ msgstr "" msgid "Save inheritance transactions in history" msgstr "" -#: bal/gui/qt/plugin.py:831 +#: bal/gui/qt/plugin.py:834 +#, python-brace-format msgid "" "After each check, save the valid will transactions into the wallet's local history (the History tab), each with a label.\n" "The label may contain the variable:\n" @@ -1376,7 +1447,8 @@ msgstr "" msgid "History label" msgstr "" -#: bal/gui/qt/plugin.py:845 +#: bal/gui/qt/plugin.py:848 +#, python-brace-format msgid "" "Label applied to the will transactions saved into the wallet's local history.\n" "Variables:\n" @@ -1392,7 +1464,7 @@ msgstr "" msgid "Rebuild will on wallet close" msgstr "" -#: bal/gui/qt/plugin.py:878 +#: bal/gui/qt/plugin.py:881 msgid "" "Run the 'Build your will' wizard every time the wallet is closed or Electrum is quit, so the will is rebuilt and re-validated.\n" "When disabled, the will is only rebuilt when you press Check or Prepare. The last built state is still saved to the wallet." @@ -1402,7 +1474,7 @@ msgstr "" msgid "Rebuild automatically on new transactions" msgstr "" -#: bal/gui/qt/plugin.py:896 +#: bal/gui/qt/plugin.py:899 msgid "" "When a new transaction arrives for the wallet, automatically rebuild the will the same way the wizard does at wallet close: the delivery date is anticipated by one day so the new will replaces the previous one, and the rebuilt transactions are signed and sent to their will-executors.\n" "An on-chain invalidation transaction is only built when the anticipated delivery date would fall before the Check Alive threshold, or when the threshold is already in the past.\n" @@ -1413,7 +1485,7 @@ msgstr "" msgid "Invalidation fee policy" msgstr "" -#: bal/gui/qt/plugin.py:966 +#: bal/gui/qt/plugin.py:972 msgid "" "Fee rate the on-chain invalidation transaction pays.\n" "The invalidation is sent TODAY (it spends the will's coins so the old inheritance transactions become unusable), so it should pay the current network fee - not the will's mining fee rate.\n" @@ -1441,6 +1513,7 @@ msgid "Support:" msgstr "" #: bal/gui/qt/plugin.py:1131 +#, python-brace-format msgid "BAL - {}" msgstr "" @@ -1486,7 +1559,7 @@ msgstr "" msgid "Miner fee, click for more information" msgstr "" -#: bal/gui/qt/widgets.py:213 +#: bal/gui/qt/widgets.py:214 msgid "" "if you choose Raw, you can insert various options based on suffix:\n" " - d: number of days after current day(ex: 1d means tomorrow)\n" @@ -1521,19 +1594,20 @@ msgstr "" msgid "Export reminder dates to your calendar (.ics)" msgstr "" -#: bal/gui/qt/widgets.py:854 +#: bal/gui/qt/widgets.py:855 msgid "" "Enter the date on which you want the inheritance (or backup)\n" "of your Electrum wallet to take effect." msgstr "" -#: bal/gui/qt/widgets.py:885 +#: bal/gui/qt/widgets.py:886 msgid "" "Please note: Do not reduce the miner fees\n" "unless you know what you’re doing" msgstr "" #: bal/gui/qt/widgets.py:1235 +#, python-brace-format msgid "{} or perc value" msgstr "" @@ -1605,10 +1679,6 @@ msgstr "" msgid "Heirs are not defined" msgstr "" -#: bal/gui/qt/window.py:841 -msgid "In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts.{}" -msgstr "" - #: bal/gui/qt/window.py:859 msgid "CheckAlive is in the past please update it to a date in the future but less than locktime" msgstr "" @@ -1621,7 +1691,7 @@ msgstr "" msgid " no backup transaction or willexecutor selected" msgstr "" -#: bal/gui/qt/window.py:917 +#: bal/gui/qt/window.py:918 msgid "" "This inheritance was already signed/sent to will-executors and you are postponing it.\n" "\n" @@ -1646,7 +1716,7 @@ msgstr "" msgid "Txfees are changed" msgstr "" -#: bal/gui/qt/window.py:952 +#: bal/gui/qt/window.py:953 msgid "" "Found CHANGES to the DATE or the HEIRS,\n" "a NEW WILL must be prepared." @@ -1657,6 +1727,7 @@ msgid "will have to be built" msgstr "" #: bal/gui/qt/window.py:979 +#, python-brace-format msgid "" "Error:{}\n" " {}" @@ -1666,7 +1737,7 @@ msgstr "" msgid "Please, check your heirs, locktime and threshold!" msgstr "" -#: bal/gui/qt/window.py:995 +#: bal/gui/qt/window.py:996 msgid "" "Your inheritance has been rebuilt and now needs to be signed again.\n" "\n" @@ -1674,7 +1745,7 @@ msgid "" " 1. Press 'Sign' to sign the new transaction." msgstr "" -#: bal/gui/qt/window.py:1002 +#: bal/gui/qt/window.py:1003 msgid "" "Your inheritance has been rebuilt and now needs to be signed and re-sent to the will-executors.\n" "\n" @@ -1704,10 +1775,12 @@ msgid "Calculating Transactions" msgstr "" #: bal/gui/qt/window.py:1110 +#, python-brace-format msgid "signed: {}" msgstr "" #: bal/gui/qt/window.py:1111 +#, python-brace-format msgid "signing: {}" msgstr "" @@ -1740,14 +1813,18 @@ msgid "checking..." msgstr "" #: bal/gui/qt/window.py:1694 +#, python-brace-format msgid "checking {} - {} : {}" msgstr "" #: bal/gui/qt/window.py:1703 +#, python-brace-format msgid "checked {} - {} : {}" msgstr "" -#: bal/gui/qt/window.py:1899 bal/gui/qt/window.py:1937 bal/gui/qt/window.py:1961 +#: bal/gui/qt/window.py:1899 bal/gui/qt/window.py:1937 +#: bal/gui/qt/window.py:1961 +#, python-brace-format msgid "Invalid will file: {}" msgstr "" @@ -1763,14 +1840,14 @@ msgstr "" msgid "Check Transaction" msgstr "" -#: bal/gui/qt/window.py:2172 +#: bal/gui/qt/window.py:2173 msgid "" "Could not download the will-executors list.\n" "\n" "This is usually caused by your internet connection or a firewall, not by the plugin. Please check your connection (a VPN often helps) and try again." msgstr "" -#: bal/gui/qt/window.py:2182 +#: bal/gui/qt/window.py:2183 msgid "" "Could not download the will-executors list over Tor.\n" "\n" @@ -1781,14 +1858,16 @@ msgstr "" msgid "Downloading will-executors list..." msgstr "" -#: bal/gui/qt/window.py:2254 +#: bal/gui/qt/window.py:2255 +#, python-brace-format msgid "" "No active will-executor servers found for the {chain} network.\n" "\n" "The welist server at {url} responded but returned no will-executors for this chain." msgstr "" -#: bal/gui/qt/window.py:2262 +#: bal/gui/qt/window.py:2263 +#, python-brace-format msgid "" "Could not reach the configured welist server.\n" "\n" @@ -1799,6 +1878,7 @@ msgid "" msgstr "" #: bal/gui/qt/window.py:2273 +#, python-brace-format msgid "No active will-executor found for the {chain} network." msgstr "" diff --git a/bal/locale/es_ES/LC_MESSAGES/bal.po b/bal/locale/es_ES/LC_MESSAGES/bal.po index 8e4855e..5a3e34b 100644 --- a/bal/locale/es_ES/LC_MESSAGES/bal.po +++ b/bal/locale/es_ES/LC_MESSAGES/bal.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: BAL Electrum plugin VERSION\n" "Report-Msgid-Bugs-To: info@bitcoin-after.life\n" -"POT-Creation-Date: 2026-10-10 15:53-0400\n" +"POT-Creation-Date: 2026-10-15 16:08-0400\n" "PO-Revision-Date: 2026-10-03 11:40-0400\n" "Last-Translator: FULL NAME \n" "Language: es_ES\n" @@ -16,7 +16,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: bal/core/plugin_base.py:378 msgid "" @@ -32,88 +32,88 @@ msgstr "" msgid "BAL -Will execution of $wallet_name" msgstr "BAL - Ejecución del testamento de $wallet_name" -#: bal/core/will.py:1502 +#: bal/core/will.py:1525 #, python-brace-format msgid "NOT {}" msgstr "NO {}" -#: bal/core/will.py:1526 +#: bal/core/will.py:1549 msgid "Anticipated" msgstr "Anticipado" -#: bal/core/will.py:1527 +#: bal/core/will.py:1550 msgid "Broadcasted" msgstr "Transmitido" -#: bal/core/will.py:1528 +#: bal/core/will.py:1551 msgid "Checked" msgstr "Comprobado" -#: bal/core/will.py:1529 +#: bal/core/will.py:1552 msgid "Check Failed" msgstr "Comprobación fallida" -#: bal/core/will.py:1530 +#: bal/core/will.py:1553 msgid "Signed" msgstr "Firmado" -#: bal/core/will.py:1531 +#: bal/core/will.py:1554 msgid "Confirmed" msgstr "Confirmado" -#: bal/core/will.py:1532 bal/gui/qt/lists.py:1354 bal/gui/qt/lists.py:1368 +#: bal/core/will.py:1555 bal/gui/qt/lists.py:1354 bal/gui/qt/lists.py:1368 msgid "Error" msgstr "Error" -#: bal/core/will.py:1533 bal/gui/qt/dialogs.py:826 +#: bal/core/will.py:1556 bal/gui/qt/dialogs.py:846 msgid "Expired" msgstr "Caducado" -#: bal/core/will.py:1534 +#: bal/core/will.py:1557 msgid "Exported" msgstr "Exportado" -#: bal/core/will.py:1535 +#: bal/core/will.py:1558 msgid "Imported" msgstr "Importado" -#: bal/core/will.py:1536 +#: bal/core/will.py:1559 msgid "Invalidated" msgstr "Invalidado" -#: bal/core/will.py:1537 +#: bal/core/will.py:1560 msgid "Mempool" msgstr "Mempool" -#: bal/core/will.py:1538 +#: bal/core/will.py:1561 msgid "Push failed" msgstr "Envío fallido" -#: bal/core/will.py:1539 +#: bal/core/will.py:1562 msgid "Pushed" msgstr "Enviado" -#: bal/core/will.py:1540 +#: bal/core/will.py:1563 msgid "Partially Signed" msgstr "Firmado parcialmente" -#: bal/core/will.py:1541 +#: bal/core/will.py:1564 msgid "Replaced" msgstr "Sustituido" -#: bal/core/will.py:1542 +#: bal/core/will.py:1565 msgid "Restored" msgstr "Restaurado" -#: bal/core/will.py:1543 +#: bal/core/will.py:1566 msgid "Updated" msgstr "Actualizado" -#: bal/core/will.py:1544 bal/gui/qt/dialogs.py:2635 +#: bal/core/will.py:1567 bal/gui/qt/dialogs.py:2676 msgid "Valid" msgstr "Válido" -#: bal/core/will.py:1550 +#: bal/core/will.py:1573 msgid "New" msgstr "Nuevo" @@ -121,7 +121,8 @@ msgstr "Nuevo" msgid "Waiting..." msgstr "Esperando..." -#: bal/core/willexecutors.py:394 bal/gui/qt/window.py:245 bal/gui/qt/window.py:1667 +#: bal/core/willexecutors.py:394 bal/gui/qt/window.py:245 +#: bal/gui/qt/window.py:1667 msgid "Success" msgstr "Completado" @@ -206,15 +207,15 @@ msgstr "Sus {0} se exportaron a '{1}'" msgid "Bal Wizard Setup" msgstr "Configuración del asistente de BAL" -#: bal/gui/qt/dialogs.py:325 bal/gui/qt/dialogs.py:2764 +#: bal/gui/qt/dialogs.py:325 bal/gui/qt/dialogs.py:2805 msgid "Previous" msgstr "Anterior" -#: bal/gui/qt/dialogs.py:329 bal/gui/qt/dialogs.py:2767 +#: bal/gui/qt/dialogs.py:329 bal/gui/qt/dialogs.py:2808 msgid "Next" msgstr "Siguiente" -#: bal/gui/qt/dialogs.py:333 bal/gui/qt/dialogs.py:4050 +#: bal/gui/qt/dialogs.py:333 bal/gui/qt/dialogs.py:4091 msgid "Cancel" msgstr "Cancelar" @@ -222,7 +223,7 @@ msgstr "Cancelar" msgid "Bitcoin After Life Heirs" msgstr "Bitcoin After Life - Herederos" -#: bal/gui/qt/dialogs.py:360 +#: bal/gui/qt/dialogs.py:361 msgid "" "Please add your heirs\n" " remember that the wallet balance will be spent at 100%" @@ -234,11 +235,14 @@ msgstr "" msgid "Add" msgstr "Añadir" -#: bal/gui/qt/dialogs.py:372 bal/gui/qt/dialogs.py:2596 bal/gui/qt/lists.py:311 bal/gui/qt/lists.py:673 bal/gui/qt/lists.py:1237 +#: bal/gui/qt/dialogs.py:372 bal/gui/qt/dialogs.py:2637 bal/gui/qt/lists.py:311 +#: bal/gui/qt/lists.py:673 bal/gui/qt/lists.py:1237 msgid "Import" msgstr "Importar" -#: bal/gui/qt/dialogs.py:374 bal/gui/qt/dialogs.py:2432 bal/gui/qt/dialogs.py:2600 bal/gui/qt/lists.py:312 bal/gui/qt/lists.py:672 bal/gui/qt/lists.py:1249 +#: bal/gui/qt/dialogs.py:374 bal/gui/qt/dialogs.py:2473 +#: bal/gui/qt/dialogs.py:2641 bal/gui/qt/lists.py:312 bal/gui/qt/lists.py:672 +#: bal/gui/qt/lists.py:1249 msgid "Export" msgstr "Exportar" @@ -290,127 +294,137 @@ msgstr "Creación del testamento" msgid "Building Will:" msgstr "Creación del testamento:" -#: bal/gui/qt/dialogs.py:731 bal/gui/qt/dialogs.py:757 bal/gui/qt/dialogs.py:767 bal/gui/qt/dialogs.py:790 +#: bal/gui/qt/dialogs.py:737 bal/gui/qt/dialogs.py:763 +#: bal/gui/qt/dialogs.py:773 bal/gui/qt/dialogs.py:796 +#: bal/gui/qt/dialogs.py:807 bal/gui/qt/dialogs.py:820 msgid "Checking variables" msgstr "Comprobando variables" -#: bal/gui/qt/dialogs.py:758 +#: bal/gui/qt/dialogs.py:764 msgid "Check Alive Threshold Passed: you have to Invalidate your old Will" msgstr "El umbral de verificación de vida se ha superado: debes invalidar tu antiguo testamento" -#: bal/gui/qt/dialogs.py:767 bal/gui/qt/dialogs.py:850 +#: bal/gui/qt/dialogs.py:773 bal/gui/qt/dialogs.py:870 msgid "No Heirs" msgstr "Sin herederos" -#: bal/gui/qt/dialogs.py:790 bal/gui/qt/dialogs.py:1338 bal/gui/qt/dialogs.py:2284 bal/gui/qt/window.py:2319 +#: bal/gui/qt/dialogs.py:796 bal/gui/qt/dialogs.py:1380 +#: bal/gui/qt/dialogs.py:2325 bal/gui/qt/window.py:2319 msgid "Ok" msgstr "Hecho" -#: bal/gui/qt/dialogs.py:794 -msgid "" -"In the inheritance process, the entire wallet will always be fully emptied. \n" -"Your settings require an adjustment of the amounts" -msgstr "" -"En el proceso de herencia, la cartera siempre se vaciará por completo. \n" -"Tu configuración requiere un ajuste de los importes" +#: bal/gui/qt/dialogs.py:810 bal/gui/qt/window.py:841 +msgid "In the inheritance process, the entire wallet will always be fully emptied." +msgstr "En el proceso de herencia, la cartera siempre se vaciará por completo." -#: bal/gui/qt/dialogs.py:803 bal/gui/qt/window.py:846 +#: bal/gui/qt/dialogs.py:822 bal/gui/qt/window.py:846 #, python-brace-format msgid "Will-executor fee too high: {}" msgstr "Comisión del Will-Executor demasiado alta: {}" -#: bal/gui/qt/dialogs.py:837 +#: bal/gui/qt/dialogs.py:857 msgid "Postponed: invalidating old will" msgstr "Aplazado: invalidando el antiguo testamento" -#: bal/gui/qt/dialogs.py:873 bal/gui/qt/dialogs.py:882 bal/gui/qt/dialogs.py:2244 +#: bal/gui/qt/dialogs.py:893 bal/gui/qt/dialogs.py:902 +#: bal/gui/qt/dialogs.py:2285 msgid "Checking your will" msgstr "Comprobando tu testamento" -#: bal/gui/qt/dialogs.py:875 +#: bal/gui/qt/dialogs.py:895 msgid "An inheritance of this wallet is already executed (on blockchain)" msgstr "Una herencia de esta cartera ya se ha ejecutado (en la blockchain)" -#: bal/gui/qt/dialogs.py:884 +#: bal/gui/qt/dialogs.py:904 msgid "Inheritance in mempool (waiting confirmation)" msgstr "Herencia en la mempool (esperando confirmación)" -#: bal/gui/qt/dialogs.py:917 +#: bal/gui/qt/dialogs.py:937 msgid "Will-Executor excluded" msgstr "Will-Executor excluido" -#: bal/gui/qt/dialogs.py:917 bal/gui/qt/dialogs.py:1011 bal/gui/qt/dialogs.py:2225 bal/gui/qt/dialogs.py:2236 +#: bal/gui/qt/dialogs.py:937 bal/gui/qt/dialogs.py:1031 +#: bal/gui/qt/dialogs.py:2266 bal/gui/qt/dialogs.py:2277 msgid "Skipped" msgstr "Omitido" -#: bal/gui/qt/dialogs.py:923 bal/gui/qt/dialogs.py:1708 bal/gui/qt/lists.py:345 bal/gui/qt/theme.py:116 +#: bal/gui/qt/dialogs.py:943 bal/gui/qt/dialogs.py:1749 bal/gui/qt/lists.py:345 +#: bal/gui/qt/theme.py:116 msgid "Will-Executor" msgstr "Will-Executor" -#: bal/gui/qt/dialogs.py:924 +#: bal/gui/qt/dialogs.py:944 msgid "Not present - select one or enable backup mode" msgstr "No presente - selecciona uno o activa el modo de copia de seguridad" -#: bal/gui/qt/dialogs.py:986 +#: bal/gui/qt/dialogs.py:1006 msgid "All heirs' shares are below the dust limit: the inheritance cannot be created. Increase the amounts or reduce the number of heirs." msgstr "Todas las partes de los herederos están por debajo del límite de polvo (dust): no se puede crear la herencia. Aumenta los importes o reduce el número de herederos." -#: bal/gui/qt/dialogs.py:1002 +#: bal/gui/qt/dialogs.py:1022 #, python-brace-format msgid "Wallet balance is too low: {} satoshi available, but the miner and will-executor fees need {} satoshi (the minimum usable amount is {} satoshi). Add funds, or select fewer will-executors." msgstr "El saldo de la cartera es demasiado bajo: {} satoshis disponibles, pero las comisiones de minería y del Will-Executor necesitan {} satoshis (el importe mínimo utilizable es {} satoshis). Añade fondos o selecciona menos Will-Executor." -#: bal/gui/qt/dialogs.py:1045 +#: bal/gui/qt/dialogs.py:1065 #, python-brace-format msgid "Heir {}" msgstr "Heredero {}" -#: bal/gui/qt/dialogs.py:1047 +#: bal/gui/qt/dialogs.py:1067 #, python-brace-format msgid "{} is DUST - excluded (amount below dust limit)" msgstr "{} es POLVO (dust) - excluido (importe por debajo del límite de polvo)" -#: bal/gui/qt/dialogs.py:1103 +#: bal/gui/qt/dialogs.py:1120 +#, python-brace-format +msgid "Anticipated - new delivery date: {}" +msgstr "Anticipada - nueva fecha de entrega: {}" + +#: bal/gui/qt/dialogs.py:1139 msgid "Heir" msgstr "Heredero" -#: bal/gui/qt/dialogs.py:1220 bal/gui/qt/dialogs.py:2273 +#: bal/gui/qt/dialogs.py:1262 bal/gui/qt/dialogs.py:2314 #, python-brace-format msgid "Please wait {}secs" msgstr "Espera {} segundos" -#: bal/gui/qt/dialogs.py:1227 bal/gui/qt/dialogs.py:1279 bal/gui/qt/dialogs.py:1317 +#: bal/gui/qt/dialogs.py:1269 bal/gui/qt/dialogs.py:1321 +#: bal/gui/qt/dialogs.py:1359 msgid "Broadcasting" msgstr "Transmitiendo" -#: bal/gui/qt/dialogs.py:1338 bal/gui/qt/window.py:2321 +#: bal/gui/qt/dialogs.py:1380 bal/gui/qt/window.py:2321 msgid "Ko" msgstr "Error" -#: bal/gui/qt/dialogs.py:1349 +#: bal/gui/qt/dialogs.py:1391 msgid "Timeout - no answer" msgstr "Tiempo agotado - sin respuesta" -#: bal/gui/qt/dialogs.py:1391 +#: bal/gui/qt/dialogs.py:1433 #, python-brace-format msgid "checking {} - {}" msgstr "comprobando {} - {}" -#: bal/gui/qt/dialogs.py:1394 bal/gui/qt/dialogs.py:2242 bal/gui/qt/window.py:1695 +#: bal/gui/qt/dialogs.py:1436 bal/gui/qt/dialogs.py:2283 +#: bal/gui/qt/window.py:1695 msgid "Waiting" msgstr "Esperando" -#: bal/gui/qt/dialogs.py:1408 +#: bal/gui/qt/dialogs.py:1450 #, python-brace-format msgid "checked {} - {}" msgstr "comprobado {} - {}" -#: bal/gui/qt/dialogs.py:1458 bal/gui/qt/dialogs.py:2028 bal/gui/qt/dialogs.py:2039 +#: bal/gui/qt/dialogs.py:1500 bal/gui/qt/dialogs.py:2069 +#: bal/gui/qt/dialogs.py:2080 #, python-brace-format msgid "Error: {}" msgstr "Error: {}" -#: bal/gui/qt/dialogs.py:1519 +#: bal/gui/qt/dialogs.py:1562 msgid "" "Your will has expired and must be invalidated before it can be rebuilt.\n" "A transaction window will now open:\n" @@ -422,11 +436,11 @@ msgstr "" "firma la transacción y luego TRANSMÍTELA para invalidar tu antiguo testamento.\n" "Cuando se confirme la invalidación, pulsa el botón Comprobar para terminar el testamento." -#: bal/gui/qt/dialogs.py:1549 bal/gui/qt/window.py:852 +#: bal/gui/qt/dialogs.py:1591 bal/gui/qt/window.py:852 msgid "Check Alive must be after today and before the delivery date, please update it" msgstr "La fecha de verificación de vida debe ser posterior a hoy y anterior a la fecha de entrega: actualízala" -#: bal/gui/qt/dialogs.py:1571 +#: bal/gui/qt/dialogs.py:1614 msgid "" "Your old will has been invalidated and the transaction was broadcast.\n" "Electrum may need a little time to register it.\n" @@ -436,19 +450,19 @@ msgstr "" "Electrum puede tardar un poco en registrarla.\n" "Espera a que se confirme la transacción de invalidación y vuelve a pulsar el botón Comprobar para terminar de actualizar tu testamento." -#: bal/gui/qt/dialogs.py:1587 +#: bal/gui/qt/dialogs.py:1629 msgid "Invalidate your old will" msgstr "Invalida tu antiguo testamento" -#: bal/gui/qt/dialogs.py:1601 bal/gui/qt/dialogs.py:1646 +#: bal/gui/qt/dialogs.py:1643 bal/gui/qt/dialogs.py:1687 msgid "Aborted" msgstr "Abortado" -#: bal/gui/qt/dialogs.py:1620 +#: bal/gui/qt/dialogs.py:1662 msgid "Auto-sign disabled — sign manually" msgstr "Firma automática desactivada — firma manualmente" -#: bal/gui/qt/dialogs.py:1633 +#: bal/gui/qt/dialogs.py:1676 msgid "" "The delivery date was automatically moved one day earlier so the updated will can correctly replace the previous one.\n" "Please sign (and broadcast) to confirm the change." @@ -456,131 +470,134 @@ msgstr "" "La fecha de entrega se ha adelantado automáticamente un día para que el testamento actualizado pueda sustituir correctamente al anterior.\n" "Firma (y transmite) para confirmar el cambio." -#: bal/gui/qt/dialogs.py:1643 +#: bal/gui/qt/dialogs.py:1684 msgid "Sign your will" msgstr "Firma tu testamento" -#: bal/gui/qt/dialogs.py:1648 bal/gui/qt/dialogs.py:1931 +#: bal/gui/qt/dialogs.py:1689 bal/gui/qt/dialogs.py:1972 msgid "Nothing to do" msgstr "Nada que hacer" -#: bal/gui/qt/dialogs.py:1667 +#: bal/gui/qt/dialogs.py:1708 msgid "Finished" msgstr "Terminado" -#: bal/gui/qt/dialogs.py:1684 +#: bal/gui/qt/dialogs.py:1725 msgid "Calendar" msgstr "Calendario" -#: bal/gui/qt/dialogs.py:1686 bal/gui/qt/dialogs.py:1716 bal/gui/qt/dialogs.py:1783 bal/gui/qt/dialogs.py:2031 bal/gui/qt/dialogs.py:2978 bal/gui/qt/dialogs.py:3233 bal/gui/qt/dialogs.py:4069 +#: bal/gui/qt/dialogs.py:1727 bal/gui/qt/dialogs.py:1757 +#: bal/gui/qt/dialogs.py:1824 bal/gui/qt/dialogs.py:2072 +#: bal/gui/qt/dialogs.py:3019 bal/gui/qt/dialogs.py:3274 +#: bal/gui/qt/dialogs.py:4110 msgid "Close" msgstr "Cerrar" -#: bal/gui/qt/dialogs.py:1712 bal/gui/qt/dialogs.py:1779 +#: bal/gui/qt/dialogs.py:1753 bal/gui/qt/dialogs.py:1820 msgid "🔮 Wizard" msgstr "🔮 Asistente" -#: bal/gui/qt/dialogs.py:1775 bal/gui/qt/dialogs.py:2583 +#: bal/gui/qt/dialogs.py:1816 bal/gui/qt/dialogs.py:2624 msgid "Heirs" msgstr "Herederos" -#: bal/gui/qt/dialogs.py:1884 bal/gui/qt/widgets.py:1150 +#: bal/gui/qt/dialogs.py:1925 bal/gui/qt/widgets.py:1150 #, python-brace-format msgid "(reminder {idx}/{total})" msgstr "(recordatorio {idx}/{total})" -#: bal/gui/qt/dialogs.py:1948 +#: bal/gui/qt/dialogs.py:1989 msgid "All done" msgstr "Todo listo" -#: bal/gui/qt/dialogs.py:2000 +#: bal/gui/qt/dialogs.py:2041 msgid "Next steps (manual): press 'Sign' to sign your will, then 'Broadcast' to send it to the will-executors." msgstr "Siguientes pasos (manual): pulsa 'Firmar' para firmar tu testamento y luego 'Transmitir' para enviarlo a los Will-Executor." -#: bal/gui/qt/dialogs.py:2005 +#: bal/gui/qt/dialogs.py:2046 msgid "Next step (manual): press 'Sign' to sign your will." msgstr "Siguiente paso (manual): pulsa 'Firmar' para firmar tu testamento." -#: bal/gui/qt/dialogs.py:2009 +#: bal/gui/qt/dialogs.py:2050 msgid "Next step (manual): press 'Broadcast' to send your will to the will-executors." msgstr "Siguiente paso (manual): pulsa 'Transmitir' para enviar tu testamento a los Will-Executor." -#: bal/gui/qt/dialogs.py:2104 +#: bal/gui/qt/dialogs.py:2145 #, python-brace-format msgid "Miner fee rate changed (the will was built with {} sat/byte, now it is {}): a new will must be prepared." msgstr "La tasa de comisión de minería ha cambiado (el testamento se creó con {} sat/byte, ahora es {}): hay que preparar un nuevo testamento." -#: bal/gui/qt/dialogs.py:2109 +#: bal/gui/qt/dialogs.py:2150 msgid "The miner fee rate changed: a new will must be prepared." msgstr "La tasa de comisión de minería ha cambiado: hay que preparar un nuevo testamento." -#: bal/gui/qt/dialogs.py:2112 +#: bal/gui/qt/dialogs.py:2154 #, python-brace-format msgid "Will-executor \"{}\" is not covered by the current will: a new will must be prepared." msgstr "El Will-Executor \"{}\" no está cubierto por el testamento actual: hay que preparar un nuevo testamento." -#: bal/gui/qt/dialogs.py:2118 +#: bal/gui/qt/dialogs.py:2159 msgid "Backup mode is enabled but the will has no backup transaction: a new will must be prepared." msgstr "El modo de copia de seguridad está activado pero el testamento no tiene transacción de copia de seguridad: hay que preparar un nuevo testamento." -#: bal/gui/qt/dialogs.py:2126 +#: bal/gui/qt/dialogs.py:2168 #, python-brace-format msgid "Heir \"{}\" is not covered by the current will (it was added or removed, or its delivery date changed): a new will must be prepared." msgstr "El heredero \"{}\" no está cubierto por el testamento actual (se añadió o se eliminó, o cambió su fecha de entrega): hay que preparar un nuevo testamento." -#: bal/gui/qt/dialogs.py:2135 +#: bal/gui/qt/dialogs.py:2176 msgid "The heirs changed: a new will must be prepared." msgstr "Los herederos han cambiado: hay que preparar un nuevo testamento." -#: bal/gui/qt/dialogs.py:2137 +#: bal/gui/qt/dialogs.py:2178 msgid "A will-executor changed: a new will must be prepared." msgstr "Un Will-Executor ha cambiado: hay que preparar un nuevo testamento." -#: bal/gui/qt/dialogs.py:2147 +#: bal/gui/qt/dialogs.py:2188 msgid "The wallet contains funds that the current will does not cover yet: a new will must be prepared." msgstr "La cartera contiene fondos que el testamento actual aún no cubre: hay que preparar un nuevo testamento." -#: bal/gui/qt/dialogs.py:2151 +#: bal/gui/qt/dialogs.py:2192 msgid "The will contains no valid transaction: a new will must be prepared." msgstr "El testamento no contiene ninguna transacción válida: hay que preparar un nuevo testamento." -#: bal/gui/qt/dialogs.py:2157 +#: bal/gui/qt/dialogs.py:2198 msgid "The will is no longer coherent and must be rebuilt; the exact reason could not be determined." msgstr "El testamento ya no es coherente y debe recrearse; no se pudo determinar el motivo exacto." -#: bal/gui/qt/dialogs.py:2187 +#: bal/gui/qt/dialogs.py:2228 msgid "No heirs: add at least one heir before building the will." msgstr "Sin herederos: añade al menos un heredero antes de crear el testamento." -#: bal/gui/qt/dialogs.py:2190 +#: bal/gui/qt/dialogs.py:2231 msgid "The wallet has no spendable funds, so no inheritance transaction can be created." msgstr "La cartera no tiene fondos gastables, por lo que no se puede crear ninguna transacción de herencia." -#: bal/gui/qt/dialogs.py:2194 +#: bal/gui/qt/dialogs.py:2235 msgid "No usable will-executor: none of the servers in the list is both selected and valid. Open the will-executor settings, select at least one server and check that it is reachable." msgstr "No hay ningún Will-Executor utilizable: ninguno de los servidores de la lista está a la vez seleccionado y es válido. Abre la configuración de los Will-Executor, selecciona al menos un servidor y comprueba que es accesible." -#: bal/gui/qt/dialogs.py:2199 +#: bal/gui/qt/dialogs.py:2240 msgid "No delivery date left to build: every heir's date is already covered by the existing will. Choose a later delivery date, or change an heir's date." msgstr "No queda ninguna fecha de entrega para crear: la fecha de cada heredero ya está cubierta por el testamento existente. Elige una fecha de entrega posterior o cambia la fecha de un heredero." -#: bal/gui/qt/dialogs.py:2204 +#: bal/gui/qt/dialogs.py:2245 msgid "The amount to send must cover the miner fees plus this will-executor's fee, and the wallet balance is not enough: select cheaper will-executors, or add funds to the wallet." msgstr "El importe a enviar debe cubrir las comisiones de minería más la comisión de este Will-Executor, y el saldo de la cartera no es suficiente: selecciona Will-Executor más baratos o añade fondos a la cartera." -#: bal/gui/qt/dialogs.py:2209 +#: bal/gui/qt/dialogs.py:2250 msgid "A will-executor asks for more than the maximum fee you allowed: raise the maximum fee in the settings, or select a cheaper will-executor." msgstr "Un Will-Executor pide más que la comisión máxima que permitiste: sube la comisión máxima en la configuración o selecciona un Will-Executor más barato." -#: bal/gui/qt/dialogs.py:2214 +#: bal/gui/qt/dialogs.py:2255 msgid "The inheritance transactions could not be assembled from the available funds (the balance may not cover the miner fees)." msgstr "No se pudieron componer las transacciones de herencia con los fondos disponibles (el saldo puede no cubrir las comisiones de minería)." -#: bal/gui/qt/dialogs.py:2218 +#: bal/gui/qt/dialogs.py:2259 msgid "An unexpected error stopped the transactions being prepared for a will-executor, so it was skipped. Try again, or select a different will-executor." msgstr "Un error inesperado detuvo la preparación de las transacciones para un Will-Executor, así que se omitió. Inténtalo de nuevo o selecciona otro Will-Executor." -#: bal/gui/qt/dialogs.py:2228 +#: bal/gui/qt/dialogs.py:2270 msgid "" "Could not build the will, and the exact cause could not be determined. Please check that:\n" "- the wallet balance covers the miner and will-executor fees,\n" @@ -594,126 +611,127 @@ msgstr "" "- la fecha de verificación de vida es ANTERIOR a la fecha de entrega,\n" "- hay al menos un Will-Executor seleccionado y accesible." -#: bal/gui/qt/dialogs.py:2249 +#: bal/gui/qt/dialogs.py:2290 msgid "Invalidating old will" msgstr "Invalidando el antiguo testamento" -#: bal/gui/qt/dialogs.py:2255 +#: bal/gui/qt/dialogs.py:2296 msgid "Building your will" msgstr "Creando tu testamento" -#: bal/gui/qt/dialogs.py:2261 +#: bal/gui/qt/dialogs.py:2302 msgid "Signing your will" msgstr "Firmando tu testamento" -#: bal/gui/qt/dialogs.py:2267 +#: bal/gui/qt/dialogs.py:2308 msgid "Broadcasting your will to executors" msgstr "Transmitiendo tu testamento a los ejecutores" -#: bal/gui/qt/dialogs.py:2315 +#: bal/gui/qt/dialogs.py:2356 msgid "Wait" msgstr "Espera" -#: bal/gui/qt/dialogs.py:2418 +#: bal/gui/qt/dialogs.py:2459 msgid "Will Details" msgstr "Detalles del testamento" -#: bal/gui/qt/dialogs.py:2424 bal/gui/qt/dialogs.py:4044 bal/gui/qt/lists.py:668 +#: bal/gui/qt/dialogs.py:2465 bal/gui/qt/dialogs.py:4085 +#: bal/gui/qt/lists.py:668 msgid "Sign" msgstr "Firmar" -#: bal/gui/qt/dialogs.py:2428 bal/gui/qt/lists.py:675 +#: bal/gui/qt/dialogs.py:2469 bal/gui/qt/lists.py:675 msgid "Broadcast" msgstr "Transmitir" -#: bal/gui/qt/dialogs.py:2435 bal/gui/qt/lists.py:677 +#: bal/gui/qt/dialogs.py:2476 bal/gui/qt/lists.py:677 msgid "Invalidate" msgstr "Invalidar" -#: bal/gui/qt/dialogs.py:2440 bal/gui/qt/lists.py:674 +#: bal/gui/qt/dialogs.py:2481 bal/gui/qt/lists.py:674 msgid "Merge" msgstr "Combinar" -#: bal/gui/qt/dialogs.py:2448 +#: bal/gui/qt/dialogs.py:2489 #, python-brace-format msgid "Expiration date: {}" msgstr "Fecha de caducidad: {}" -#: bal/gui/qt/dialogs.py:2454 +#: bal/gui/qt/dialogs.py:2495 #, python-brace-format msgid "Valid Txs:{}" msgstr "Transacciones válidas: {}" -#: bal/gui/qt/dialogs.py:2456 +#: bal/gui/qt/dialogs.py:2497 #, python-brace-format msgid "Total Txs:{}" msgstr "Transacciones totales: {}" -#: bal/gui/qt/dialogs.py:2510 +#: bal/gui/qt/dialogs.py:2551 msgid "Hide replaced" msgstr "Ocultar sustituidas" -#: bal/gui/qt/dialogs.py:2512 +#: bal/gui/qt/dialogs.py:2553 msgid "Unhide replaced" msgstr "Mostrar sustituidas" -#: bal/gui/qt/dialogs.py:2518 +#: bal/gui/qt/dialogs.py:2559 msgid "Hide invalidated" msgstr "Ocultar invalidadas" -#: bal/gui/qt/dialogs.py:2520 +#: bal/gui/qt/dialogs.py:2561 msgid "Unhide invalidated" msgstr "Mostrar invalidadas" -#: bal/gui/qt/dialogs.py:2545 +#: bal/gui/qt/dialogs.py:2586 msgid "Will-Executor Service List" msgstr "Lista de servicios Will-Executor" -#: bal/gui/qt/dialogs.py:2592 bal/gui/qt/lists.py:314 +#: bal/gui/qt/dialogs.py:2633 bal/gui/qt/lists.py:314 msgid "New Heir" msgstr "Nuevo heredero" -#: bal/gui/qt/dialogs.py:2634 +#: bal/gui/qt/dialogs.py:2675 msgid "All" msgstr "Todo" -#: bal/gui/qt/dialogs.py:2637 +#: bal/gui/qt/dialogs.py:2678 msgid "Valid NC" msgstr "Válido NC" -#: bal/gui/qt/dialogs.py:2775 bal/gui/qt/dialogs.py:2853 +#: bal/gui/qt/dialogs.py:2816 bal/gui/qt/dialogs.py:2894 msgid "Auto" msgstr "Automático" -#: bal/gui/qt/dialogs.py:2777 +#: bal/gui/qt/dialogs.py:2818 msgid "Automatically advance through the QR codes." msgstr "Avanza automáticamente por los códigos QR." -#: bal/gui/qt/dialogs.py:2781 +#: bal/gui/qt/dialogs.py:2822 msgid "QR codes per second:" msgstr "Códigos QR por segundo:" -#: bal/gui/qt/dialogs.py:2785 +#: bal/gui/qt/dialogs.py:2826 msgid " /s" msgstr " /s" -#: bal/gui/qt/dialogs.py:2787 +#: bal/gui/qt/dialogs.py:2828 msgid "Loop" msgstr "Bucle" -#: bal/gui/qt/dialogs.py:2790 +#: bal/gui/qt/dialogs.py:2831 msgid "When the last QR code is reached, keep cycling from the first one instead of stopping." msgstr "Cuando se alcanza el último código QR, sigue repitiendo desde el primero en lugar de detenerse." -#: bal/gui/qt/dialogs.py:2799 +#: bal/gui/qt/dialogs.py:2840 msgid "QR code size:" msgstr "Tamaño del código QR:" -#: bal/gui/qt/dialogs.py:2847 +#: bal/gui/qt/dialogs.py:2888 msgid "Stop" msgstr "Detener" -#: bal/gui/qt/dialogs.py:2868 +#: bal/gui/qt/dialogs.py:2910 #, python-brace-format msgid "" "Scan the QR codes below with the will-opening device.\n" @@ -722,98 +740,101 @@ msgstr "" "Escanea los códigos QR de abajo con el dispositivo que abre el testamento.\n" "{} códigos contienen la transferencia completa (sirve cualquier orden y se ignoran los duplicados)." -#: bal/gui/qt/dialogs.py:2890 +#: bal/gui/qt/dialogs.py:2931 #, python-brace-format msgid "Frame {} of {}" msgstr "Código {} de {}" -#: bal/gui/qt/dialogs.py:2913 +#: bal/gui/qt/dialogs.py:2954 msgid "Export will" msgstr "Exportar testamento" -#: bal/gui/qt/dialogs.py:2924 +#: bal/gui/qt/dialogs.py:2965 msgid "No will transaction to export." msgstr "No hay ninguna transacción del testamento que exportar." -#: bal/gui/qt/dialogs.py:2931 +#: bal/gui/qt/dialogs.py:2972 msgid "Export:" msgstr "Exportar:" -#: bal/gui/qt/dialogs.py:2938 +#: bal/gui/qt/dialogs.py:2979 msgid "Whole will" msgstr "Testamento completo" -#: bal/gui/qt/dialogs.py:2942 +#: bal/gui/qt/dialogs.py:2983 msgid "Export the full will items (all details/statuses) as JSON, or only the serialized transactions." msgstr "Exporta los elementos completos del testamento (todos los detalles y estados) en JSON, o solo las transacciones serializadas." -#: bal/gui/qt/dialogs.py:2952 +#: bal/gui/qt/dialogs.py:2993 msgid "Send as:" msgstr "Enviar como:" -#: bal/gui/qt/dialogs.py:2954 bal/gui/qt/dialogs.py:3210 +#: bal/gui/qt/dialogs.py:2995 bal/gui/qt/dialogs.py:3251 msgid "File" msgstr "Archivo" -#: bal/gui/qt/dialogs.py:2955 bal/gui/qt/dialogs.py:3211 +#: bal/gui/qt/dialogs.py:2996 bal/gui/qt/dialogs.py:3252 msgid "QR Code" msgstr "Código QR" -#: bal/gui/qt/dialogs.py:2956 bal/gui/qt/dialogs.py:3212 +#: bal/gui/qt/dialogs.py:2997 bal/gui/qt/dialogs.py:3253 msgid "Audio" msgstr "Audio" -#: bal/gui/qt/dialogs.py:3007 +#: bal/gui/qt/dialogs.py:3049 msgid "Export the will as a JSON file. Uncheck \"Whole will\" above to export only the serialized transactions (comma-separated)." msgstr "Exporta el testamento como archivo JSON. Desmarca \"Testamento completo\" arriba para exportar solo las transacciones serializadas (separadas por comas)." -#: bal/gui/qt/dialogs.py:3016 +#: bal/gui/qt/dialogs.py:3057 msgid "Export…" msgstr "Exportar…" -#: bal/gui/qt/dialogs.py:3034 bal/gui/qt/dialogs.py:3273 bal/gui/qt/window.py:1791 bal/gui/qt/window.py:1804 +#: bal/gui/qt/dialogs.py:3075 bal/gui/qt/dialogs.py:3314 +#: bal/gui/qt/window.py:1791 bal/gui/qt/window.py:1804 msgid "Audio MODEM plugin is not available." msgstr "El plugin del MÓDEM de audio no está disponible." -#: bal/gui/qt/dialogs.py:3038 bal/gui/qt/dialogs.py:3277 +#: bal/gui/qt/dialogs.py:3079 bal/gui/qt/dialogs.py:3318 msgid "Speed (KB/sec):" msgstr "Velocidad (KB/s):" -#: bal/gui/qt/dialogs.py:3049 +#: bal/gui/qt/dialogs.py:3090 msgid "Send" msgstr "Enviar" -#: bal/gui/qt/dialogs.py:3102 bal/gui/qt/dialogs.py:3136 bal/gui/qt/dialogs.py:3161 +#: bal/gui/qt/dialogs.py:3143 bal/gui/qt/dialogs.py:3177 +#: bal/gui/qt/dialogs.py:3202 msgid "No will transaction matches the selected filter." msgstr "Ninguna transacción del testamento coincide con el filtro seleccionado." -#: bal/gui/qt/dialogs.py:3125 +#: bal/gui/qt/dialogs.py:3166 msgid "item(s)" msgstr "elemento(s)" -#: bal/gui/qt/dialogs.py:3125 +#: bal/gui/qt/dialogs.py:3166 msgid "transaction(s)" msgstr "transacción(es)" -#: bal/gui/qt/dialogs.py:3127 +#: bal/gui/qt/dialogs.py:3168 #, python-brace-format msgid "{} {} will be exported." msgstr "Se exportará: {} {}." -#: bal/gui/qt/dialogs.py:3130 +#: bal/gui/qt/dialogs.py:3171 #, python-brace-format msgid "{} {} will be sent." msgstr "Se enviará: {} {}." -#: bal/gui/qt/dialogs.py:3154 bal/gui/qt/dialogs.py:3157 bal/gui/qt/dialogs.py:3313 bal/gui/qt/dialogs.py:3316 +#: bal/gui/qt/dialogs.py:3195 bal/gui/qt/dialogs.py:3198 +#: bal/gui/qt/dialogs.py:3354 bal/gui/qt/dialogs.py:3357 msgid "Invalid audio speed." msgstr "Velocidad de audio no válida." -#: bal/gui/qt/dialogs.py:3193 +#: bal/gui/qt/dialogs.py:3234 msgid "Import will" msgstr "Importar testamento" -#: bal/gui/qt/dialogs.py:3199 +#: bal/gui/qt/dialogs.py:3241 msgid "" "Choose how the will was exported: from a file, QR codes or audio.\n" "The import never touches the live will." @@ -821,59 +842,59 @@ msgstr "" "Elige cómo se exportó el testamento: desde un archivo, códigos QR o audio.\n" "La importación nunca afecta al testamento activo." -#: bal/gui/qt/dialogs.py:3208 +#: bal/gui/qt/dialogs.py:3249 msgid "Import from:" msgstr "Importar desde:" -#: bal/gui/qt/dialogs.py:3249 +#: bal/gui/qt/dialogs.py:3290 msgid "Import the JSON will file written by the Export ▶ File option. The will opens in a read-only preview window." msgstr "Importa el archivo JSON del testamento creado con la opción Exportar ▶ Archivo. El testamento se abre en una ventana de vista previa de solo lectura." -#: bal/gui/qt/dialogs.py:3255 +#: bal/gui/qt/dialogs.py:3296 msgid "Choose will file…" msgstr "Elige el archivo del testamento…" -#: bal/gui/qt/dialogs.py:3286 +#: bal/gui/qt/dialogs.py:3327 msgid "Waiting for the audio transfer…" msgstr "Esperando la transferencia de audio…" -#: bal/gui/qt/dialogs.py:3289 +#: bal/gui/qt/dialogs.py:3330 msgid "Receive by audio…" msgstr "Recibir por audio…" -#: bal/gui/qt/dialogs.py:3330 +#: bal/gui/qt/dialogs.py:3371 msgid "Receiving…" msgstr "Recibiendo…" -#: bal/gui/qt/dialogs.py:3350 +#: bal/gui/qt/dialogs.py:3391 msgid "No transaction data received." msgstr "No se recibió ningún dato de transacción." -#: bal/gui/qt/dialogs.py:3368 +#: bal/gui/qt/dialogs.py:3409 #, python-brace-format msgid "Waiting for audio ({:.1f} kbps)…" msgstr "Esperando audio ({:.1f} kbps)…" -#: bal/gui/qt/dialogs.py:3441 +#: bal/gui/qt/dialogs.py:3482 #, python-brace-format msgid "Could not parse a transferred will item: {}" msgstr "No se pudo interpretar un elemento del testamento transferido: {}" -#: bal/gui/qt/dialogs.py:3461 +#: bal/gui/qt/dialogs.py:3502 #, python-brace-format msgid "Could not parse a transferred transaction: {}" msgstr "No se pudo interpretar una transacción transferida: {}" -#: bal/gui/qt/dialogs.py:3473 +#: bal/gui/qt/dialogs.py:3514 msgid "The imported will contains no valid transaction in this wallet." msgstr "El testamento importado no contiene ninguna transacción válida en esta cartera." -#: bal/gui/qt/dialogs.py:3484 +#: bal/gui/qt/dialogs.py:3525 #, python-brace-format msgid "{} imported transaction(s) are not valid in this wallet and were skipped." msgstr "{} transacción(es) importada(s) no son válidas en esta cartera y se omitieron." -#: bal/gui/qt/dialogs.py:3583 +#: bal/gui/qt/dialogs.py:3625 msgid "" "Show the will QR codes to the camera, one after another.\n" "After the first code, every new code is captured automatically.\n" @@ -883,114 +904,114 @@ msgstr "" "Después del primer código, cada código nuevo se captura automáticamente.\n" "El primer código indica el número total de códigos; se ignoran los duplicados." -#: bal/gui/qt/dialogs.py:3593 bal/gui/qt/dialogs.py:3771 +#: bal/gui/qt/dialogs.py:3634 bal/gui/qt/dialogs.py:3812 msgid "Waiting for the first frame…" msgstr "Esperando el primer código…" -#: bal/gui/qt/dialogs.py:3610 +#: bal/gui/qt/dialogs.py:3651 msgid "…or paste/type the frame text here" msgstr "…o pega/escribe aquí el texto del código" -#: bal/gui/qt/dialogs.py:3614 +#: bal/gui/qt/dialogs.py:3655 msgid "Add frame" msgstr "Añadir código" -#: bal/gui/qt/dialogs.py:3620 bal/gui/qt/dialogs.py:3863 +#: bal/gui/qt/dialogs.py:3661 bal/gui/qt/dialogs.py:3904 msgid "Scan with camera…" msgstr "Escanear con la cámara…" -#: bal/gui/qt/dialogs.py:3623 +#: bal/gui/qt/dialogs.py:3664 msgid "Start the live camera. While it runs, every new QR code shown to the camera is captured automatically." msgstr "Inicia la cámara en vivo. Mientras esté en marcha, cada código QR nuevo que se muestre a la cámara se capturará automáticamente." -#: bal/gui/qt/dialogs.py:3629 +#: bal/gui/qt/dialogs.py:3670 msgid "Reset" msgstr "Reiniciar" -#: bal/gui/qt/dialogs.py:3636 +#: bal/gui/qt/dialogs.py:3677 msgid "Review and Sign…" msgstr "Revisar y firmar…" -#: bal/gui/qt/dialogs.py:3656 +#: bal/gui/qt/dialogs.py:3697 #, python-brace-format msgid "The scanned code belongs to a different transfer ({} frames, {}). The import was reset; scan the first code again." msgstr "El código escaneado pertenece a otra transferencia ({} códigos, {}). Se reinició la importación; escanea de nuevo el primer código." -#: bal/gui/qt/dialogs.py:3746 +#: bal/gui/qt/dialogs.py:3787 #, python-brace-format msgid "All {} frames stored." msgstr "Se guardaron los {} códigos." -#: bal/gui/qt/dialogs.py:3752 +#: bal/gui/qt/dialogs.py:3793 #, python-brace-format msgid "Stored {} of {} frames." msgstr "Guardados {} de {} códigos." -#: bal/gui/qt/dialogs.py:3817 +#: bal/gui/qt/dialogs.py:3858 msgid "Cannot start QR scanner, no usable camera found." msgstr "No se puede inciar scanner QR, no se encontró la camara." -#: bal/gui/qt/dialogs.py:3822 +#: bal/gui/qt/dialogs.py:3863 msgid "Stop scanning" msgstr "Detener escaneo" -#: bal/gui/qt/dialogs.py:3869 +#: bal/gui/qt/dialogs.py:3910 #, python-brace-format msgid "Camera error: {}" msgstr "Error de cámara: {}" -#: bal/gui/qt/dialogs.py:3916 +#: bal/gui/qt/dialogs.py:3957 #, python-brace-format msgid "The scanned code belongs to a different transfer ({} frames, {}). The import was reset; show the first code again." msgstr "El código escaneado pertenece a otra transferencia ({} códigos, {}). Se reinició la importación; muestra de nuevo el primer código." -#: bal/gui/qt/dialogs.py:3959 +#: bal/gui/qt/dialogs.py:4000 msgid "The transferred will contains no transactions." msgstr "El testamento transferido no contiene transacciones." -#: bal/gui/qt/dialogs.py:3988 +#: bal/gui/qt/dialogs.py:4029 msgid "Review and sign imported will" msgstr "Revisar y firmar el testamento importado" -#: bal/gui/qt/dialogs.py:4001 +#: bal/gui/qt/dialogs.py:4042 msgid "Enter your wallet password to sign the imported transactions." msgstr "Introduce la contraseña de tu cartera para firmar las transacciones importadas." -#: bal/gui/qt/dialogs.py:4047 +#: bal/gui/qt/dialogs.py:4088 msgid "Skip" msgstr "Omitir" -#: bal/gui/qt/dialogs.py:4063 +#: bal/gui/qt/dialogs.py:4104 msgid "Save signed file…" msgstr "Guardar archivo firmado…" -#: bal/gui/qt/dialogs.py:4066 +#: bal/gui/qt/dialogs.py:4107 msgid "Show signed QR…" msgstr "Mostrar QR firmado…" -#: bal/gui/qt/dialogs.py:4090 +#: bal/gui/qt/dialogs.py:4131 #, python-brace-format msgid "Transaction {} of {}" msgstr "Transacción {} de {}" -#: bal/gui/qt/dialogs.py:4092 +#: bal/gui/qt/dialogs.py:4133 #, python-brace-format msgid "TXID: {}" msgstr "TXID: {}" -#: bal/gui/qt/dialogs.py:4095 +#: bal/gui/qt/dialogs.py:4136 msgid "unknown" msgstr "desconocido" -#: bal/gui/qt/dialogs.py:4101 +#: bal/gui/qt/dialogs.py:4142 msgid "(no outputs)" msgstr "(sin salidas)" -#: bal/gui/qt/dialogs.py:4115 +#: bal/gui/qt/dialogs.py:4156 msgid "unknown (partial transaction)" msgstr "desconocida (transacción parcial)" -#: bal/gui/qt/dialogs.py:4117 +#: bal/gui/qt/dialogs.py:4158 #, python-brace-format msgid "" "Total outputs: {}\n" @@ -999,7 +1020,7 @@ msgstr "" "Salidas totales: {}\n" "Comisión: {}" -#: bal/gui/qt/dialogs.py:4128 +#: bal/gui/qt/dialogs.py:4170 #, python-brace-format msgid "" "Signed {} of {} transactions.\n" @@ -1010,16 +1031,16 @@ msgstr "" "\n" "Guarda un archivo firmado para llevarlo al dispositivo de transmisión o muestra las transacciones firmadas como códigos QR." -#: bal/gui/qt/dialogs.py:4147 +#: bal/gui/qt/dialogs.py:4188 #, python-brace-format msgid "Could not sign the transaction: {}" msgstr "No se pudo firmar la transacción: {}" -#: bal/gui/qt/dialogs.py:4166 +#: bal/gui/qt/dialogs.py:4207 msgid "Signed will saved." msgstr "Testamento firmado guardado." -#: bal/gui/qt/dialogs.py:4177 +#: bal/gui/qt/dialogs.py:4218 msgid "No signed transaction to show." msgstr "No hay ninguna transacción firmada que mostrar." @@ -1027,7 +1048,8 @@ msgstr "No hay ninguna transacción firmada que mostrar." msgid "Name" msgstr "Nombre" -#: bal/gui/qt/lists.py:135 bal/gui/qt/lists.py:1432 bal/gui/qt/widgets.py:1420 bal/gui/qt/window.py:374 +#: bal/gui/qt/lists.py:135 bal/gui/qt/lists.py:1432 bal/gui/qt/widgets.py:1420 +#: bal/gui/qt/window.py:374 msgid "Address" msgstr "Dirección" @@ -1235,7 +1257,8 @@ msgstr "Deseleccionar solo los no válidos" msgid "Edit: {}" msgstr "Editar: {}" -#: bal/gui/qt/lists.py:1290 bal/gui/qt/lists.py:1302 bal/gui/qt/lists.py:1316 bal/gui/qt/lists.py:1476 +#: bal/gui/qt/lists.py:1290 bal/gui/qt/lists.py:1302 bal/gui/qt/lists.py:1316 +#: bal/gui/qt/lists.py:1476 msgid "New Will Executor" msgstr "Nuevo Will-Executor" @@ -1349,7 +1372,7 @@ msgstr "Oculta las transacciones invalidadas del detalle y la lista del testamen msgid "Auto-sign on Check" msgstr "Firma automática al comprobar" -#: bal/gui/qt/plugin.py:702 +#: bal/gui/qt/plugin.py:705 msgid "" "When checking, automatically sign and broadcast the will transactions to their will-executors.\n" "The wallet password is requested only if the wallet is encrypted." @@ -1361,7 +1384,7 @@ msgstr "" msgid "Panel editable Date and Fee" msgstr "Panel editable de fecha y comisión" -#: bal/gui/qt/plugin.py:720 +#: bal/gui/qt/plugin.py:723 msgid "" "When enabled, the delivery-time and check-alive date fields can be edited everywhere (toolbar / Heirs tab), not only in the will-building wizard.\n" "When disabled, those dates are display-only outside the wizard." @@ -1373,7 +1396,7 @@ msgstr "" msgid "Max Will-Executor Fee (satoshi)" msgstr "Comisión máxima del Will-Executor (satoshi)" -#: bal/gui/qt/plugin.py:735 +#: bal/gui/qt/plugin.py:738 msgid "" "Maximum fee (in satoshi) allowed to be paid to a single will-executor. If a will-executor charges more than this, the will will not be built.\n" "Default: 500,000 satoshi (0.005 BTC)." @@ -1385,7 +1408,7 @@ msgstr "" msgid "User Type" msgstr "Tipo de usuario" -#: bal/gui/qt/plugin.py:750 +#: bal/gui/qt/plugin.py:753 msgid "" "Choose how much detail the plugin shows.\n" "\n" @@ -1411,7 +1434,7 @@ msgstr "Cuántas alarmas de recordatorio contiene el evento de calendario (.ics) msgid "Event summary" msgstr "Resumen del evento" -#: bal/gui/qt/plugin.py:776 +#: bal/gui/qt/plugin.py:779 msgid "" "Default message to be used in event summary\n" "Variables:\n" @@ -1429,7 +1452,7 @@ msgstr "" msgid "Event description" msgstr "Descripción del evento" -#: bal/gui/qt/plugin.py:790 +#: bal/gui/qt/plugin.py:793 msgid "" "Default message to be used in event description\n" "Variables:\n" @@ -1455,7 +1478,7 @@ msgstr "URL del servidor que proporciona la lista de Will-Executor. Solo disponi msgid "Calendar app command" msgstr "Comando de la aplicación de calendario" -#: bal/gui/qt/plugin.py:816 +#: bal/gui/qt/plugin.py:819 msgid "" "Command used to open .ics calendar files.\n" "Leave empty to use the system default (xdg-open/open/start).\n" @@ -1469,7 +1492,7 @@ msgstr "" msgid "Save inheritance transactions in history" msgstr "Guardar las transacciones de herencia en el historial" -#: bal/gui/qt/plugin.py:831 +#: bal/gui/qt/plugin.py:834 #, python-brace-format msgid "" "After each check, save the valid will transactions into the wallet's local history (the History tab), each with a label.\n" @@ -1486,7 +1509,7 @@ msgstr "" msgid "History label" msgstr "Etiqueta del historial" -#: bal/gui/qt/plugin.py:845 +#: bal/gui/qt/plugin.py:848 #, python-brace-format msgid "" "Label applied to the will transactions saved into the wallet's local history.\n" @@ -1507,7 +1530,7 @@ msgstr "Transmitir todas las transacciones a los Will-Executor, incluidas las ya msgid "Rebuild will on wallet close" msgstr "Recrear el testamento al cerrar la cartera" -#: bal/gui/qt/plugin.py:878 +#: bal/gui/qt/plugin.py:881 msgid "" "Run the 'Build your will' wizard every time the wallet is closed or Electrum is quit, so the will is rebuilt and re-validated.\n" "When disabled, the will is only rebuilt when you press Check or Prepare. The last built state is still saved to the wallet." @@ -1519,7 +1542,7 @@ msgstr "" msgid "Rebuild automatically on new transactions" msgstr "Recrear automáticamente con nuevas transacciones" -#: bal/gui/qt/plugin.py:896 +#: bal/gui/qt/plugin.py:899 msgid "" "When a new transaction arrives for the wallet, automatically rebuild the will the same way the wizard does at wallet close: the delivery date is anticipated by one day so the new will replaces the previous one, and the rebuilt transactions are signed and sent to their will-executors.\n" "An on-chain invalidation transaction is only built when the anticipated delivery date would fall before the Check Alive threshold, or when the threshold is already in the past.\n" @@ -1534,7 +1557,7 @@ msgstr "" msgid "Invalidation fee policy" msgstr "Invalidando el antiguo testamento" -#: bal/gui/qt/plugin.py:966 +#: bal/gui/qt/plugin.py:972 msgid "" "Fee rate the on-chain invalidation transaction pays.\n" "The invalidation is sent TODAY (it spends the will's coins so the old inheritance transactions become unusable), so it should pay the current network fee - not the will's mining fee rate.\n" @@ -1610,7 +1633,7 @@ msgstr "" msgid "Miner fee, click for more information" msgstr "Comisión de minería, haz clic para más información" -#: bal/gui/qt/widgets.py:213 +#: bal/gui/qt/widgets.py:214 msgid "" "if you choose Raw, you can insert various options based on suffix:\n" " - d: number of days after current day(ex: 1d means tomorrow)\n" @@ -1648,7 +1671,7 @@ msgstr "Fecha de entrega, haz clic para más información" msgid "Export reminder dates to your calendar (.ics)" msgstr "Exportar las fechas de recordatorio a tu calendario (.ics)" -#: bal/gui/qt/widgets.py:854 +#: bal/gui/qt/widgets.py:855 msgid "" "Enter the date on which you want the inheritance (or backup)\n" "of your Electrum wallet to take effect." @@ -1656,7 +1679,7 @@ msgstr "" "Introduce la fecha en la que quieres que la herencia\n" "de tu cartera Electrum tenga efecto." -#: bal/gui/qt/widgets.py:885 +#: bal/gui/qt/widgets.py:886 msgid "" "Please note: Do not reduce the miner fees\n" "unless you know what you’re doing" @@ -1737,11 +1760,6 @@ msgstr "herederos" msgid "Heirs are not defined" msgstr "Los herederos no están definidos" -#: bal/gui/qt/window.py:841 -#, python-brace-format -msgid "In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts.{}" -msgstr "En el proceso de herencia, la cartera siempre se vaciará por completo. Tu configuración requiere un ajuste de los importes.{}" - #: bal/gui/qt/window.py:859 msgid "CheckAlive is in the past please update it to a date in the future but less than locktime" msgstr "La fecha de verificación de vida está en el pasado: actualízala a una fecha futura pero anterior al locktime" @@ -1754,7 +1772,7 @@ msgstr "el locktime es anterior al umbral de verificación de vida" msgid " no backup transaction or willexecutor selected" msgstr " sin transacción de copia de seguridad ni Will-Executor seleccionado" -#: bal/gui/qt/window.py:917 +#: bal/gui/qt/window.py:918 msgid "" "This inheritance was already signed/sent to will-executors and you are postponing it.\n" "\n" @@ -1784,7 +1802,7 @@ msgstr "Will-Executor cambiado" msgid "Txfees are changed" msgstr "Las comisiones de transacción han cambiado" -#: bal/gui/qt/window.py:952 +#: bal/gui/qt/window.py:953 msgid "" "Found CHANGES to the DATE or the HEIRS,\n" "a NEW WILL must be prepared." @@ -1809,7 +1827,7 @@ msgstr "" msgid "Please, check your heirs, locktime and threshold!" msgstr "¡Comprueba tus herederos, el locktime y el umbral de verificación de vida!" -#: bal/gui/qt/window.py:995 +#: bal/gui/qt/window.py:996 msgid "" "Your inheritance has been rebuilt and now needs to be signed again.\n" "\n" @@ -1821,7 +1839,7 @@ msgstr "" "Siguiente paso (manual):\n" " 1. Pulsa 'Firmar' para firmar la nueva transacción." -#: bal/gui/qt/window.py:1002 +#: bal/gui/qt/window.py:1003 msgid "" "Your inheritance has been rebuilt and now needs to be signed and re-sent to the will-executors.\n" "\n" @@ -1903,7 +1921,8 @@ msgstr "comprobando {} - {} : {}" msgid "checked {} - {} : {}" msgstr "comprobado {} - {} : {}" -#: bal/gui/qt/window.py:1899 bal/gui/qt/window.py:1937 bal/gui/qt/window.py:1961 +#: bal/gui/qt/window.py:1899 bal/gui/qt/window.py:1937 +#: bal/gui/qt/window.py:1961 #, python-brace-format msgid "Invalid will file: {}" msgstr "Archivo de testamento no válido: {}" @@ -1920,7 +1939,7 @@ msgstr "Comprobando transacciones" msgid "Check Transaction" msgstr "Comprobar transacción" -#: bal/gui/qt/window.py:2172 +#: bal/gui/qt/window.py:2173 msgid "" "Could not download the will-executors list.\n" "\n" @@ -1930,7 +1949,7 @@ msgstr "" "\n" "Normalmente la causa es tu conexión a internet o un cortafuegos, no el plugin. Comprueba tu conexión (una VPN suele ayudar) e inténtalo de nuevo." -#: bal/gui/qt/window.py:2182 +#: bal/gui/qt/window.py:2183 msgid "" "Could not download the will-executors list over Tor.\n" "\n" @@ -1944,7 +1963,7 @@ msgstr "" msgid "Downloading will-executors list..." msgstr "Descargando la lista de Will-Executor..." -#: bal/gui/qt/window.py:2254 +#: bal/gui/qt/window.py:2255 #, python-brace-format msgid "" "No active will-executor servers found for the {chain} network.\n" @@ -1955,7 +1974,7 @@ msgstr "" "\n" "El servidor welist de {url} respondió pero no devolvió ningún Will-Executor para esta cadena." -#: bal/gui/qt/window.py:2262 +#: bal/gui/qt/window.py:2263 #, python-brace-format msgid "" "Could not reach the configured welist server.\n" @@ -2024,3 +2043,6 @@ msgstr "Ping a los Will-Executor" #~ "Los códigos QR más grandes contienen más datos (menos tomas) pero son más fáciles de escanear con una cámara de alta resolución; los códigos más pequeños se escanean bien incluso con cámaras de baja resolución pero requieren más tomas.\n" #~ "El mismo selector está disponible dentro del diálogo de exportación." +#~ msgid "In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts.{}" +#~ msgstr "En el proceso de herencia, la cartera siempre se vaciará por completo. Tu configuración requiere un ajuste de los importes.{}" + diff --git a/bal/locale/it_IT/LC_MESSAGES/bal.po b/bal/locale/it_IT/LC_MESSAGES/bal.po index 6039aaa..dd7c8a5 100644 --- a/bal/locale/it_IT/LC_MESSAGES/bal.po +++ b/bal/locale/it_IT/LC_MESSAGES/bal.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: BAL Electrum plugin VERSION\n" "Report-Msgid-Bugs-To: info@bitcoin-after.life\n" -"POT-Creation-Date: 2026-10-10 15:53-0400\n" +"POT-Creation-Date: 2026-10-15 16:08-0400\n" "PO-Revision-Date: 2026-09-26 22:02+0200\n" "Last-Translator: FULL NAME \n" "Language: it_IT\n" @@ -16,7 +16,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: bal/core/plugin_base.py:378 msgid "" @@ -32,88 +32,88 @@ msgstr "" msgid "BAL -Will execution of $wallet_name" msgstr "BAL - Esecuzione del testamento di $wallet_name" -#: bal/core/will.py:1502 +#: bal/core/will.py:1525 #, python-brace-format msgid "NOT {}" msgstr "NON {}" -#: bal/core/will.py:1526 +#: bal/core/will.py:1549 msgid "Anticipated" msgstr "Anticipato" -#: bal/core/will.py:1527 +#: bal/core/will.py:1550 msgid "Broadcasted" msgstr "Trasmesso" -#: bal/core/will.py:1528 +#: bal/core/will.py:1551 msgid "Checked" msgstr "Verificato" -#: bal/core/will.py:1529 +#: bal/core/will.py:1552 msgid "Check Failed" msgstr "Verifica fallita" -#: bal/core/will.py:1530 +#: bal/core/will.py:1553 msgid "Signed" msgstr "Firmato" -#: bal/core/will.py:1531 +#: bal/core/will.py:1554 msgid "Confirmed" msgstr "Confermato" -#: bal/core/will.py:1532 bal/gui/qt/lists.py:1354 bal/gui/qt/lists.py:1368 +#: bal/core/will.py:1555 bal/gui/qt/lists.py:1354 bal/gui/qt/lists.py:1368 msgid "Error" msgstr "Errore" -#: bal/core/will.py:1533 bal/gui/qt/dialogs.py:826 +#: bal/core/will.py:1556 bal/gui/qt/dialogs.py:846 msgid "Expired" msgstr "Scaduto" -#: bal/core/will.py:1534 +#: bal/core/will.py:1557 msgid "Exported" msgstr "Esportato" -#: bal/core/will.py:1535 +#: bal/core/will.py:1558 msgid "Imported" msgstr "Importato" -#: bal/core/will.py:1536 +#: bal/core/will.py:1559 msgid "Invalidated" msgstr "Invalidato" -#: bal/core/will.py:1537 +#: bal/core/will.py:1560 msgid "Mempool" msgstr "Mempool" -#: bal/core/will.py:1538 +#: bal/core/will.py:1561 msgid "Push failed" msgstr "Invio fallito" -#: bal/core/will.py:1539 +#: bal/core/will.py:1562 msgid "Pushed" msgstr "Inviato" -#: bal/core/will.py:1540 +#: bal/core/will.py:1563 msgid "Partially Signed" msgstr "Parzialmente firmato" -#: bal/core/will.py:1541 +#: bal/core/will.py:1564 msgid "Replaced" msgstr "Sostituito" -#: bal/core/will.py:1542 +#: bal/core/will.py:1565 msgid "Restored" msgstr "Ripristinato" -#: bal/core/will.py:1543 +#: bal/core/will.py:1566 msgid "Updated" msgstr "Aggiornato" -#: bal/core/will.py:1544 bal/gui/qt/dialogs.py:2635 +#: bal/core/will.py:1567 bal/gui/qt/dialogs.py:2676 msgid "Valid" msgstr "Valido" -#: bal/core/will.py:1550 +#: bal/core/will.py:1573 msgid "New" msgstr "Nuovo" @@ -121,7 +121,8 @@ msgstr "Nuovo" msgid "Waiting..." msgstr "In attesa..." -#: bal/core/willexecutors.py:394 bal/gui/qt/window.py:245 bal/gui/qt/window.py:1667 +#: bal/core/willexecutors.py:394 bal/gui/qt/window.py:245 +#: bal/gui/qt/window.py:1667 msgid "Success" msgstr "Riuscito" @@ -206,15 +207,15 @@ msgstr "Il tuo {0} è stato esportato a '{1}'" msgid "Bal Wizard Setup" msgstr "Bal - Configurazione guidata" -#: bal/gui/qt/dialogs.py:325 bal/gui/qt/dialogs.py:2764 +#: bal/gui/qt/dialogs.py:325 bal/gui/qt/dialogs.py:2805 msgid "Previous" msgstr "Indietro" -#: bal/gui/qt/dialogs.py:329 bal/gui/qt/dialogs.py:2767 +#: bal/gui/qt/dialogs.py:329 bal/gui/qt/dialogs.py:2808 msgid "Next" msgstr "Avanti" -#: bal/gui/qt/dialogs.py:333 bal/gui/qt/dialogs.py:4050 +#: bal/gui/qt/dialogs.py:333 bal/gui/qt/dialogs.py:4091 msgid "Cancel" msgstr "Annulla" @@ -222,7 +223,7 @@ msgstr "Annulla" msgid "Bitcoin After Life Heirs" msgstr "Bitcoin After Life - Eredi" -#: bal/gui/qt/dialogs.py:360 +#: bal/gui/qt/dialogs.py:361 msgid "" "Please add your heirs\n" " remember that the wallet balance will be spent at 100%" @@ -234,11 +235,14 @@ msgstr "" msgid "Add" msgstr "Aggiungi" -#: bal/gui/qt/dialogs.py:372 bal/gui/qt/dialogs.py:2596 bal/gui/qt/lists.py:311 bal/gui/qt/lists.py:673 bal/gui/qt/lists.py:1237 +#: bal/gui/qt/dialogs.py:372 bal/gui/qt/dialogs.py:2637 bal/gui/qt/lists.py:311 +#: bal/gui/qt/lists.py:673 bal/gui/qt/lists.py:1237 msgid "Import" msgstr "Importa" -#: bal/gui/qt/dialogs.py:374 bal/gui/qt/dialogs.py:2432 bal/gui/qt/dialogs.py:2600 bal/gui/qt/lists.py:312 bal/gui/qt/lists.py:672 bal/gui/qt/lists.py:1249 +#: bal/gui/qt/dialogs.py:374 bal/gui/qt/dialogs.py:2473 +#: bal/gui/qt/dialogs.py:2641 bal/gui/qt/lists.py:312 bal/gui/qt/lists.py:672 +#: bal/gui/qt/lists.py:1249 msgid "Export" msgstr "Esporta" @@ -290,127 +294,137 @@ msgstr "Preparazione del testamento" msgid "Building Will:" msgstr "Preparazione del testamento:" -#: bal/gui/qt/dialogs.py:731 bal/gui/qt/dialogs.py:757 bal/gui/qt/dialogs.py:767 bal/gui/qt/dialogs.py:790 +#: bal/gui/qt/dialogs.py:737 bal/gui/qt/dialogs.py:763 +#: bal/gui/qt/dialogs.py:773 bal/gui/qt/dialogs.py:796 +#: bal/gui/qt/dialogs.py:807 bal/gui/qt/dialogs.py:820 msgid "Checking variables" msgstr "Controllo dei parametri" -#: bal/gui/qt/dialogs.py:758 +#: bal/gui/qt/dialogs.py:764 msgid "Check Alive Threshold Passed: you have to Invalidate your old Will" msgstr "La data della verifica se sei vivo è passata: devi invalidare il piano del vecchio testamento" -#: bal/gui/qt/dialogs.py:767 bal/gui/qt/dialogs.py:850 +#: bal/gui/qt/dialogs.py:773 bal/gui/qt/dialogs.py:870 msgid "No Heirs" msgstr "Nessun erede" -#: bal/gui/qt/dialogs.py:790 bal/gui/qt/dialogs.py:1338 bal/gui/qt/dialogs.py:2284 bal/gui/qt/window.py:2319 +#: bal/gui/qt/dialogs.py:796 bal/gui/qt/dialogs.py:1380 +#: bal/gui/qt/dialogs.py:2325 bal/gui/qt/window.py:2319 msgid "Ok" msgstr "OK" -#: bal/gui/qt/dialogs.py:794 -msgid "" -"In the inheritance process, the entire wallet will always be fully emptied. \n" -"Your settings require an adjustment of the amounts" -msgstr "" -"Nel processo di eredità il portafogli viene sempre svuotato del tutto. \n" -"Le tue impostazioni richiedono una correzione degli importi" +#: bal/gui/qt/dialogs.py:810 bal/gui/qt/window.py:841 +msgid "In the inheritance process, the entire wallet will always be fully emptied." +msgstr "Nel processo di eredità il portafogli viene sempre svuotato del tutto." -#: bal/gui/qt/dialogs.py:803 bal/gui/qt/window.py:846 +#: bal/gui/qt/dialogs.py:822 bal/gui/qt/window.py:846 #, python-brace-format msgid "Will-executor fee too high: {}" msgstr "Commissione del Will-Executor troppo alta: {}" -#: bal/gui/qt/dialogs.py:837 +#: bal/gui/qt/dialogs.py:857 msgid "Postponed: invalidating old will" msgstr "Posticipato: invalidazione del piano del vecchio testamento" -#: bal/gui/qt/dialogs.py:873 bal/gui/qt/dialogs.py:882 bal/gui/qt/dialogs.py:2244 +#: bal/gui/qt/dialogs.py:893 bal/gui/qt/dialogs.py:902 +#: bal/gui/qt/dialogs.py:2285 msgid "Checking your will" msgstr "Controllo del testamento" -#: bal/gui/qt/dialogs.py:875 +#: bal/gui/qt/dialogs.py:895 msgid "An inheritance of this wallet is already executed (on blockchain)" msgstr "Un'eredità di questo portafogli è già stata eseguita (sulla blockchain)" -#: bal/gui/qt/dialogs.py:884 +#: bal/gui/qt/dialogs.py:904 msgid "Inheritance in mempool (waiting confirmation)" msgstr "Eredità nella mempool (in attesa di conferma)" -#: bal/gui/qt/dialogs.py:917 +#: bal/gui/qt/dialogs.py:937 msgid "Will-Executor excluded" msgstr "Will-Executor escluso" -#: bal/gui/qt/dialogs.py:917 bal/gui/qt/dialogs.py:1011 bal/gui/qt/dialogs.py:2225 bal/gui/qt/dialogs.py:2236 +#: bal/gui/qt/dialogs.py:937 bal/gui/qt/dialogs.py:1031 +#: bal/gui/qt/dialogs.py:2266 bal/gui/qt/dialogs.py:2277 msgid "Skipped" msgstr "Saltato" -#: bal/gui/qt/dialogs.py:923 bal/gui/qt/dialogs.py:1708 bal/gui/qt/lists.py:345 bal/gui/qt/theme.py:116 +#: bal/gui/qt/dialogs.py:943 bal/gui/qt/dialogs.py:1749 bal/gui/qt/lists.py:345 +#: bal/gui/qt/theme.py:116 msgid "Will-Executor" msgstr "Will-Executor" -#: bal/gui/qt/dialogs.py:924 +#: bal/gui/qt/dialogs.py:944 msgid "Not present - select one or enable backup mode" msgstr "Assente - selezionane uno o attiva la modalità 'transazione senza Will-Executor'" -#: bal/gui/qt/dialogs.py:986 +#: bal/gui/qt/dialogs.py:1006 msgid "All heirs' shares are below the dust limit: the inheritance cannot be created. Increase the amounts or reduce the number of heirs." msgstr "Le quote di tutti gli eredi sono sotto il limite minimo (dust): l'eredità non può essere creata. Aumenta gli importi o riduci il numero di eredi." -#: bal/gui/qt/dialogs.py:1002 +#: bal/gui/qt/dialogs.py:1022 #, python-brace-format msgid "Wallet balance is too low: {} satoshi available, but the miner and will-executor fees need {} satoshi (the minimum usable amount is {} satoshi). Add funds, or select fewer will-executors." msgstr "Il saldo del portafogli è troppo basso: {} satoshi disponibili, ma le commissioni dei miner e dei Will-Executor richiedono {} satoshi (l'importo minimo utilizzabile è {} satoshi). Aggiungi fondi, oppure seleziona meno Will-Executor." -#: bal/gui/qt/dialogs.py:1045 +#: bal/gui/qt/dialogs.py:1065 #, python-brace-format msgid "Heir {}" msgstr "Erede {}" -#: bal/gui/qt/dialogs.py:1047 +#: bal/gui/qt/dialogs.py:1067 #, python-brace-format msgid "{} is DUST - excluded (amount below dust limit)" msgstr "{} è DUST - escluso (importo sotto il limite minimo)" -#: bal/gui/qt/dialogs.py:1103 +#: bal/gui/qt/dialogs.py:1120 +#, python-brace-format +msgid "Anticipated - new delivery date: {}" +msgstr "Anticipata - nuova data di consegna: {}" + +#: bal/gui/qt/dialogs.py:1139 msgid "Heir" msgstr "Erede" -#: bal/gui/qt/dialogs.py:1220 bal/gui/qt/dialogs.py:2273 +#: bal/gui/qt/dialogs.py:1262 bal/gui/qt/dialogs.py:2314 #, python-brace-format msgid "Please wait {}secs" msgstr "Attendi {} secondi" -#: bal/gui/qt/dialogs.py:1227 bal/gui/qt/dialogs.py:1279 bal/gui/qt/dialogs.py:1317 +#: bal/gui/qt/dialogs.py:1269 bal/gui/qt/dialogs.py:1321 +#: bal/gui/qt/dialogs.py:1359 msgid "Broadcasting" msgstr "Trasmissione" -#: bal/gui/qt/dialogs.py:1338 bal/gui/qt/window.py:2321 +#: bal/gui/qt/dialogs.py:1380 bal/gui/qt/window.py:2321 msgid "Ko" msgstr "Ko" -#: bal/gui/qt/dialogs.py:1349 +#: bal/gui/qt/dialogs.py:1391 msgid "Timeout - no answer" msgstr "Tempo scaduto - nessuna risposta" -#: bal/gui/qt/dialogs.py:1391 +#: bal/gui/qt/dialogs.py:1433 #, python-brace-format msgid "checking {} - {}" msgstr "controllo {} - {}" -#: bal/gui/qt/dialogs.py:1394 bal/gui/qt/dialogs.py:2242 bal/gui/qt/window.py:1695 +#: bal/gui/qt/dialogs.py:1436 bal/gui/qt/dialogs.py:2283 +#: bal/gui/qt/window.py:1695 msgid "Waiting" msgstr "In attesa" -#: bal/gui/qt/dialogs.py:1408 +#: bal/gui/qt/dialogs.py:1450 #, python-brace-format msgid "checked {} - {}" msgstr "controllato {} - {}" -#: bal/gui/qt/dialogs.py:1458 bal/gui/qt/dialogs.py:2028 bal/gui/qt/dialogs.py:2039 +#: bal/gui/qt/dialogs.py:1500 bal/gui/qt/dialogs.py:2069 +#: bal/gui/qt/dialogs.py:2080 #, python-brace-format msgid "Error: {}" msgstr "Errore: {}" -#: bal/gui/qt/dialogs.py:1519 +#: bal/gui/qt/dialogs.py:1562 msgid "" "Your will has expired and must be invalidated before it can be rebuilt.\n" "A transaction window will now open:\n" @@ -422,11 +436,11 @@ msgstr "" "FIRMALA e poi TRASMETTILA per invalidare il piano del vecchio testamento.\n" "Quando l'invalidazione del piano è confermata, premi il pulsante Controlla per completare il testamento." -#: bal/gui/qt/dialogs.py:1549 bal/gui/qt/window.py:852 +#: bal/gui/qt/dialogs.py:1591 bal/gui/qt/window.py:852 msgid "Check Alive must be after today and before the delivery date, please update it" msgstr "La data della verifica se sei vivo deve essere dopo oggi e prima della data di consegna: aggiornala" -#: bal/gui/qt/dialogs.py:1571 +#: bal/gui/qt/dialogs.py:1614 msgid "" "Your old will has been invalidated and the transaction was broadcast.\n" "Electrum may need a little time to register it.\n" @@ -436,19 +450,19 @@ msgstr "" "Electrum potrebbe avere bisogno di un po' di tempo per registrarla.\n" "Attendi che la transazione di invalidazione sia confermata, poi premi di nuovo il pulsante Controlla per completare l'aggiornamento del testamento." -#: bal/gui/qt/dialogs.py:1587 +#: bal/gui/qt/dialogs.py:1629 msgid "Invalidate your old will" msgstr "Invalida il piano del vecchio testamento" -#: bal/gui/qt/dialogs.py:1601 bal/gui/qt/dialogs.py:1646 +#: bal/gui/qt/dialogs.py:1643 bal/gui/qt/dialogs.py:1687 msgid "Aborted" msgstr "Interrotto" -#: bal/gui/qt/dialogs.py:1620 +#: bal/gui/qt/dialogs.py:1662 msgid "Auto-sign disabled — sign manually" msgstr "Firma automatica disattivata — firma manualmente" -#: bal/gui/qt/dialogs.py:1633 +#: bal/gui/qt/dialogs.py:1676 msgid "" "The delivery date was automatically moved one day earlier so the updated will can correctly replace the previous one.\n" "Please sign (and broadcast) to confirm the change." @@ -456,131 +470,134 @@ msgstr "" "La data di consegna è stata anticipata automaticamente di un giorno, così il testamento aggiornato può sostituire correttamente il precedente.\n" "Firma (e trasmetti il piano) per confermare la modifica." -#: bal/gui/qt/dialogs.py:1643 +#: bal/gui/qt/dialogs.py:1684 msgid "Sign your will" msgstr "Firma il testamento" -#: bal/gui/qt/dialogs.py:1648 bal/gui/qt/dialogs.py:1931 +#: bal/gui/qt/dialogs.py:1689 bal/gui/qt/dialogs.py:1972 msgid "Nothing to do" msgstr "Niente da fare" -#: bal/gui/qt/dialogs.py:1667 +#: bal/gui/qt/dialogs.py:1708 msgid "Finished" msgstr "Finito" -#: bal/gui/qt/dialogs.py:1684 +#: bal/gui/qt/dialogs.py:1725 msgid "Calendar" msgstr "Calendario" -#: bal/gui/qt/dialogs.py:1686 bal/gui/qt/dialogs.py:1716 bal/gui/qt/dialogs.py:1783 bal/gui/qt/dialogs.py:2031 bal/gui/qt/dialogs.py:2978 bal/gui/qt/dialogs.py:3233 bal/gui/qt/dialogs.py:4069 +#: bal/gui/qt/dialogs.py:1727 bal/gui/qt/dialogs.py:1757 +#: bal/gui/qt/dialogs.py:1824 bal/gui/qt/dialogs.py:2072 +#: bal/gui/qt/dialogs.py:3019 bal/gui/qt/dialogs.py:3274 +#: bal/gui/qt/dialogs.py:4110 msgid "Close" msgstr "Chiudi" -#: bal/gui/qt/dialogs.py:1712 bal/gui/qt/dialogs.py:1779 +#: bal/gui/qt/dialogs.py:1753 bal/gui/qt/dialogs.py:1820 msgid "🔮 Wizard" msgstr "🔮 Procedura guidata" -#: bal/gui/qt/dialogs.py:1775 bal/gui/qt/dialogs.py:2583 +#: bal/gui/qt/dialogs.py:1816 bal/gui/qt/dialogs.py:2624 msgid "Heirs" msgstr "Eredi" -#: bal/gui/qt/dialogs.py:1884 bal/gui/qt/widgets.py:1150 +#: bal/gui/qt/dialogs.py:1925 bal/gui/qt/widgets.py:1150 #, python-brace-format msgid "(reminder {idx}/{total})" msgstr "(promemoria {idx}/{total})" -#: bal/gui/qt/dialogs.py:1948 +#: bal/gui/qt/dialogs.py:1989 msgid "All done" msgstr "Tutto fatto" -#: bal/gui/qt/dialogs.py:2000 +#: bal/gui/qt/dialogs.py:2041 msgid "Next steps (manual): press 'Sign' to sign your will, then 'Broadcast' to send it to the will-executors." msgstr "Prossimi passi (manuali): premi 'Firma' per firmare il testamento, poi 'Trasmetti il piano' per inviarlo ai Will-Executor." -#: bal/gui/qt/dialogs.py:2005 +#: bal/gui/qt/dialogs.py:2046 msgid "Next step (manual): press 'Sign' to sign your will." msgstr "Prossimo passo (manuale): premi 'Firma' per firmare il testamento." -#: bal/gui/qt/dialogs.py:2009 +#: bal/gui/qt/dialogs.py:2050 msgid "Next step (manual): press 'Broadcast' to send your will to the will-executors." msgstr "Prossimo passo (manuale): premi 'Trasmetti il piano' per inviare il testamento ai Will-Executor." -#: bal/gui/qt/dialogs.py:2104 +#: bal/gui/qt/dialogs.py:2145 #, python-brace-format msgid "Miner fee rate changed (the will was built with {} sat/byte, now it is {}): a new will must be prepared." msgstr "La commissione dei miner è cambiata (il testamento è stato creato con {} sat/byte, ora è {}): bisogna preparare un nuovo testamento." -#: bal/gui/qt/dialogs.py:2109 +#: bal/gui/qt/dialogs.py:2150 msgid "The miner fee rate changed: a new will must be prepared." msgstr "La commissione dei miner è cambiata: bisogna preparare un nuovo testamento." -#: bal/gui/qt/dialogs.py:2112 +#: bal/gui/qt/dialogs.py:2154 #, python-brace-format msgid "Will-executor \"{}\" is not covered by the current will: a new will must be prepared." msgstr "Il Will-Executor \"{}\" non è compreso nel testamento attuale: bisogna preparare un nuovo testamento." -#: bal/gui/qt/dialogs.py:2118 +#: bal/gui/qt/dialogs.py:2159 msgid "Backup mode is enabled but the will has no backup transaction: a new will must be prepared." msgstr "La transazione senza Will-Executor (tx di backup) è attiva ma il testamento non ha la transazione scritta: bisogna preparare un nuovo testamento." -#: bal/gui/qt/dialogs.py:2126 +#: bal/gui/qt/dialogs.py:2168 #, python-brace-format msgid "Heir \"{}\" is not covered by the current will (it was added or removed, or its delivery date changed): a new will must be prepared." msgstr "L'erede \"{}\" non è compreso nel testamento attuale (è stato aggiunto o rimosso, o la sua data di consegna è cambiata): bisogna preparare un nuovo testamento." -#: bal/gui/qt/dialogs.py:2135 +#: bal/gui/qt/dialogs.py:2176 msgid "The heirs changed: a new will must be prepared." msgstr "Gli eredi sono cambiati: bisogna preparare un nuovo testamento." -#: bal/gui/qt/dialogs.py:2137 +#: bal/gui/qt/dialogs.py:2178 msgid "A will-executor changed: a new will must be prepared." msgstr "Un Will-Executor è cambiato: bisogna preparare un nuovo testamento." -#: bal/gui/qt/dialogs.py:2147 +#: bal/gui/qt/dialogs.py:2188 msgid "The wallet contains funds that the current will does not cover yet: a new will must be prepared." msgstr "Il portafogli contiene fondi che il testamento attuale non comprende ancora: bisogna preparare un nuovo testamento." -#: bal/gui/qt/dialogs.py:2151 +#: bal/gui/qt/dialogs.py:2192 msgid "The will contains no valid transaction: a new will must be prepared." msgstr "Il testamento non contiene transazioni valide: bisogna preparare un nuovo testamento." -#: bal/gui/qt/dialogs.py:2157 +#: bal/gui/qt/dialogs.py:2198 msgid "The will is no longer coherent and must be rebuilt; the exact reason could not be determined." msgstr "Il testamento non è più coerente e va ricreato; non è stato possibile determinare il motivo esatto." -#: bal/gui/qt/dialogs.py:2187 +#: bal/gui/qt/dialogs.py:2228 msgid "No heirs: add at least one heir before building the will." msgstr "Nessun erede: aggiungi almeno un erede prima di preparare il testamento." -#: bal/gui/qt/dialogs.py:2190 +#: bal/gui/qt/dialogs.py:2231 msgid "The wallet has no spendable funds, so no inheritance transaction can be created." msgstr "Il portafogli non ha fondi spendibili, quindi non si può creare nessuna transazione di eredità." -#: bal/gui/qt/dialogs.py:2194 +#: bal/gui/qt/dialogs.py:2235 msgid "No usable will-executor: none of the servers in the list is both selected and valid. Open the will-executor settings, select at least one server and check that it is reachable." msgstr "Nessun Will-Executor utilizzabile: nessun server dell'elenco è sia selezionato sia valido. Apri le impostazioni dei Will-Executor, seleziona almeno un server e controlla che sia raggiungibile." -#: bal/gui/qt/dialogs.py:2199 +#: bal/gui/qt/dialogs.py:2240 msgid "No delivery date left to build: every heir's date is already covered by the existing will. Choose a later delivery date, or change an heir's date." msgstr "Nessuna data di consegna da preparare: la data di ogni erede è già compresa nel testamento esistente. Scegli una data di consegna successiva, oppure cambia la data di un erede." -#: bal/gui/qt/dialogs.py:2204 +#: bal/gui/qt/dialogs.py:2245 msgid "The amount to send must cover the miner fees plus this will-executor's fee, and the wallet balance is not enough: select cheaper will-executors, or add funds to the wallet." msgstr "L'importo da inviare deve coprire le commissioni dei miner più la commissione di questo Will-Executor, e il saldo del portafogli non basta: seleziona Will-Executor più economici, oppure aggiungi fondi al portafogli." -#: bal/gui/qt/dialogs.py:2209 +#: bal/gui/qt/dialogs.py:2250 msgid "A will-executor asks for more than the maximum fee you allowed: raise the maximum fee in the settings, or select a cheaper will-executor." msgstr "Un Will-Executor chiede più della commissione massima che hai permesso: alza la commissione massima nelle impostazioni, oppure seleziona un Will-Executor più economico." -#: bal/gui/qt/dialogs.py:2214 +#: bal/gui/qt/dialogs.py:2255 msgid "The inheritance transactions could not be assembled from the available funds (the balance may not cover the miner fees)." msgstr "Non è stato possibile comporre le transazioni di eredità con i fondi disponibili (il saldo potrebbe non coprire le commissioni dei miner)." -#: bal/gui/qt/dialogs.py:2218 +#: bal/gui/qt/dialogs.py:2259 msgid "An unexpected error stopped the transactions being prepared for a will-executor, so it was skipped. Try again, or select a different will-executor." msgstr "Un errore imprevisto ha interrotto la preparazione delle transazioni per un Will-Executor, che è stato saltato. Riprova, oppure seleziona un altro Will-Executor." -#: bal/gui/qt/dialogs.py:2228 +#: bal/gui/qt/dialogs.py:2270 msgid "" "Could not build the will, and the exact cause could not be determined. Please check that:\n" "- the wallet balance covers the miner and will-executor fees,\n" @@ -594,126 +611,127 @@ msgstr "" "- la data della verifica se sei vivo sia PRECEDENTE alla data di consegna,\n" "- almeno un Will-Executor sia selezionato e raggiungibile." -#: bal/gui/qt/dialogs.py:2249 +#: bal/gui/qt/dialogs.py:2290 msgid "Invalidating old will" msgstr "Invalidazione del piano del vecchio testamento" -#: bal/gui/qt/dialogs.py:2255 +#: bal/gui/qt/dialogs.py:2296 msgid "Building your will" msgstr "Preparazione del testamento" -#: bal/gui/qt/dialogs.py:2261 +#: bal/gui/qt/dialogs.py:2302 msgid "Signing your will" msgstr "Firma del testamento" -#: bal/gui/qt/dialogs.py:2267 +#: bal/gui/qt/dialogs.py:2308 msgid "Broadcasting your will to executors" msgstr "Trasmissione del piano ai Will-Executor" -#: bal/gui/qt/dialogs.py:2315 +#: bal/gui/qt/dialogs.py:2356 msgid "Wait" msgstr "Attendi" -#: bal/gui/qt/dialogs.py:2418 +#: bal/gui/qt/dialogs.py:2459 msgid "Will Details" msgstr "Dettagli del testamento" -#: bal/gui/qt/dialogs.py:2424 bal/gui/qt/dialogs.py:4044 bal/gui/qt/lists.py:668 +#: bal/gui/qt/dialogs.py:2465 bal/gui/qt/dialogs.py:4085 +#: bal/gui/qt/lists.py:668 msgid "Sign" msgstr "Firma" -#: bal/gui/qt/dialogs.py:2428 bal/gui/qt/lists.py:675 +#: bal/gui/qt/dialogs.py:2469 bal/gui/qt/lists.py:675 msgid "Broadcast" msgstr "Trasmissione" -#: bal/gui/qt/dialogs.py:2435 bal/gui/qt/lists.py:677 +#: bal/gui/qt/dialogs.py:2476 bal/gui/qt/lists.py:677 msgid "Invalidate" msgstr "Invalida il piano" -#: bal/gui/qt/dialogs.py:2440 bal/gui/qt/lists.py:674 +#: bal/gui/qt/dialogs.py:2481 bal/gui/qt/lists.py:674 msgid "Merge" msgstr "Unisci" -#: bal/gui/qt/dialogs.py:2448 +#: bal/gui/qt/dialogs.py:2489 #, python-brace-format msgid "Expiration date: {}" msgstr "Data di scadenza: {}" -#: bal/gui/qt/dialogs.py:2454 +#: bal/gui/qt/dialogs.py:2495 #, python-brace-format msgid "Valid Txs:{}" msgstr "Tx valide: {}" -#: bal/gui/qt/dialogs.py:2456 +#: bal/gui/qt/dialogs.py:2497 #, python-brace-format msgid "Total Txs:{}" msgstr "Tx totali: {}" -#: bal/gui/qt/dialogs.py:2510 +#: bal/gui/qt/dialogs.py:2551 msgid "Hide replaced" msgstr "Nascondi sostituite" -#: bal/gui/qt/dialogs.py:2512 +#: bal/gui/qt/dialogs.py:2553 msgid "Unhide replaced" msgstr "Mostra sostituite" -#: bal/gui/qt/dialogs.py:2518 +#: bal/gui/qt/dialogs.py:2559 msgid "Hide invalidated" msgstr "Nascondi invalidate" -#: bal/gui/qt/dialogs.py:2520 +#: bal/gui/qt/dialogs.py:2561 msgid "Unhide invalidated" msgstr "Mostra invalidate" -#: bal/gui/qt/dialogs.py:2545 +#: bal/gui/qt/dialogs.py:2586 msgid "Will-Executor Service List" msgstr "Elenco dei servizi Will-Executor" -#: bal/gui/qt/dialogs.py:2592 bal/gui/qt/lists.py:314 +#: bal/gui/qt/dialogs.py:2633 bal/gui/qt/lists.py:314 msgid "New Heir" msgstr "Nuovo erede" -#: bal/gui/qt/dialogs.py:2634 +#: bal/gui/qt/dialogs.py:2675 msgid "All" msgstr "Tutti" -#: bal/gui/qt/dialogs.py:2637 +#: bal/gui/qt/dialogs.py:2678 msgid "Valid NC" msgstr "Valido NC" -#: bal/gui/qt/dialogs.py:2775 bal/gui/qt/dialogs.py:2853 +#: bal/gui/qt/dialogs.py:2816 bal/gui/qt/dialogs.py:2894 msgid "Auto" msgstr "Auto" -#: bal/gui/qt/dialogs.py:2777 +#: bal/gui/qt/dialogs.py:2818 msgid "Automatically advance through the QR codes." msgstr "Scorri automaticamente i codici QR." -#: bal/gui/qt/dialogs.py:2781 +#: bal/gui/qt/dialogs.py:2822 msgid "QR codes per second:" msgstr "Codici QR al secondo:" -#: bal/gui/qt/dialogs.py:2785 +#: bal/gui/qt/dialogs.py:2826 msgid " /s" msgstr " /s" -#: bal/gui/qt/dialogs.py:2787 +#: bal/gui/qt/dialogs.py:2828 msgid "Loop" msgstr "Ripeti" -#: bal/gui/qt/dialogs.py:2790 +#: bal/gui/qt/dialogs.py:2831 msgid "When the last QR code is reached, keep cycling from the first one instead of stopping." msgstr "Arrivato all'ultimo codice QR, riparti dal primo invece di fermarti." -#: bal/gui/qt/dialogs.py:2799 +#: bal/gui/qt/dialogs.py:2840 msgid "QR code size:" msgstr "Dimensione del codice QR:" -#: bal/gui/qt/dialogs.py:2847 +#: bal/gui/qt/dialogs.py:2888 msgid "Stop" msgstr "Ferma" -#: bal/gui/qt/dialogs.py:2868 +#: bal/gui/qt/dialogs.py:2910 #, python-brace-format msgid "" "Scan the QR codes below with the will-opening device.\n" @@ -722,98 +740,101 @@ msgstr "" "Scansiona i codici QR qui sotto con il dispositivo che apre il testamento.\n" "{} codici contengono tutto il trasferimento (l'ordine non conta, i doppioni vengono ignorati)." -#: bal/gui/qt/dialogs.py:2890 +#: bal/gui/qt/dialogs.py:2931 #, python-brace-format msgid "Frame {} of {}" msgstr "Frame {} di {}" -#: bal/gui/qt/dialogs.py:2913 +#: bal/gui/qt/dialogs.py:2954 msgid "Export will" msgstr "Esporta il testamento" -#: bal/gui/qt/dialogs.py:2924 +#: bal/gui/qt/dialogs.py:2965 msgid "No will transaction to export." msgstr "Nessuna transazione del testamento da esportare." -#: bal/gui/qt/dialogs.py:2931 +#: bal/gui/qt/dialogs.py:2972 msgid "Export:" msgstr "Esporta:" -#: bal/gui/qt/dialogs.py:2938 +#: bal/gui/qt/dialogs.py:2979 msgid "Whole will" msgstr "Testamento completo" -#: bal/gui/qt/dialogs.py:2942 +#: bal/gui/qt/dialogs.py:2983 msgid "Export the full will items (all details/statuses) as JSON, or only the serialized transactions." msgstr "Esporta gli elementi completi del testamento (tutti i dettagli e gli stati) in JSON, oppure solo le transazioni serializzate." -#: bal/gui/qt/dialogs.py:2952 +#: bal/gui/qt/dialogs.py:2993 msgid "Send as:" msgstr "Invia come:" -#: bal/gui/qt/dialogs.py:2954 bal/gui/qt/dialogs.py:3210 +#: bal/gui/qt/dialogs.py:2995 bal/gui/qt/dialogs.py:3251 msgid "File" msgstr "File" -#: bal/gui/qt/dialogs.py:2955 bal/gui/qt/dialogs.py:3211 +#: bal/gui/qt/dialogs.py:2996 bal/gui/qt/dialogs.py:3252 msgid "QR Code" msgstr "Codice QR" -#: bal/gui/qt/dialogs.py:2956 bal/gui/qt/dialogs.py:3212 +#: bal/gui/qt/dialogs.py:2997 bal/gui/qt/dialogs.py:3253 msgid "Audio" msgstr "Audio" -#: bal/gui/qt/dialogs.py:3007 +#: bal/gui/qt/dialogs.py:3049 msgid "Export the will as a JSON file. Uncheck \"Whole will\" above to export only the serialized transactions (comma-separated)." msgstr "Esporta il testamento come file JSON. Togli la spunta a \"Testamento completo\" qui sopra per esportare solo le transazioni serializzate (separate da virgola)." -#: bal/gui/qt/dialogs.py:3016 +#: bal/gui/qt/dialogs.py:3057 msgid "Export…" msgstr "Esporta…" -#: bal/gui/qt/dialogs.py:3034 bal/gui/qt/dialogs.py:3273 bal/gui/qt/window.py:1791 bal/gui/qt/window.py:1804 +#: bal/gui/qt/dialogs.py:3075 bal/gui/qt/dialogs.py:3314 +#: bal/gui/qt/window.py:1791 bal/gui/qt/window.py:1804 msgid "Audio MODEM plugin is not available." msgstr "Il plugin Audio MODEM non è disponibile." -#: bal/gui/qt/dialogs.py:3038 bal/gui/qt/dialogs.py:3277 +#: bal/gui/qt/dialogs.py:3079 bal/gui/qt/dialogs.py:3318 msgid "Speed (KB/sec):" msgstr "Velocità (KB/sec):" -#: bal/gui/qt/dialogs.py:3049 +#: bal/gui/qt/dialogs.py:3090 msgid "Send" msgstr "Invia" -#: bal/gui/qt/dialogs.py:3102 bal/gui/qt/dialogs.py:3136 bal/gui/qt/dialogs.py:3161 +#: bal/gui/qt/dialogs.py:3143 bal/gui/qt/dialogs.py:3177 +#: bal/gui/qt/dialogs.py:3202 msgid "No will transaction matches the selected filter." msgstr "Nessuna transazione del testamento corrisponde al filtro selezionato." -#: bal/gui/qt/dialogs.py:3125 +#: bal/gui/qt/dialogs.py:3166 msgid "item(s)" msgstr "elemento/i" -#: bal/gui/qt/dialogs.py:3125 +#: bal/gui/qt/dialogs.py:3166 msgid "transaction(s)" msgstr "transazione/i" -#: bal/gui/qt/dialogs.py:3127 +#: bal/gui/qt/dialogs.py:3168 #, python-brace-format msgid "{} {} will be exported." msgstr "Verranno esportati: {} {}." -#: bal/gui/qt/dialogs.py:3130 +#: bal/gui/qt/dialogs.py:3171 #, python-brace-format msgid "{} {} will be sent." msgstr "Verranno inviati: {} {}." -#: bal/gui/qt/dialogs.py:3154 bal/gui/qt/dialogs.py:3157 bal/gui/qt/dialogs.py:3313 bal/gui/qt/dialogs.py:3316 +#: bal/gui/qt/dialogs.py:3195 bal/gui/qt/dialogs.py:3198 +#: bal/gui/qt/dialogs.py:3354 bal/gui/qt/dialogs.py:3357 msgid "Invalid audio speed." msgstr "Velocità audio non valida." -#: bal/gui/qt/dialogs.py:3193 +#: bal/gui/qt/dialogs.py:3234 msgid "Import will" msgstr "Importa il testamento" -#: bal/gui/qt/dialogs.py:3199 +#: bal/gui/qt/dialogs.py:3241 msgid "" "Choose how the will was exported: from a file, QR codes or audio.\n" "The import never touches the live will." @@ -821,59 +842,59 @@ msgstr "" "Scegli come è stato esportato il testamento: da file, codici QR o audio.\n" "L'importazione non modifica mai il testamento in uso." -#: bal/gui/qt/dialogs.py:3208 +#: bal/gui/qt/dialogs.py:3249 msgid "Import from:" msgstr "Importa da:" -#: bal/gui/qt/dialogs.py:3249 +#: bal/gui/qt/dialogs.py:3290 msgid "Import the JSON will file written by the Export ▶ File option. The will opens in a read-only preview window." msgstr "Importa il file JSON del testamento creato con l'opzione Esporta ▶ File. Il testamento si apre in una finestra di anteprima in sola lettura." -#: bal/gui/qt/dialogs.py:3255 +#: bal/gui/qt/dialogs.py:3296 msgid "Choose will file…" msgstr "Scegli il file del testamento…" -#: bal/gui/qt/dialogs.py:3286 +#: bal/gui/qt/dialogs.py:3327 msgid "Waiting for the audio transfer…" msgstr "In attesa del trasferimento audio…" -#: bal/gui/qt/dialogs.py:3289 +#: bal/gui/qt/dialogs.py:3330 msgid "Receive by audio…" msgstr "Ricevi via audio…" -#: bal/gui/qt/dialogs.py:3330 +#: bal/gui/qt/dialogs.py:3371 msgid "Receiving…" msgstr "Ricezione in corso…" -#: bal/gui/qt/dialogs.py:3350 +#: bal/gui/qt/dialogs.py:3391 msgid "No transaction data received." msgstr "Nessun dato di transazione ricevuto." -#: bal/gui/qt/dialogs.py:3368 +#: bal/gui/qt/dialogs.py:3409 #, python-brace-format msgid "Waiting for audio ({:.1f} kbps)…" msgstr "In attesa dell'audio ({:.1f} kbps)…" -#: bal/gui/qt/dialogs.py:3441 +#: bal/gui/qt/dialogs.py:3482 #, python-brace-format msgid "Could not parse a transferred will item: {}" msgstr "Impossibile leggere un elemento del testamento trasferito: {}" -#: bal/gui/qt/dialogs.py:3461 +#: bal/gui/qt/dialogs.py:3502 #, python-brace-format msgid "Could not parse a transferred transaction: {}" msgstr "Impossibile leggere una transazione trasferita: {}" -#: bal/gui/qt/dialogs.py:3473 +#: bal/gui/qt/dialogs.py:3514 msgid "The imported will contains no valid transaction in this wallet." msgstr "Il testamento importato non contiene transazioni valide in questo portafogli." -#: bal/gui/qt/dialogs.py:3484 +#: bal/gui/qt/dialogs.py:3525 #, python-brace-format msgid "{} imported transaction(s) are not valid in this wallet and were skipped." msgstr "{} transazione/i importata/e non valide in questo portafogli, quindi saltate." -#: bal/gui/qt/dialogs.py:3583 +#: bal/gui/qt/dialogs.py:3625 msgid "" "Show the will QR codes to the camera, one after another.\n" "After the first code, every new code is captured automatically.\n" @@ -883,114 +904,114 @@ msgstr "" "Dopo il primo codice, ogni nuovo codice viene acquisito automaticamente.\n" "Il primo frame indica il numero totale di codici; i doppioni vengono ignorati." -#: bal/gui/qt/dialogs.py:3593 bal/gui/qt/dialogs.py:3771 +#: bal/gui/qt/dialogs.py:3634 bal/gui/qt/dialogs.py:3812 msgid "Waiting for the first frame…" msgstr "In attesa del primo frame…" -#: bal/gui/qt/dialogs.py:3610 +#: bal/gui/qt/dialogs.py:3651 msgid "…or paste/type the frame text here" msgstr "…oppure incolla o scrivi qui il testo del frame" -#: bal/gui/qt/dialogs.py:3614 +#: bal/gui/qt/dialogs.py:3655 msgid "Add frame" msgstr "Aggiungi frame" -#: bal/gui/qt/dialogs.py:3620 bal/gui/qt/dialogs.py:3863 +#: bal/gui/qt/dialogs.py:3661 bal/gui/qt/dialogs.py:3904 msgid "Scan with camera…" msgstr "Scansiona con la fotocamera…" -#: bal/gui/qt/dialogs.py:3623 +#: bal/gui/qt/dialogs.py:3664 msgid "Start the live camera. While it runs, every new QR code shown to the camera is captured automatically." msgstr "Avvia la fotocamera. Mentre è attiva, ogni nuovo codice QR mostrato viene acquisito automaticamente." -#: bal/gui/qt/dialogs.py:3629 +#: bal/gui/qt/dialogs.py:3670 msgid "Reset" msgstr "Reimposta" -#: bal/gui/qt/dialogs.py:3636 +#: bal/gui/qt/dialogs.py:3677 msgid "Review and Sign…" msgstr "Controlla e firma…" -#: bal/gui/qt/dialogs.py:3656 +#: bal/gui/qt/dialogs.py:3697 #, python-brace-format msgid "The scanned code belongs to a different transfer ({} frames, {}). The import was reset; scan the first code again." msgstr "Il codice scansionato appartiene a un altro trasferimento ({} frame, {}). L'importazione è stata azzerata; scansiona di nuovo il primo codice." -#: bal/gui/qt/dialogs.py:3746 +#: bal/gui/qt/dialogs.py:3787 #, python-brace-format msgid "All {} frames stored." msgstr "Tutti i {} frame salvati." -#: bal/gui/qt/dialogs.py:3752 +#: bal/gui/qt/dialogs.py:3793 #, python-brace-format msgid "Stored {} of {} frames." msgstr "Salvati {} frame su {}." -#: bal/gui/qt/dialogs.py:3817 +#: bal/gui/qt/dialogs.py:3858 msgid "Cannot start QR scanner, no usable camera found." msgstr "Impossibile avviare lo scanner QR, nessuna fotocamera utilizzabile trovata." -#: bal/gui/qt/dialogs.py:3822 +#: bal/gui/qt/dialogs.py:3863 msgid "Stop scanning" msgstr "Ferma la scansione" -#: bal/gui/qt/dialogs.py:3869 +#: bal/gui/qt/dialogs.py:3910 #, python-brace-format msgid "Camera error: {}" msgstr "Errore della fotocamera: {}" -#: bal/gui/qt/dialogs.py:3916 +#: bal/gui/qt/dialogs.py:3957 #, python-brace-format msgid "The scanned code belongs to a different transfer ({} frames, {}). The import was reset; show the first code again." msgstr "Il codice scansionato appartiene a un altro trasferimento ({} frame, {}). L'importazione è stata azzerata; mostra di nuovo il primo codice." -#: bal/gui/qt/dialogs.py:3959 +#: bal/gui/qt/dialogs.py:4000 msgid "The transferred will contains no transactions." msgstr "Il testamento trasferito non contiene transazioni." -#: bal/gui/qt/dialogs.py:3988 +#: bal/gui/qt/dialogs.py:4029 msgid "Review and sign imported will" msgstr "Controlla e firma il testamento importato" -#: bal/gui/qt/dialogs.py:4001 +#: bal/gui/qt/dialogs.py:4042 msgid "Enter your wallet password to sign the imported transactions." msgstr "Inserisci la password del portafogli per firmare le transazioni importate." -#: bal/gui/qt/dialogs.py:4047 +#: bal/gui/qt/dialogs.py:4088 msgid "Skip" msgstr "Salta" -#: bal/gui/qt/dialogs.py:4063 +#: bal/gui/qt/dialogs.py:4104 msgid "Save signed file…" msgstr "Salva il file firmato…" -#: bal/gui/qt/dialogs.py:4066 +#: bal/gui/qt/dialogs.py:4107 msgid "Show signed QR…" msgstr "Mostra i QR firmati…" -#: bal/gui/qt/dialogs.py:4090 +#: bal/gui/qt/dialogs.py:4131 #, python-brace-format msgid "Transaction {} of {}" msgstr "Transazione {} di {}" -#: bal/gui/qt/dialogs.py:4092 +#: bal/gui/qt/dialogs.py:4133 #, python-brace-format msgid "TXID: {}" msgstr "TXID: {}" -#: bal/gui/qt/dialogs.py:4095 +#: bal/gui/qt/dialogs.py:4136 msgid "unknown" msgstr "sconosciuto" -#: bal/gui/qt/dialogs.py:4101 +#: bal/gui/qt/dialogs.py:4142 msgid "(no outputs)" msgstr "(nessun output)" -#: bal/gui/qt/dialogs.py:4115 +#: bal/gui/qt/dialogs.py:4156 msgid "unknown (partial transaction)" msgstr "sconosciuta (transazione parziale)" -#: bal/gui/qt/dialogs.py:4117 +#: bal/gui/qt/dialogs.py:4158 #, python-brace-format msgid "" "Total outputs: {}\n" @@ -999,7 +1020,7 @@ msgstr "" "Totale output: {}\n" "Commissione: {}" -#: bal/gui/qt/dialogs.py:4128 +#: bal/gui/qt/dialogs.py:4170 #, python-brace-format msgid "" "Signed {} of {} transactions.\n" @@ -1010,16 +1031,16 @@ msgstr "" "\n" "Salva un file firmato da portare sul dispositivo che trasmette il piano, oppure mostra le transazioni firmate come codici QR." -#: bal/gui/qt/dialogs.py:4147 +#: bal/gui/qt/dialogs.py:4188 #, python-brace-format msgid "Could not sign the transaction: {}" msgstr "Impossibile firmare la transazione: {}" -#: bal/gui/qt/dialogs.py:4166 +#: bal/gui/qt/dialogs.py:4207 msgid "Signed will saved." msgstr "Testamento firmato salvato." -#: bal/gui/qt/dialogs.py:4177 +#: bal/gui/qt/dialogs.py:4218 msgid "No signed transaction to show." msgstr "Nessuna transazione firmata da mostrare." @@ -1027,7 +1048,8 @@ msgstr "Nessuna transazione firmata da mostrare." msgid "Name" msgstr "Nome" -#: bal/gui/qt/lists.py:135 bal/gui/qt/lists.py:1432 bal/gui/qt/widgets.py:1420 bal/gui/qt/window.py:374 +#: bal/gui/qt/lists.py:135 bal/gui/qt/lists.py:1432 bal/gui/qt/widgets.py:1420 +#: bal/gui/qt/window.py:374 msgid "Address" msgstr "Indirizzo" @@ -1235,7 +1257,8 @@ msgstr "Deseleziona solo i non validi" msgid "Edit: {}" msgstr "Modifica: {}" -#: bal/gui/qt/lists.py:1290 bal/gui/qt/lists.py:1302 bal/gui/qt/lists.py:1316 bal/gui/qt/lists.py:1476 +#: bal/gui/qt/lists.py:1290 bal/gui/qt/lists.py:1302 bal/gui/qt/lists.py:1316 +#: bal/gui/qt/lists.py:1476 msgid "New Will Executor" msgstr "Nuovo Will-Executor" @@ -1349,7 +1372,7 @@ msgstr "Nascondi le transazioni invalidate dal dettaglio e dall'elenco del testa msgid "Auto-sign on Check" msgstr "Firma automatica al Controllo" -#: bal/gui/qt/plugin.py:702 +#: bal/gui/qt/plugin.py:705 msgid "" "When checking, automatically sign and broadcast the will transactions to their will-executors.\n" "The wallet password is requested only if the wallet is encrypted." @@ -1361,7 +1384,7 @@ msgstr "" msgid "Panel editable Date and Fee" msgstr "Data e commissione modificabili nel pannello" -#: bal/gui/qt/plugin.py:720 +#: bal/gui/qt/plugin.py:723 msgid "" "When enabled, the delivery-time and check-alive date fields can be edited everywhere (toolbar / Heirs tab), not only in the will-building wizard.\n" "When disabled, those dates are display-only outside the wizard." @@ -1373,7 +1396,7 @@ msgstr "" msgid "Max Will-Executor Fee (satoshi)" msgstr "Commissione massima del Will-Executor (satoshi)" -#: bal/gui/qt/plugin.py:735 +#: bal/gui/qt/plugin.py:738 msgid "" "Maximum fee (in satoshi) allowed to be paid to a single will-executor. If a will-executor charges more than this, the will will not be built.\n" "Default: 500,000 satoshi (0.005 BTC)." @@ -1385,7 +1408,7 @@ msgstr "" msgid "User Type" msgstr "Tipo di utente" -#: bal/gui/qt/plugin.py:750 +#: bal/gui/qt/plugin.py:753 msgid "" "Choose how much detail the plugin shows.\n" "\n" @@ -1411,7 +1434,7 @@ msgstr "Quanti promemoria contiene l'evento del calendario esportato (.ics). Da msgid "Event summary" msgstr "Titolo dell'evento" -#: bal/gui/qt/plugin.py:776 +#: bal/gui/qt/plugin.py:779 msgid "" "Default message to be used in event summary\n" "Variables:\n" @@ -1429,7 +1452,7 @@ msgstr "" msgid "Event description" msgstr "Descrizione dell'evento" -#: bal/gui/qt/plugin.py:790 +#: bal/gui/qt/plugin.py:793 msgid "" "Default message to be used in event description\n" "Variables:\n" @@ -1455,7 +1478,7 @@ msgstr "URL del server che fornisce l'elenco dei Will-Executor. Disponibile sol msgid "Calendar app command" msgstr "Comando dell'app calendario" -#: bal/gui/qt/plugin.py:816 +#: bal/gui/qt/plugin.py:819 msgid "" "Command used to open .ics calendar files.\n" "Leave empty to use the system default (xdg-open/open/start).\n" @@ -1469,7 +1492,7 @@ msgstr "" msgid "Save inheritance transactions in history" msgstr "Salva le transazioni di eredità nella cronologia" -#: bal/gui/qt/plugin.py:831 +#: bal/gui/qt/plugin.py:834 #, python-brace-format msgid "" "After each check, save the valid will transactions into the wallet's local history (the History tab), each with a label.\n" @@ -1486,7 +1509,7 @@ msgstr "" msgid "History label" msgstr "Etichetta nella cronologia" -#: bal/gui/qt/plugin.py:845 +#: bal/gui/qt/plugin.py:848 #, python-brace-format msgid "" "Label applied to the will transactions saved into the wallet's local history.\n" @@ -1507,7 +1530,7 @@ msgstr "Trasmetti il piano ai Will-Executor con tutte le transazioni, comprese q msgid "Rebuild will on wallet close" msgstr "Ricrea il testamento alla chiusura del portafogli" -#: bal/gui/qt/plugin.py:878 +#: bal/gui/qt/plugin.py:881 msgid "" "Run the 'Build your will' wizard every time the wallet is closed or Electrum is quit, so the will is rebuilt and re-validated.\n" "When disabled, the will is only rebuilt when you press Check or Prepare. The last built state is still saved to the wallet." @@ -1519,7 +1542,7 @@ msgstr "" msgid "Rebuild automatically on new transactions" msgstr "Ricrea automaticamente con nuove transazioni" -#: bal/gui/qt/plugin.py:896 +#: bal/gui/qt/plugin.py:899 msgid "" "When a new transaction arrives for the wallet, automatically rebuild the will the same way the wizard does at wallet close: the delivery date is anticipated by one day so the new will replaces the previous one, and the rebuilt transactions are signed and sent to their will-executors.\n" "An on-chain invalidation transaction is only built when the anticipated delivery date would fall before the Check Alive threshold, or when the threshold is already in the past.\n" @@ -1534,7 +1557,7 @@ msgstr "" msgid "Invalidation fee policy" msgstr "Invalidazione del piano del vecchio testamento" -#: bal/gui/qt/plugin.py:966 +#: bal/gui/qt/plugin.py:972 msgid "" "Fee rate the on-chain invalidation transaction pays.\n" "The invalidation is sent TODAY (it spends the will's coins so the old inheritance transactions become unusable), so it should pay the current network fee - not the will's mining fee rate.\n" @@ -1610,7 +1633,7 @@ msgstr "" msgid "Miner fee, click for more information" msgstr "Commissione dei miner, clicca per maggiori informazioni" -#: bal/gui/qt/widgets.py:213 +#: bal/gui/qt/widgets.py:214 msgid "" "if you choose Raw, you can insert various options based on suffix:\n" " - d: number of days after current day(ex: 1d means tomorrow)\n" @@ -1648,7 +1671,7 @@ msgstr "Data di consegna, clicca per maggiori informazioni" msgid "Export reminder dates to your calendar (.ics)" msgstr "Esporta le date dei promemoria nel tuo calendario (.ics)" -#: bal/gui/qt/widgets.py:854 +#: bal/gui/qt/widgets.py:855 msgid "" "Enter the date on which you want the inheritance (or backup)\n" "of your Electrum wallet to take effect." @@ -1656,7 +1679,7 @@ msgstr "" "Inserisci la data in cui vuoi che l'eredità\n" "del tuo portafogli Electrum abbia effetto." -#: bal/gui/qt/widgets.py:885 +#: bal/gui/qt/widgets.py:886 msgid "" "Please note: Do not reduce the miner fees\n" "unless you know what you’re doing" @@ -1737,11 +1760,6 @@ msgstr "eredi" msgid "Heirs are not defined" msgstr "Gli eredi non sono definiti" -#: bal/gui/qt/window.py:841 -#, python-brace-format -msgid "In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts.{}" -msgstr "Nel processo di eredità il portafogli viene sempre svuotato del tutto. Le tue impostazioni richiedono una correzione degli importi.{}" - #: bal/gui/qt/window.py:859 msgid "CheckAlive is in the past please update it to a date in the future but less than locktime" msgstr "La data della verifica se sei vivo è nel passato: aggiornala a una data futura ma precedente al locktime" @@ -1754,7 +1772,7 @@ msgstr "il locktime è precedente alla data della verifica se sei vivo" msgid " no backup transaction or willexecutor selected" msgstr " nessuna transazione senza Will-Executor attiva o nessun Will-Executor selezionato" -#: bal/gui/qt/window.py:917 +#: bal/gui/qt/window.py:918 msgid "" "This inheritance was already signed/sent to will-executors and you are postponing it.\n" "\n" @@ -1784,7 +1802,7 @@ msgstr "Will-Executor cambiato" msgid "Txfees are changed" msgstr "Le commissioni sono cambiate" -#: bal/gui/qt/window.py:952 +#: bal/gui/qt/window.py:953 msgid "" "Found CHANGES to the DATE or the HEIRS,\n" "a NEW WILL must be prepared." @@ -1809,7 +1827,7 @@ msgstr "" msgid "Please, check your heirs, locktime and threshold!" msgstr "Controlla i tuoi eredi, il locktime e la data della verifica se sei vivo!" -#: bal/gui/qt/window.py:995 +#: bal/gui/qt/window.py:996 msgid "" "Your inheritance has been rebuilt and now needs to be signed again.\n" "\n" @@ -1821,7 +1839,7 @@ msgstr "" "Prossimo passo (manuale):\n" " 1. Premi 'Firma' per firmare la nuova transazione." -#: bal/gui/qt/window.py:1002 +#: bal/gui/qt/window.py:1003 msgid "" "Your inheritance has been rebuilt and now needs to be signed and re-sent to the will-executors.\n" "\n" @@ -1903,7 +1921,8 @@ msgstr "controllo {} - {} : {}" msgid "checked {} - {} : {}" msgstr "controllato {} - {} : {}" -#: bal/gui/qt/window.py:1899 bal/gui/qt/window.py:1937 bal/gui/qt/window.py:1961 +#: bal/gui/qt/window.py:1899 bal/gui/qt/window.py:1937 +#: bal/gui/qt/window.py:1961 #, python-brace-format msgid "Invalid will file: {}" msgstr "File del testamento non valido: {}" @@ -1920,7 +1939,7 @@ msgstr "Controllo delle transazioni" msgid "Check Transaction" msgstr "Controlla la transazione" -#: bal/gui/qt/window.py:2172 +#: bal/gui/qt/window.py:2173 msgid "" "Could not download the will-executors list.\n" "\n" @@ -1930,7 +1949,7 @@ msgstr "" "\n" "Di solito la causa è la connessione a internet o un firewall, non il plugin. Controlla la connessione (spesso una VPN aiuta) e riprova." -#: bal/gui/qt/window.py:2182 +#: bal/gui/qt/window.py:2183 msgid "" "Could not download the will-executors list over Tor.\n" "\n" @@ -1944,7 +1963,7 @@ msgstr "" msgid "Downloading will-executors list..." msgstr "Download dell'elenco dei Will-Executor..." -#: bal/gui/qt/window.py:2254 +#: bal/gui/qt/window.py:2255 #, python-brace-format msgid "" "No active will-executor servers found for the {chain} network.\n" @@ -1955,7 +1974,7 @@ msgstr "" "\n" "Il server welist {url} ha risposto, ma non ha restituito Will-Executor per questa rete." -#: bal/gui/qt/window.py:2262 +#: bal/gui/qt/window.py:2263 #, python-brace-format msgid "" "Could not reach the configured welist server.\n" @@ -2024,3 +2043,6 @@ msgstr "Ping ai Will-Executor" #~ "I codici QR più grandi contengono più dati (meno scatti) ma si leggono meglio con una fotocamera ad alta risoluzione; quelli più piccoli si leggono bene anche con fotocamere a bassa risoluzione ma richiedono più scatti.\n" #~ "Lo stesso selettore è disponibile anche nella finestra di esportazione." +#~ msgid "In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts.{}" +#~ msgstr "Nel processo di eredità il portafogli viene sempre svuotato del tutto. Le tue impostazioni richiedono una correzione degli importi.{}" + diff --git a/tests/test_cli_controller_offline.py b/tests/test_cli_controller_offline.py index 85d1fa6..437d728 100644 --- a/tests/test_cli_controller_offline.py +++ b/tests/test_cli_controller_offline.py @@ -25,9 +25,14 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir)) from electrum.simple_config import SimpleConfig from electrum.util import UserFacingException -from bal.cli.controller import BalController +from bal.cli.controller import BalController, _user_facing from bal.core.heirs import Heirs from bal.core.util import Util +from bal.core.will import ( + HeirChangeException, + NotCompleteWillException, + WillexecutorChangeException, +) VALID_ADDRESS = "bc1qusymuetsz2psaqzqxv8qmzcy64d9meckj3lxxf" @@ -102,6 +107,13 @@ def _make_controller(plugin): return BalController(plugin, FakeWallet()) +def _tmp_path(): + """Return the path of a fresh temporary JSON file (caller removes it).""" + fd, path = tempfile.mkstemp(prefix="bal_cli_", suffix=".json") + os.close(fd) + return path + + def test_controller_init_empty(): with Plugin() as plugin: c = _make_controller(plugin) @@ -194,6 +206,179 @@ def test_willexecutors_crud(): assert renamed not in c.willexecutors +def test_willexecutors_update_accepts_promo_code(): + """Regression: the command transport used to forward six positional args to + a five-parameter controller method, raising TypeError. ``promo_code`` must + also be applied to the record instead of being silently dropped. + """ + with Plugin() as plugin: + c = _make_controller(plugin) + url = "https://executor-promo.example.invalid" + c.willexecutors_add(url, address="", base_fee=250) + # Positional call mirroring the transport layer: (url, address, + # base_fee, info, promo_code, rename_to). + result = c.willexecutors_update( + url, "", "300", "Promo executor", "PROMO10", None + ) + assert result["willexecutor"]["base_fee"] == 300 + assert result["willexecutor"]["info"] == "Promo executor" + assert c.willexecutors[url]["promo_code"] == "PROMO10" + + +def test_heirs_locktime_forced_when_multiverse_disabled(): + """When multiverse is disabled the heir locktime follows the will locktime, + exactly like the GUI's ``set_heir`` (which forces ``heir[3]``).""" + with Plugin() as plugin: + plugin.WILL_SETTINGS.set( + {"threshold": "-150d", "locktime": "2y", "baltx_fees": 20} + ) + plugin.ENABLE_MULTIVERSE.set(False) + c = _make_controller(plugin) + c.heirs_add("bob", VALID_ADDRESS, "100000", locktime="30d") + assert c.heirs["bob"][2] == "2y" + + +def test_heirs_locktime_kept_when_multiverse_enabled(): + with Plugin() as plugin: + plugin.WILL_SETTINGS.set({"threshold": "-150d", "locktime": "2y", "baltx_fees": 20}) + plugin.ENABLE_MULTIVERSE.set(True) + c = _make_controller(plugin) + c.heirs_add("carol", VALID_ADDRESS, "100000", locktime="30d") + assert c.heirs["carol"][2] == "30d" + + +def test_user_facing_maps_not_complete_will(): + """The check flow must translate every NotCompleteWillException subtype to a + user-facing message instead of leaking the raw internal exception. + """ + assert "heirs changed" in str(_user_facing(HeirChangeException())).lower() + assert "will-executor changed" in str( + _user_facing(WillexecutorChangeException()) + ).lower() + assert "no valid transaction" in str( + _user_facing(NotCompleteWillException()) + ).lower() + assert "does not cover" in str( + _user_facing(NotCompleteWillException("utxo")) + ).lower() + +def test_willexecutors_delete_missing_is_noop(): + with Plugin() as plugin: + c = _make_controller(plugin) + assert c.willexecutors_delete(["https://missing.example.invalid"]) == { + "deleted": [] + } + + +def test_willexecutors_select_only_valid(): + with Plugin() as plugin: + c = _make_controller(plugin) + valid_url = "https://valid.example.invalid" + invalid_url = "https://invalid.example.invalid" + # Valid: real address, base_fee within [dust, max_fee]. + c.willexecutors_add(valid_url, address=VALID_ADDRESS, base_fee=1000) + # Invalid: no address. + c.willexecutors_add(invalid_url, address="", base_fee=1000) + + c.willexecutors_select(None, select=True, only_valid=True) + assert c.willexecutors[valid_url]["selected"] is True + assert c.willexecutors[invalid_url]["selected"] is False + + # Select everything, then deselect only-valid: the valid one keeps its + # state, only the invalid one is cleared. + c.willexecutors_select(None, select=True) + c.willexecutors_select(None, select=False, only_valid=True) + assert c.willexecutors[valid_url]["selected"] is True + assert c.willexecutors[invalid_url]["selected"] is False + + +def test_willexecutors_import_overwrites_existing(): + import json + + with Plugin() as plugin: + c = _make_controller(plugin) + url = "https://existing.example.invalid" + c.willexecutors_add(url, address="", base_fee=100, info="Old") + path = _tmp_path() + try: + with open(path, "w", encoding="utf-8") as f: + json.dump( + { + url: { + "address": "", + "base_fee": 999, + "info": "New", + "selected": True, + } + }, + f, + ) + result = c.willexecutors_import(path) + assert result["imported"] == 1 + # The imported record replaces the existing one (GUI behaviour). + assert c.willexecutors[url]["base_fee"] == 999 + assert c.willexecutors[url]["info"] == "New" + assert c.willexecutors[url]["selected"] is True + finally: + os.remove(path) + + +def test_willexecutors_export_subsets(): + import json + + with Plugin() as plugin: + c = _make_controller(plugin) + selected_url = "https://selected.example.invalid" + other_url = "https://other.example.invalid" + invalid_url = "https://invalid.example.invalid" + c.willexecutors_add(selected_url, address=VALID_ADDRESS, base_fee=1000) + c.willexecutors_add(other_url, address=VALID_ADDRESS, base_fee=1000) + c.willexecutors_add(invalid_url, address="", base_fee=1000) + c.willexecutors_select([selected_url], select=True) + + def exported(subset): + path = _tmp_path() + try: + c.willexecutors_export(path, subset) + with open(path, encoding="utf-8") as f: + return json.load(f) + finally: + os.remove(path) + + assert set(exported(None)) == {selected_url, other_url, invalid_url} + assert set(exported("selected")) == {selected_url} + # "valid" keeps both real-address records and drops the address-less one. + assert set(exported("valid")) == {selected_url, other_url} + + +def test_user_facing_maps_no_servers_for_chain(): + from bal.core.willexecutors import Willexecutors + + advanced = Willexecutors.NoServersForChainError( + "bitcoin", url="https://welist.example/", reason="boom" + ) + assert "https://welist.example/" in str(_user_facing(advanced)) + basic = Willexecutors.NoServersForChainError("bitcoin") + assert "bitcoin" in str(_user_facing(basic)) + + +def test_prepare_will_warns_on_amount_exception(): + from bal.core import will as will_mod + + with Plugin() as plugin: + plugin.NO_WILLEXECUTOR.set(True) + c = _make_controller(plugin) + c.heirs["alice"] = [VALID_ADDRESS, "100%", "2y"] + with mock.patch.object( + will_mod.Will, + "check_amounts", + side_effect=will_mod.FixedAmountException("too much"), + ), mock.patch.object(will_mod.Will, "is_will_valid", return_value=True): + result = c.prepare_will() + # The amount mismatch is a warning, not an abort: the flow completes. + assert result["result"] == "coherent" + + def test_will_status_empty(): with Plugin() as plugin: c = _make_controller(plugin) diff --git a/tests/test_gui_will_flows.py b/tests/test_gui_will_flows.py index 511584a..ef0fcc7 100644 --- a/tests/test_gui_will_flows.py +++ b/tests/test_gui_will_flows.py @@ -386,7 +386,9 @@ def test_insufficient_funds_warns(): assert not will, "no wallet funds must not build a will" assert ctl.window.warnings, "user must be warned about the balance" - assert any("adjustment" in w.lower() for w in ctl.window.warnings) + # The wording was shortened (task #67): the "adjustment of the amounts" + # sentence was dropped, the "fully emptied" note stays. + assert any("fully emptied" in w.lower() for w in ctl.window.warnings) assert not ctl.willitems diff --git a/tests/test_sync_locktime_built_txs.py b/tests/test_sync_locktime_built_txs.py index 2c70c20..10bcaa2 100644 --- a/tests/test_sync_locktime_built_txs.py +++ b/tests/test_sync_locktime_built_txs.py @@ -1,10 +1,11 @@ """ -Tests for ``BalBuildWillDialog._sync_locktime_to_built_txs``. +Tests for ``BalBuildWillDialog._sync_locktime_to_built_txs`` and the +"Building your will" row of ``BalBuildWillDialog._build_success_report``. -This is the post-build sync that keeps the plugin's stored delivery date -(WILL_SETTINGS["locktime"]) in lockstep with the BUILT transactions' fixed -locktime when the core AUTOMATICALLY anticipates it (one day earlier than -stored). +``_sync_locktime_to_built_txs`` is the post-build sync that keeps the plugin's +stored delivery date (WILL_SETTINGS["locktime"]) in lockstep with the BUILT +transactions' fixed locktime when the core AUTOMATICALLY anticipates it (one +day earlier than stored). RELATIVE recipes ("90d" / "1y") are now PRESERVED: the daily-drift problem that once forced freezing them to absolute timestamps is solved at the root by @@ -14,8 +15,14 @@ anchoring every relative recipe against the built transactions timestamp). Only a genuine automatic anticipation on an ABSOLUTE stored date moves the stored value. -The method is exercised with a lightweight fake ``self`` (no Qt event loop, no -Electrum wallet) by calling it as an unbound method. +WHY THE FLAG IS NOT SET HERE ANY MORE: because a relative recipe is anchored to +the built tx, a stored-vs-built comparison cannot detect the anticipation for +it. ``_build_success_report`` therefore detects it by comparing the will's +minimum locktime BEFORE the rebuild with the one AFTER it (see there), which +works for both absolute and relative recipes. + +The methods are exercised with a lightweight fake ``self`` (no Qt event loop, +no Electrum wallet) by calling them as unbound methods. Run: source "$BAL_HOME/electrum/env/bin/activate" @@ -35,10 +42,12 @@ from bal.gui.qt.dialogs import BalBuildWillDialog # noqa: E402 (path insert ab # ------------------------------------------------------------------ # def _fake_willitem(tx_locktime): - """Minimal stand-in for a WillItem: enough for Will.get_min_locktime.""" + """Minimal stand-in for a WillItem: enough for Will.get_min_locktime and + the heir listing in _build_success_report.""" return SimpleNamespace( tx=SimpleNamespace(locktime=tx_locktime), get_status=lambda name: True, + heirs={}, ) @@ -57,7 +66,6 @@ def _make_dialog(will_settings, tx_locktimes, recorded): will_settings=will_settings, update_setting_widgets=update_setting_widgets, ), - _date_was_anticipated=False, ) @@ -83,7 +91,6 @@ def test_relative_locktime_preserved(): assert fake.bal_window.will_settings["locktime"] == "90d" assert fake.bal_window.will_settings["threshold"] == "30d" assert recorded == [], "a relative recipe must never be rewritten" - assert fake._date_was_anticipated is False def test_relative_threshold_preserved(): @@ -108,12 +115,13 @@ def test_absolute_locktime_unchanged_on_equal(): recorded, ) assert fake.bal_window.will_settings["locktime"] == tx_locktime - assert fake._date_was_anticipated is False + assert fake.bal_window.will_settings["threshold"] == 1_700_000_000 -def test_anticipation_sets_flag_and_moves_earlier(): +def test_anticipation_moves_stored_date_earlier(): """A real automatic anticipation of an ABSOLUTE stored date (built earlier - than stored) still moves the date earlier and flags the sign prompt.""" + than stored) moves the stored date earlier so the next Check does not + mistake it for a postpone.""" tx_locktime = 1_700_000_000 recorded = [] fake = _call_sync( @@ -122,7 +130,6 @@ def test_anticipation_sets_flag_and_moves_earlier(): recorded, ) assert fake.bal_window.will_settings["locktime"] == tx_locktime - assert fake._date_was_anticipated is True def test_stored_earlier_than_built_never_moved_later(): @@ -137,7 +144,6 @@ def test_stored_earlier_than_built_never_moved_later(): recorded, ) assert fake.bal_window.will_settings["locktime"] == stored - assert fake._date_was_anticipated is False def test_multiple_txs_uses_minimum_locktime(): @@ -182,6 +188,76 @@ def test_relative_locktime_stays_coherent_via_anchor(): assert drifted > tx_locktime +# ------------------------------------------------------------------ # +# _build_success_report: the "Building your will" row +# ------------------------------------------------------------------ # + +def _make_report_dialog(new_locktimes, previous_min_locktime): + """Fake ``self`` for _build_success_report (no Qt event loop). + + ``_sync_locktime_to_built_txs`` is stubbed (it is exercised separately), so + the test drives the AFTER-build locktimes and the captured BEFORE-build + locktime directly; the message helpers capture what would be written on the + "Building your will" row. + """ + captured = {} + + def _set_building(status=None, row=None, color=None): + captured["build_status"] = status + + fake = SimpleNamespace( + bal_window=SimpleNamespace( + willitems={ + f"tx{i}": _fake_willitem(lt) + for i, lt in enumerate(new_locktimes) + }, + wallet=SimpleNamespace(set_label=lambda *a, **k: None), + ), + _previous_min_locktime=previous_min_locktime, + _sync_locktime_to_built_txs=lambda: None, + msg_set_building=_set_building, + msg_set_status=lambda *a, **k: None, + msg_alert=lambda e: "ALERT:{}".format(e), + msg_ok=lambda e=None: "OK", + ) + return fake, captured + + +def test_build_report_shows_anticipated_warning(): + """When the rebuild moved the delivery one day earlier than the previous + will, the "Building your will" row shows a warning naming the NEW delivery + date instead of a plain "Ok".""" + previous = 1_800_000_000 # 2027-01-15 (UTC) + rebuilt = previous - 86_400 # anticipated one day earlier + fake, captured = _make_report_dialog([rebuilt], previous) + BalBuildWillDialog._build_success_report(fake) + assert fake._date_was_anticipated is True + assert fake._anticipated_locktime == rebuilt + assert captured["build_status"] == ( + "ALERT:Anticipated - new delivery date: 2027-01-14" + ) + + +def test_build_report_shows_ok_when_not_anticipated(): + """Without anticipation the row keeps the plain "Ok" and the state stays + clean.""" + previous = 1_800_000_000 + fake, captured = _make_report_dialog([previous], previous) + BalBuildWillDialog._build_success_report(fake) + assert fake._date_was_anticipated is False + assert fake._anticipated_locktime is None + assert captured["build_status"] == "OK" + + +def test_build_report_first_build_is_not_anticipated(): + """A first build (no previous will) is never flagged as anticipated.""" + fake, captured = _make_report_dialog([1_800_000_000], None) + BalBuildWillDialog._build_success_report(fake) + assert fake._date_was_anticipated is False + assert fake._anticipated_locktime is None + assert captured["build_status"] == "OK" + + if __name__ == "__main__": for name in sorted(dir()): if name.startswith("test_"):