chore(core): add N4W1 error-related strings
What changed, and why it matters
This commit only adds three new user-facing text strings for an existing hardware feature called N4W1 (likely a near-field communication tag workflow). It adds error messages for empty, non-empty, and damaged tags, plus updates translation indexes and a signature file. There is no code logic change, no bug fix, and no security-relevant behavior.
No security action required. Review as normal localization/string addition.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff is a pure translation/string-table update. It introduces three new translation keys (n4w1__err_empty, n4w1__err_nonempty, n4w1__err_damaged) in the Rust qstr header, the generated TranslatedString enum, Python mocks, English translation JSON, ordering JSON, and translation signature metadata. No executable code paths are modified; no parsing, cryptography, memory handling, or authorization logic is touched. The signature update is a routine regeneration of the signed translation blob after adding strings.
Changed components
core/embed/rust/librust_qstr.hcore/embed/rust/src/translations/generated/translated_string.rscore/mocks/trezortranslate_keys.pyicore/translations/en.jsoncore/translations/order.jsoncore/translations/signatures.jsonInspect captured patch +133 / −4
diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h
index cdfe5783..ccf93cb8 100644
--- a/core/embed/rust/librust_qstr.h
+++ b/core/embed/rust/librust_qstr.h
@@ -476,6 +476,9 @@ static void _librust_qstrs(void) {
MP_QSTR_modify_fee__transaction_fee;
MP_QSTR_more_info_callback;
MP_QSTR_multiple_pages_texts;
+ MP_QSTR_n4w1__err_damaged;
+ MP_QSTR_n4w1__err_empty;
+ MP_QSTR_n4w1__err_nonempty;
MP_QSTR_n4w1__footer_first;
MP_QSTR_n4w1__footer_last;
MP_QSTR_n4w1__footer_next;
diff --git a/core/embed/rust/src/translations/generated/translated_string.rs b/core/embed/rust/src/translations/generated/translated_string.rs
index 52403ab9..05188612 100644
--- a/core/embed/rust/src/translations/generated/translated_string.rs
+++ b/core/embed/rust/src/translations/generated/translated_string.rs
@@ -1618,6 +1618,9 @@ pub enum TranslatedString {
backup__type_create = 1220, // {"Bolt": "", "Caesar": "", "Delizia": "", "Eckhart": "Select the type of wallet backup you want to create."}
backup__type_have = 1221, // {"Bolt": "", "Caesar": "", "Delizia": "", "Eckhart": "Which type of wallet backup do you have?"}
n4w1__reading = 1222, // {"Bolt": "", "Caesar": "", "Delizia": "", "Eckhart": "Reading tag..."}
+ n4w1__err_empty = 1223, // {"Bolt": "", "Caesar": "", "Delizia": "", "Eckhart": "This tag is empty. Continue to scan a different tag."}
+ n4w1__err_nonempty = 1224, // {"Bolt": "", "Caesar": "", "Delizia": "", "Eckhart": "Non-empty N4W1 tag."}
+ n4w1__err_damaged = 1225, // {"Bolt": "", "Caesar": "", "Delizia": "", "Eckhart": "This tag is damaged. Continue to try again or scan the next tag."}
}
impl TranslatedString {
@@ -2848,6 +2851,9 @@ impl TranslatedString {
"",
"",
"",
+ "",
+ "",
+ "",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -4076,6 +4082,9 @@ impl TranslatedString {
20260,
20260,
20260,
+ 20260,
+ 20260,
+ 20260,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -5303,6 +5312,9 @@ impl TranslatedString {
"",
"",
"",
+ "",
+ "",
+ "",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -6531,6 +6543,9 @@ impl TranslatedString {
20260,
20260,
20260,
+ 20260,
+ 20260,
+ 20260,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -7758,6 +7773,9 @@ impl TranslatedString {
"",
"",
"",
+ "",
+ "",
+ "",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -8986,6 +9004,9 @@ impl TranslatedString {
20260,
20260,
20260,
+ 20260,
+ 20260,
+ 20260,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -10213,6 +10234,9 @@ impl TranslatedString {
"",
"",
"",
+ "",
+ "",
+ "",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -11441,6 +11465,9 @@ impl TranslatedString {
20260,
20260,
20260,
+ 20260,
+ 20260,
+ 20260,
];
} else if #[cfg(feature = "layout_caesar")] {
@@ -12669,6 +12696,9 @@ impl TranslatedString {
"",
"",
"",
+ "",
+ "",
+ "",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -13897,6 +13927,9 @@ impl TranslatedString {
18285,
18285,
18285,
+ 18285,
+ 18285,
+ 18285,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -15124,6 +15157,9 @@ impl TranslatedString {
"",
"",
"",
+ "",
+ "",
+ "",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -16352,6 +16388,9 @@ impl TranslatedString {
18285,
18285,
18285,
+ 18285,
+ 18285,
+ 18285,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -17579,6 +17618,9 @@ impl TranslatedString {
"",
"",
"",
+ "",
+ "",
+ "",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -18807,6 +18849,9 @@ impl TranslatedString {
18285,
18285,
18285,
+ 18285,
+ 18285,
+ 18285,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -20034,6 +20079,9 @@ impl TranslatedString {
"",
"",
"",
+ "",
+ "",
+ "",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -21262,6 +21310,9 @@ impl TranslatedString {
18285,
18285,
18285,
+ 18285,
+ 18285,
+ 18285,
];
} else if #[cfg(feature = "layout_delizia")] {
@@ -22490,6 +22541,9 @@ impl TranslatedString {
"",
"",
"",
+ "",
+ "",
+ "",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -23718,6 +23772,9 @@ impl TranslatedString {
19506,
19506,
19506,
+ 19506,
+ 19506,
+ 19506,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -24945,6 +25002,9 @@ impl TranslatedString {
"",
"",
"",
+ "",
+ "",
+ "",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -26173,6 +26233,9 @@ impl TranslatedString {
19506,
19506,
19506,
+ 19506,
+ 19506,
+ 19506,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -27400,6 +27463,9 @@ impl TranslatedString {
"",
"",
"",
+ "",
+ "",
+ "",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -28628,6 +28694,9 @@ impl TranslatedString {
19506,
19506,
19506,
+ 19506,
+ 19506,
+ 19506,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -29855,6 +29924,9 @@ impl TranslatedString {
"",
"",
"",
+ "",
+ "",
+ "",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -31083,6 +31155,9 @@ impl TranslatedString {
19506,
19506,
19506,
+ 19506,
+ 19506,
+ 19506,
];
} else if #[cfg(feature = "layout_eckhart")] {
@@ -32311,6 +32386,9 @@ impl TranslatedString {
"Select the type of wallet backup you want to create.",
"Which type of wallet backup do you have?",
"Reading tag...",
+ "This tag is empty. Continue to scan a different tag.",
+ "Non-empty N4W1 tag.",
+ "This tag is damaged. Continue to try again or scan the next tag.",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -33539,6 +33617,9 @@ impl TranslatedString {
20642,
20682,
20696,
+ 20748,
+ 20767,
+ 20831,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -34766,6 +34847,9 @@ impl TranslatedString {
"Select the type of wallet backup you want to create.",
"Which type of wallet backup do you have?",
"Reading tag...",
+ "This tag is empty. Continue to scan a different tag.",
+ "Non-empty N4W1 tag.",
+ "This tag is damaged. Continue to try again or scan the next tag.",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -35994,6 +36078,9 @@ impl TranslatedString {
20642,
20682,
20696,
+ 20748,
+ 20767,
+ 20831,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -37221,6 +37308,9 @@ impl TranslatedString {
"Select the type of wallet backup you want to create.",
"Which type of wallet backup do you have?",
"Reading tag...",
+ "This tag is empty. Continue to scan a different tag.",
+ "Non-empty N4W1 tag.",
+ "This tag is damaged. Continue to try again or scan the next tag.",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -38449,6 +38539,9 @@ impl TranslatedString {
20642,
20682,
20696,
+ 20748,
+ 20767,
+ 20831,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -39676,6 +39769,9 @@ impl TranslatedString {
"Select the type of wallet backup you want to create.",
"Which type of wallet backup do you have?",
"Reading tag...",
+ "This tag is empty. Continue to scan a different tag.",
+ "Non-empty N4W1 tag.",
+ "This tag is damaged. Continue to try again or scan the next tag.",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -40904,6 +41000,9 @@ impl TranslatedString {
20642,
20682,
20696,
+ 20748,
+ 20767,
+ 20831,
];
}
@@ -41708,6 +41807,9 @@ impl TranslatedString {
(Qstr::MP_QSTR_monero__wanna_start_refresh, Self::monero__wanna_start_refresh),
#[cfg(feature = "universal_fw")]
(Qstr::MP_QSTR_monero__wanna_sync_key_images, Self::monero__wanna_sync_key_images),
+ (Qstr::MP_QSTR_n4w1__err_damaged, Self::n4w1__err_damaged),
+ (Qstr::MP_QSTR_n4w1__err_empty, Self::n4w1__err_empty),
+ (Qstr::MP_QSTR_n4w1__err_nonempty, Self::n4w1__err_nonempty),
(Qstr::MP_QSTR_n4w1__footer_first, Self::n4w1__footer_first),
(Qstr::MP_QSTR_n4w1__footer_last, Self::n4w1__footer_last),
(Qstr::MP_QSTR_n4w1__footer_next, Self::n4w1__footer_next),
diff --git a/core/mocks/trezortranslate_keys.pyi b/core/mocks/trezortranslate_keys.pyi
index c9d6aa14..417000fe 100644
--- a/core/mocks/trezortranslate_keys.pyi
+++ b/core/mocks/trezortranslate_keys.pyi
@@ -521,6 +521,9 @@ class TR:
monero__wanna_export_watchkey: str = "Do you really want to export watch-only credentials?"
monero__wanna_start_refresh: str = "Do you really want to\nstart refresh?"
monero__wanna_sync_key_images: str = "Do you really want to\nsync key images?"
+ n4w1__err_damaged: str = "This tag is damaged. Continue to try again or scan the next tag."
+ n4w1__err_empty: str = "This tag is empty. Continue to scan a different tag."
+ n4w1__err_nonempty: str = "Non-empty N4W1 tag."
n4w1__footer_first: str = "Start with any tag"
n4w1__footer_last: str = "Use the last remaining tag"
n4w1__footer_next: str = "Use any remaining tag"
diff --git a/core/translations/en.json b/core/translations/en.json
index 57e4376c..b1a1710d 100644
--- a/core/translations/en.json
+++ b/core/translations/en.json
@@ -1183,6 +1183,24 @@
"monero__wanna_export_watchkey": "Do you really want to export watch-only credentials?",
"monero__wanna_start_refresh": "Do you really want to\nstart refresh?",
"monero__wanna_sync_key_images": "Do you really want to\nsync key images?",
+ "n4w1__err_damaged": {
+ "Bolt": "",
+ "Caesar": "",
+ "Delizia": "",
+ "Eckhart": "This tag is damaged. Continue to try again or scan the next tag."
+ },
+ "n4w1__err_empty": {
+ "Bolt": "",
+ "Caesar": "",
+ "Delizia": "",
+ "Eckhart": "This tag is empty. Continue to scan a different tag."
+ },
+ "n4w1__err_nonempty": {
+ "Bolt": "",
+ "Caesar": "",
+ "Delizia": "",
+ "Eckhart": "Non-empty N4W1 tag."
+ },
"n4w1__footer_first": {
"Bolt": "",
"Caesar": "",
diff --git a/core/translations/order.json b/core/translations/order.json
index 4c7690b4..546d6f05 100644
--- a/core/translations/order.json
+++ b/core/translations/order.json
@@ -1221,5 +1221,8 @@
"1219": "ethereum__calldata_suffix",
"1220": "backup__type_create",
"1221": "backup__type_have",
- "1222": "n4w1__reading"
+ "1222": "n4w1__reading",
+ "1223": "n4w1__err_empty",
+ "1224": "n4w1__err_nonempty",
+ "1225": "n4w1__err_damaged"
}
diff --git a/core/translations/signatures.json b/core/translations/signatures.json
index c9cb7f4a..f6d34b1c 100644
--- a/core/translations/signatures.json
+++ b/core/translations/signatures.json
@@ -1,8 +1,8 @@
{
"current": {
- "merkle_root": "f75391446191bd522e508480c4c8f6e4b280228960833c719f2e0042b8fdc961",
- "datetime": "2026-04-28T13:36:20.223292+00:00",
- "commit": "195382bf5f96fa3f2668bf5df91d7e15314219a3"
+ "merkle_root": "0e59628386f44b47e66a934a1b6c632cf4ee048b0322e82cf27eb0690cb5e2c1",
+ "datetime": "2026-04-29T14:48:26.117421+00:00",
+ "commit": "9d3c6ce08ab9e21bbbd16b6e40fbb18debd3641a"
},
"history": [
{
Why this scored 14/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.