diff --git a/core/.changelog.d/3520.fixed b/core/.changelog.d/3520.fixed new file mode 100644 index 000000000..d5ee08233 --- /dev/null +++ b/core/.changelog.d/3520.fixed @@ -0,0 +1 @@ +Translate also texts for PIN progress loaders. diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index d3de52984..c2051a3e9 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -538,6 +538,10 @@ static void _librust_qstrs(void) { MP_QSTR_sign_message__verify_address; MP_QSTR_skip_first_paint; MP_QSTR_spending_amount; + MP_QSTR_storage_msg__processing; + MP_QSTR_storage_msg__starting; + MP_QSTR_storage_msg__verifying_pin; + MP_QSTR_storage_msg__wrong_pin; MP_QSTR_subprompt; MP_QSTR_subtitle; MP_QSTR_text_mono; diff --git a/core/embed/rust/src/translations/generated/translated_string.rs b/core/embed/rust/src/translations/generated/translated_string.rs index d6af2d020..145c191b4 100644 --- a/core/embed/rust/src/translations/generated/translated_string.rs +++ b/core/embed/rust/src/translations/generated/translated_string.rs @@ -1234,6 +1234,10 @@ pub enum TranslatedString { ethereum__staking_unstake = 840, // "UNSTAKE" #[cfg(feature = "universal_fw")] ethereum__staking_unstake_intro = 841, // "Unstake ETH from Everstake?" + storage_msg__processing = 842, // "PROCESSING" + storage_msg__starting = 843, // "STARTING UP" + storage_msg__verifying_pin = 844, // "VERIFYING PIN" + storage_msg__wrong_pin = 845, // "WRONG PIN" } impl TranslatedString { @@ -2463,6 +2467,10 @@ impl TranslatedString { Self::ethereum__staking_unstake => "UNSTAKE", #[cfg(feature = "universal_fw")] Self::ethereum__staking_unstake_intro => "Unstake ETH from Everstake?", + Self::storage_msg__processing => "PROCESSING", + Self::storage_msg__starting => "STARTING UP", + Self::storage_msg__verifying_pin => "VERIFYING PIN", + Self::storage_msg__wrong_pin => "WRONG PIN", } } @@ -3693,6 +3701,10 @@ impl TranslatedString { Qstr::MP_QSTR_ethereum__staking_unstake => Some(Self::ethereum__staking_unstake), #[cfg(feature = "universal_fw")] Qstr::MP_QSTR_ethereum__staking_unstake_intro => Some(Self::ethereum__staking_unstake_intro), + Qstr::MP_QSTR_storage_msg__processing => Some(Self::storage_msg__processing), + Qstr::MP_QSTR_storage_msg__starting => Some(Self::storage_msg__starting), + Qstr::MP_QSTR_storage_msg__verifying_pin => Some(Self::storage_msg__verifying_pin), + Qstr::MP_QSTR_storage_msg__wrong_pin => Some(Self::storage_msg__wrong_pin), _ => None, } } diff --git a/core/embed/rust/src/ui/model_tr/layout.rs b/core/embed/rust/src/ui/model_tr/layout.rs index 84f99be6f..dc17992b3 100644 --- a/core/embed/rust/src/ui/model_tr/layout.rs +++ b/core/embed/rust/src/ui/model_tr/layout.rs @@ -1571,18 +1571,22 @@ extern "C" fn new_show_group_share_success( extern "C" fn new_show_progress(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { - let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; + let description: StrBuffer = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?; let indeterminate: bool = kwargs.get_or(Qstr::MP_QSTR_indeterminate, false)?; - let description: StrBuffer = - kwargs.get_or(Qstr::MP_QSTR_description, StrBuffer::empty())?; + let title: Option = kwargs + .get(Qstr::MP_QSTR_title) + .and_then(Obj::try_into_option) + .unwrap_or(None); + + let mut progress = + Progress::new(indeterminate, description).with_update_description(StrBuffer::alloc); + if let Some(title) = title { + progress = progress.with_title(title); + }; // Description updates are received as &str and we need to provide a way to // convert them to StrBuffer. - let obj = LayoutObj::new( - Progress::new(indeterminate, description) - .with_title(title) - .with_update_description(StrBuffer::alloc), - )?; + let obj = LayoutObj::new(progress)?; Ok(obj.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -2074,9 +2078,9 @@ pub static mp_module_trezorui2: Module = obj_module! { /// def show_progress( /// *, - /// title: str, + /// description: str, /// indeterminate: bool = False, - /// description: str = "", + /// title: str | None = None, /// ) -> LayoutObj[UiResult]: /// """Show progress loader. Please note that the number of lines reserved on screen for /// description is determined at construction time. If you want multiline descriptions diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index 846f9449e..712a08b41 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -1547,10 +1547,18 @@ extern "C" fn new_show_remaining_shares(n_args: usize, args: *const Obj, kwargs: extern "C" fn new_show_progress(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { - let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; + let description: StrBuffer = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?; let indeterminate: bool = kwargs.get_or(Qstr::MP_QSTR_indeterminate, false)?; - let description: StrBuffer = - kwargs.get_or(Qstr::MP_QSTR_description, StrBuffer::empty())?; + let title: Option = kwargs + .get(Qstr::MP_QSTR_title) + .and_then(Obj::try_into_option) + .unwrap_or(None); + + let (title, description) = if let Some(title) = title { + (title, description) + } else { + (description, StrBuffer::empty()) + }; // Description updates are received as &str and we need to provide a way to // convert them to StrBuffer. @@ -2130,9 +2138,9 @@ pub static mp_module_trezorui2: Module = obj_module! { /// def show_progress( /// *, - /// title: str, + /// description: str, /// indeterminate: bool = False, - /// description: str = "", + /// title: str | None = None, /// ) -> LayoutObj[UiResult]: /// """Show progress loader. Please note that the number of lines reserved on screen for /// description is determined at construction time. If you want multiline descriptions diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index b0ee53534..00e6279a9 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -399,9 +399,9 @@ def show_group_share_success( # rust/src/ui/model_tr/layout.rs def show_progress( *, - title: str, + description: str, indeterminate: bool = False, - description: str = "", + title: str | None = None, ) -> LayoutObj[UiResult]: """Show progress loader. Please note that the number of lines reserved on screen for description is determined at construction time. If you want multiline descriptions @@ -917,9 +917,9 @@ def show_remaining_shares( # rust/src/ui/model_tt/layout.rs def show_progress( *, - title: str, + description: str, indeterminate: bool = False, - description: str = "", + title: str | None = None, ) -> LayoutObj[UiResult]: """Show progress loader. Please note that the number of lines reserved on screen for description is determined at construction time. If you want multiline descriptions diff --git a/core/mocks/trezortranslate_keys.pyi b/core/mocks/trezortranslate_keys.pyi index 4bbbf2e29..cced10a62 100644 --- a/core/mocks/trezortranslate_keys.pyi +++ b/core/mocks/trezortranslate_keys.pyi @@ -756,6 +756,10 @@ class TR: stellar__value_sha256: str = "Value (SHA-256):" stellar__wanna_clean_value_key_template: str = "Do you want to clear value key {0}?" stellar__your_account: str = " your account" + storage_msg__processing: str = "PROCESSING" + storage_msg__starting: str = "STARTING UP" + storage_msg__verifying_pin: str = "VERIFYING PIN" + storage_msg__wrong_pin: str = "WRONG PIN" tezos__baker_address: str = "Baker address:" tezos__balance: str = "Balance:" tezos__ballot: str = "Ballot:" diff --git a/core/src/all_modules.py b/core/src/all_modules.py index e1162a3c2..571e7cda5 100644 --- a/core/src/all_modules.py +++ b/core/src/all_modules.py @@ -169,8 +169,6 @@ trezor.ui.layouts.tr.fido import trezor.ui.layouts.tr.fido trezor.ui.layouts.tr.homescreen import trezor.ui.layouts.tr.homescreen -trezor.ui.layouts.tr.progress -import trezor.ui.layouts.tr.progress trezor.ui.layouts.tr.recovery import trezor.ui.layouts.tr.recovery trezor.ui.layouts.tr.reset @@ -181,8 +179,6 @@ trezor.ui.layouts.tt.fido import trezor.ui.layouts.tt.fido trezor.ui.layouts.tt.homescreen import trezor.ui.layouts.tt.homescreen -trezor.ui.layouts.tt.progress -import trezor.ui.layouts.tt.progress trezor.ui.layouts.tt.recovery import trezor.ui.layouts.tt.recovery trezor.ui.layouts.tt.reset diff --git a/core/src/apps/management/authenticate_device.py b/core/src/apps/management/authenticate_device.py index 073fbddec..2ea2f9d1f 100644 --- a/core/src/apps/management/authenticate_device.py +++ b/core/src/apps/management/authenticate_device.py @@ -34,7 +34,7 @@ async def authenticate_device(msg: AuthenticateDevice) -> AuthenticityProof: write_compact_size(h, len(msg.challenge)) h.extend(msg.challenge) - spinner = progress("", description=TR.progress__authenticity_check) + spinner = progress(TR.progress__authenticity_check) spinner.report(0) try: diff --git a/core/src/apps/management/change_language.py b/core/src/apps/management/change_language.py index 5083dbdb5..d942e8c09 100644 --- a/core/src/apps/management/change_language.py +++ b/core/src/apps/management/change_language.py @@ -24,7 +24,7 @@ async def change_language(msg: ChangeLanguage) -> Success: nonlocal loader if loader is None: workflow.close_others() - loader = progress("", TR.language__progress) + loader = progress(TR.language__progress) loader.report(value) if msg.data_length == 0: diff --git a/core/src/apps/management/reset_device/__init__.py b/core/src/apps/management/reset_device/__init__.py index 139b61899..9f24d167a 100644 --- a/core/src/apps/management/reset_device/__init__.py +++ b/core/src/apps/management/reset_device/__init__.py @@ -44,7 +44,7 @@ async def reset_device(msg: ResetDevice) -> Success: await confirm_reset_device(title) # Rendering empty loader so users do not feel a freezing screen - render_empty_loader(TR.progress__processing, "") + render_empty_loader(config.StorageMessage.PROCESSING_MSG) # wipe storage to make sure the device is in a clear state storage.reset() diff --git a/core/src/trezor/pin.py b/core/src/trezor/pin.py index 918fe09be..27bbd0486 100644 --- a/core/src/trezor/pin.py +++ b/core/src/trezor/pin.py @@ -1,7 +1,9 @@ from typing import TYPE_CHECKING +from . import config + if TYPE_CHECKING: - from typing import Any + from typing import Any, Container from trezor.ui.layouts.common import ProgressLayout @@ -11,13 +13,15 @@ _progress_layout: ProgressLayout | None = None _started_with_empty_loader = False keepalive_callback: Any = None -_ignore_loader_messages: tuple[str, ...] = () +_ignore_loader_messages: Container[config.StorageMessage] = () def ignore_nonpin_loader_messages() -> None: global _ignore_loader_messages - # TODO: handle translation of those (in C) - _ignore_loader_messages = ("Processing", "Starting up") + _ignore_loader_messages = ( + config.StorageMessage.PROCESSING_MSG, + config.StorageMessage.STARTING_MSG, + ) def allow_all_loader_messages() -> None: @@ -25,7 +29,7 @@ def allow_all_loader_messages() -> None: _ignore_loader_messages = () -def render_empty_loader(message: str, description: str) -> None: +def render_empty_loader(message: config.StorageMessage, description: str = "") -> None: """Render empty loader to prevent the screen appear to be frozen.""" from trezor.ui.layouts.progress import pin_progress @@ -38,7 +42,9 @@ def render_empty_loader(message: str, description: str) -> None: _started_with_empty_loader = True -def show_pin_timeout(seconds: int, progress: int, message: str) -> bool: +def show_pin_timeout( + seconds: int, progress: int, message: config.StorageMessage +) -> bool: from trezor import TR from trezor.ui.layouts.progress import pin_progress diff --git a/core/src/trezor/ui/layouts/progress.py b/core/src/trezor/ui/layouts/progress.py index fff760ab1..e08592d87 100644 --- a/core/src/trezor/ui/layouts/progress.py +++ b/core/src/trezor/ui/layouts/progress.py @@ -1,6 +1,100 @@ -from trezor import utils +from typing import TYPE_CHECKING -if utils.UI_LAYOUT == "TT": - from .tt.progress import * # noqa: F401,F403 -elif utils.UI_LAYOUT == "TR": - from .tr.progress import * # noqa: F401,F403 +import trezorui2 +from trezor import TR, config, ui, utils + +if TYPE_CHECKING: + from typing import Any + + from .common import ProgressLayout + + +def _storage_message_to_str(message: config.StorageMessage | None) -> str | None: + from trezor import TR + + if message is None: + return None + + if message == config.StorageMessage.NO_MSG: + return "" + if message == config.StorageMessage.VERIFYING_PIN_MSG: + return TR.storage_msg__verifying_pin + if message == config.StorageMessage.PROCESSING_MSG: + return TR.storage_msg__processing + if message == config.StorageMessage.STARTING_MSG: + return TR.storage_msg__starting + if message == config.StorageMessage.WRONG_PIN_MSG: + return TR.storage_msg__wrong_pin + raise RuntimeError # unknown message + + +class RustProgress: + def __init__( + self, + layout: Any, + ): + self.layout = layout + ui.backlight_fade(ui.style.BACKLIGHT_DIM) + self.layout.attach_timer_fn(self.set_timer) + self.layout.paint() + ui.refresh() + ui.backlight_fade(ui.style.BACKLIGHT_NORMAL) + + def set_timer(self, token: int, deadline: int) -> None: + raise RuntimeError # progress layouts should not set timers + + def report(self, value: int, description: str | None = None): + msg = self.layout.progress_event(value, description or "") + assert msg is None + self.layout.paint() + ui.refresh() + + +def progress( + description: str | None = None, + title: str | None = None, + indeterminate: bool = False, +) -> ProgressLayout: + if description is None: + description = TR.progress__please_wait # def_arg + + if title is not None: + title = title.upper() + elif not utils.MODEL_IS_T2B1: + # on TT, uppercase the description which ends up on top of the screen + # when no title is set + description = description.upper() + + return RustProgress( + layout=trezorui2.show_progress( + description=description, + title=title, + indeterminate=indeterminate, + ) + ) + + +def bitcoin_progress(message: str) -> ProgressLayout: + return progress(message) + + +def coinjoin_progress(message: str) -> ProgressLayout: + return RustProgress( + layout=trezorui2.show_progress_coinjoin(title=message, indeterminate=False) + ) + + +def pin_progress(title: config.StorageMessage, description: str) -> ProgressLayout: + return progress(description=description, title=_storage_message_to_str(title)) + + +if not utils.BITCOIN_ONLY: + + def monero_keyimage_sync_progress() -> ProgressLayout: + return progress(TR.progress__syncing) + + def monero_live_refresh_progress() -> ProgressLayout: + return progress(TR.progress__refreshing, indeterminate=True) + + def monero_transaction_progress_inner() -> ProgressLayout: + return progress(TR.progress__signing_transaction) diff --git a/core/src/trezor/ui/layouts/tr/progress.py b/core/src/trezor/ui/layouts/tr/progress.py deleted file mode 100644 index 6cf843a58..000000000 --- a/core/src/trezor/ui/layouts/tr/progress.py +++ /dev/null @@ -1,69 +0,0 @@ -from typing import TYPE_CHECKING - -import trezorui2 -from trezor import TR, ui, utils - -if TYPE_CHECKING: - from typing import Any - - from ..common import ProgressLayout - - -class RustProgress: - def __init__( - self, - layout: Any, - ): - self.layout = layout - self.layout.attach_timer_fn(self.set_timer) - self.layout.paint() - ui.refresh() - - def set_timer(self, token: int, deadline: int) -> None: - raise RuntimeError # progress layouts should not set timers - - def report(self, value: int, description: str | None = None): - msg = self.layout.progress_event(value, description or "") - assert msg is None - self.layout.paint() - ui.refresh() - - -def progress( - message: str | None = None, - description: str | None = None, - indeterminate: bool = False, -) -> ProgressLayout: - return RustProgress( - layout=trezorui2.show_progress( - title=message.upper() if message else "", - indeterminate=indeterminate, - description=description or "", - ) - ) - - -def bitcoin_progress(description: str) -> ProgressLayout: - return progress("", description) - - -def coinjoin_progress(message: str) -> ProgressLayout: - return RustProgress( - layout=trezorui2.show_progress_coinjoin(title=message, indeterminate=False) - ) - - -def pin_progress(message: str, description: str) -> ProgressLayout: - return progress(message, description) - - -if not utils.BITCOIN_ONLY: - - def monero_keyimage_sync_progress() -> ProgressLayout: - return progress("", TR.progress__syncing) - - def monero_live_refresh_progress() -> ProgressLayout: - return progress("", TR.progress__refreshing, indeterminate=True) - - def monero_transaction_progress_inner() -> ProgressLayout: - return progress("", TR.progress__signing_transaction) diff --git a/core/src/trezor/ui/layouts/tt/progress.py b/core/src/trezor/ui/layouts/tt/progress.py deleted file mode 100644 index 472e6d30e..000000000 --- a/core/src/trezor/ui/layouts/tt/progress.py +++ /dev/null @@ -1,72 +0,0 @@ -from typing import TYPE_CHECKING - -import trezorui2 -from trezor import TR, ui, utils - -if TYPE_CHECKING: - from typing import Any - - from ..common import ProgressLayout - - -class RustProgress: - def __init__( - self, - layout: Any, - ): - self.layout = layout - ui.backlight_fade(ui.style.BACKLIGHT_DIM) - self.layout.attach_timer_fn(self.set_timer) - self.layout.paint() - ui.refresh() - ui.backlight_fade(ui.style.BACKLIGHT_NORMAL) - - def set_timer(self, token: int, deadline: int) -> None: - raise RuntimeError # progress layouts should not set timers - - def report(self, value: int, description: str | None = None): - msg = self.layout.progress_event(value, description or "") - assert msg is None - self.layout.paint() - ui.refresh() - - -def progress( - message: str | None = None, - description: str | None = None, - indeterminate: bool = False, -) -> ProgressLayout: - message = message or TR.progress__please_wait # def_arg - return RustProgress( - layout=trezorui2.show_progress( - title=message.upper(), - indeterminate=indeterminate, - description=description or "", - ) - ) - - -def bitcoin_progress(message: str) -> ProgressLayout: - return progress(message) - - -def coinjoin_progress(message: str) -> ProgressLayout: - return RustProgress( - layout=trezorui2.show_progress_coinjoin(title=message, indeterminate=False) - ) - - -def pin_progress(message: str, description: str) -> ProgressLayout: - return progress(message, description=description) - - -if not utils.BITCOIN_ONLY: - - def monero_keyimage_sync_progress() -> ProgressLayout: - return progress("", TR.progress__syncing) - - def monero_live_refresh_progress() -> ProgressLayout: - return progress("", TR.progress__refreshing, indeterminate=True) - - def monero_transaction_progress_inner() -> ProgressLayout: - return progress("", TR.progress__signing_transaction) diff --git a/core/translations/en.json b/core/translations/en.json index 280f091d6..b294eda6d 100644 --- a/core/translations/en.json +++ b/core/translations/en.json @@ -677,6 +677,10 @@ "sign_message__confirm_message": "CONFIRM MESSAGE", "sign_message__message_size": "Message size:", "sign_message__verify_address": "VERIFY ADDRESS", + "storage_msg__verifying_pin": "VERIFYING PIN", + "storage_msg__processing": "PROCESSING", + "storage_msg__starting": "STARTING UP", + "storage_msg__wrong_pin": "WRONG PIN", "solana__account_index": "Account index", "solana__associated_token_account": "Associated token account", "solana__confirm_multisig": "Confirm multisig", diff --git a/core/translations/order.json b/core/translations/order.json index f3c278375..f7b5f4be0 100644 --- a/core/translations/order.json +++ b/core/translations/order.json @@ -840,5 +840,9 @@ "838": "ethereum__staking_stake_address", "839": "ethereum__staking_stake_intro", "840": "ethereum__staking_unstake", - "841": "ethereum__staking_unstake_intro" + "841": "ethereum__staking_unstake_intro", + "842": "storage_msg__processing", + "843": "storage_msg__starting", + "844": "storage_msg__verifying_pin", + "845": "storage_msg__wrong_pin" } diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index 9f7a68ab3..320a16940 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -12196,7 +12196,7 @@ "TR_en_test_cancel.py::test_cancel_message_via_initialize[message1]": "41b9fc37f230520f9d94df226ff8433822e56ea4276a31ef99171a774e477045", "TR_en_test_cancel.py::test_cancel_on_paginated": "79f025ebfbdc5a81dae1385b17d2d802280063479c8480fa5281734fe1542385", "TR_en_test_debuglink.py::test_softlock_instability": "cff029b728b242ec07f405a0fcd12a77212f0a28e9ec14f1b9e2db1b63293783", -"TR_en_test_firmware_hash.py::test_firmware_hash_emu": "a5099e7016da59ba2a1efac6a060711383f199d674c8357146738c42b79be6ff", +"TR_en_test_firmware_hash.py::test_firmware_hash_emu": "a020914cfcb0f51772fc14300eb89899b605e114cb75655874aed44ef29695c0", "TR_en_test_firmware_hash.py::test_firmware_hash_hw": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_en_test_language.py::test_error_invalid_data_hash": "0cb01b8002472dff316d6eb3ba901dffb762d88fdf61e5ef8642ca7772d3e71c", "TR_en_test_language.py::test_error_invalid_data_length": "4ffbed72e7ed7fbab85f830952200adf7758af81b658b56de4672344120456a6", @@ -19514,28 +19514,28 @@ "TT_en_test_debuglink.py::test_softlock_instability": "55cb4cbeec68bd8ccee460034677cf8053f8f688d5c3559f360c38a205b34e37", "TT_en_test_firmware_hash.py::test_firmware_hash_emu": "2a63f0bd10ba99e223f571482d4af635653bb8a3bddc1d8400777ee5519bc605", "TT_en_test_firmware_hash.py::test_firmware_hash_hw": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_en_test_language.py::test_error_invalid_data_hash": "67782b952469c260afac92bac1efc2ba9c2f342319ae95fb5e91c843da2a6e46", +"TT_en_test_language.py::test_error_invalid_data_hash": "aaf31bdc64a531bc9084a003b2ad78a9fb91ba9b138090b1e2daf78ca4c106f9", "TT_en_test_language.py::test_error_invalid_data_length": "d702b0f90581cf17e0f77b4d318324a002deec42c2c5cb8860d51f6cb50f5739", "TT_en_test_language.py::test_error_invalid_header_magic": "d702b0f90581cf17e0f77b4d318324a002deec42c2c5cb8860d51f6cb50f5739", "TT_en_test_language.py::test_error_invalid_signature": "d702b0f90581cf17e0f77b4d318324a002deec42c2c5cb8860d51f6cb50f5739", "TT_en_test_language.py::test_error_too_long": "d702b0f90581cf17e0f77b4d318324a002deec42c2c5cb8860d51f6cb50f5739", "TT_en_test_language.py::test_error_version_mismatch": "d702b0f90581cf17e0f77b4d318324a002deec42c2c5cb8860d51f6cb50f5739", -"TT_en_test_language.py::test_full_language_change[cs]": "1cf02eca93e97af9c4a4193a04050f43ddc7c627cca85dc7486050977d89d95b", -"TT_en_test_language.py::test_full_language_change[de]": "d05c45a698f9e8a00b7f64bee10077dbce8e592fb5f76b76ba37e62df8d34e6c", +"TT_en_test_language.py::test_full_language_change[cs]": "82f805dacbd77f3fe46224744a2c2fe24623a2a32aa3b538ffc15ea147c26c61", +"TT_en_test_language.py::test_full_language_change[de]": "637494aacf526b8c6465a5c48a35eee4fa71d90d9f90d7c675c555bc5df75442", "TT_en_test_language.py::test_full_language_change[en]": "5f6cec419aad5e5658f6fda45c2cd40fa4581823e7f9f0c4199970cd179bfd4e", -"TT_en_test_language.py::test_full_language_change[es]": "fcb472f8786ab55cc7b90450a002165fd74ed88edc0d41a0dffd741b801d7f0b", -"TT_en_test_language.py::test_full_language_change[fr]": "a6b00695cb76f4fcc7197d37df49c3b1997da6ed23f2c21330d30e0f28dc910d", -"TT_en_test_language.py::test_header_trailing_data": "be40adb967cdb6ed5857aebeabbd13c65900fc8c2aa30ff90e239b911fbd9c59", -"TT_en_test_language.py::test_language_is_removed_after_wipe": "3e1fb6ae0bdcc7b306971d831c48e989d176cb57b10e69b319f546e0f5437f9c", +"TT_en_test_language.py::test_full_language_change[es]": "6c3c6983dedaf60e8818c0acdff7f1ba83ff9106333d834b8bed02d910bf5b1f", +"TT_en_test_language.py::test_full_language_change[fr]": "7e1f16d84163fa6b8a8acce859f5c5e97ded578c28f75629e4f9bd587cd051a8", +"TT_en_test_language.py::test_header_trailing_data": "073921ad154051d3ae330aa981a7c8ddf725006ffd007a9f131cdec0ccb82097", +"TT_en_test_language.py::test_language_is_removed_after_wipe": "094c2025512f5e4b32344313a4c3d9a1e62d8b1e04eee4dbc282509082d76979", "TT_en_test_language.py::test_reject_update": "78b8f16e00c5d653a7d5c0929d21ae8ae1c76798fe28f0eb6edee8e2ee8b0202", -"TT_en_test_language.py::test_silent_first_install[False-False]": "91184a50875388be3e29102184c2828150196f29cc59cb0e81fa6623d8ddb796", -"TT_en_test_language.py::test_silent_first_install[None-False]": "91184a50875388be3e29102184c2828150196f29cc59cb0e81fa6623d8ddb796", -"TT_en_test_language.py::test_silent_first_install[True-True]": "5620e376c365737f72b1b86d4942c162ef1f65ff159cb8262f2411e01fa0b016", -"TT_en_test_language.py::test_switch_from_english[None]": "0f92d5c7b12c2ab21152dbc9a5498859990476f91267f337dfad4b35c87e5de2", -"TT_en_test_language.py::test_switch_from_english[True]": "0f92d5c7b12c2ab21152dbc9a5498859990476f91267f337dfad4b35c87e5de2", +"TT_en_test_language.py::test_silent_first_install[False-False]": "7476715631cb4348ca5bc8ecdac99792abfc77b10da654305e1d09ce5e838176", +"TT_en_test_language.py::test_silent_first_install[None-False]": "7476715631cb4348ca5bc8ecdac99792abfc77b10da654305e1d09ce5e838176", +"TT_en_test_language.py::test_silent_first_install[True-True]": "944168e4747abf8a2a894ed59aad65de2d0e7193488b22869e3f59be034f2e5f", +"TT_en_test_language.py::test_switch_from_english[None]": "dc4fef22119297c57f6b239143880cdd8d9f08199ff596467ab17db1a64b015d", +"TT_en_test_language.py::test_switch_from_english[True]": "dc4fef22119297c57f6b239143880cdd8d9f08199ff596467ab17db1a64b015d", "TT_en_test_language.py::test_switch_from_english_not_silent": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_en_test_language.py::test_switch_language": "2d7cc1088467af2f13ec08755cd2d11e39b463209e92ef9a06d1eec0cfb8dde0", -"TT_en_test_language.py::test_translations_renders_on_screen": "9e96d81519ee2405b37a18dd856209373366665d1d9921da5ea73edcf2a74e88", +"TT_en_test_language.py::test_switch_language": "c6d3537688d4ad0169fa2e8d43d9d68f7965ac09e15e31eb618d4a40dfd9be5d", +"TT_en_test_language.py::test_translations_renders_on_screen": "30c57160aa25242ac290960c65bfe9d2f0bd3ee74ca97809f33351900c3a8c5e", "TT_en_test_msg_applysettings.py::test_apply_homescreen_jpeg": "0e2a71ac60add6bebc03645b6f4f6f19abdba56f1e55e799479b116e5a66aef6", "TT_en_test_msg_applysettings.py::test_apply_homescreen_jpeg_progressive": "4d7c67024ee17436071e5cf2f79c36453249c95314a732580623cb1f1cdbfdf3", "TT_en_test_msg_applysettings.py::test_apply_homescreen_jpeg_wrong_size": "4d7c67024ee17436071e5cf2f79c36453249c95314a732580623cb1f1cdbfdf3",