From 7fa0682076873b467b47ea48a2f2d316ed4d2e46 Mon Sep 17 00:00:00 2001 From: foXaCe Date: Thu, 2 Oct 2025 18:39:42 +0200 Subject: [PATCH] feat: add multilingual support (EN/FR) for Stax/Flex Implement internationalization system with English and French translations: - New i18n system with 152 translated strings - Language setting in Settings menu with toggle - NVM storage for language preference - All NBGL UI strings externalized - Default language: English Supported languages: - English (default) - French Modified files: - 15 NBGL UI files updated to use i18n strings - Makefile updated to include i18n sources - Storage structure extended with language field --- .gitignore | 4 + Makefile | 2 +- src/i18n/i18n.c | 42 +++++ src/i18n/i18n.h | 191 +++++++++++++++++++++++ src/i18n/strings_en.c | 152 ++++++++++++++++++ src/i18n/strings_fr.c | 156 ++++++++++++++++++ src/nbgl/ui_blind_signing.c | 11 +- src/nbgl/ui_confirm_parameter_selector.c | 11 +- src/nbgl/ui_display_privacy.c | 9 +- src/nbgl/ui_get_eth2_public_key.c | 3 +- src/nbgl/ui_home.c | 72 ++++++--- src/nbgl/ui_no_7702.c | 11 +- src/nbgl/ui_no_7702_whitelist.c | 10 +- src/nbgl/ui_safe_account.c | 13 +- src/nbgl/ui_sign_712.c | 3 +- src/nbgl/ui_sign_authorization_7702.c | 15 +- src/nbgl/ui_sign_message.c | 5 +- src/nbgl/ui_sign_revocation_7702.c | 11 +- src/nbgl/ui_tx_simulation.c | 29 ++-- src/shared_context.h | 1 + 20 files changed, 667 insertions(+), 84 deletions(-) create mode 100644 src/i18n/i18n.c create mode 100644 src/i18n/i18n.h create mode 100644 src/i18n/strings_en.c create mode 100644 src/i18n/strings_fr.c diff --git a/.gitignore b/.gitignore index 87e05487f2..faef59c0d9 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,7 @@ report.html # LSP .cache/ + +# i18n implementation documentation +I18N_IMPLEMENTATION.md +I18N_TODO.md diff --git a/Makefile b/Makefile index f8eb3ff15b..af7efa1875 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ APPVERSION_P = 0 APPVERSION = $(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)-dev # Application source files -APP_SOURCE_PATH += src +APP_SOURCE_PATH += src src/i18n APP_SOURCE_FILES += $(filter-out ./ethereum-plugin-sdk/src/main.c, $(wildcard ./ethereum-plugin-sdk/src/*.c)) INCLUDES_PATH += ./ethereum-plugin-sdk/src diff --git a/src/i18n/i18n.c b/src/i18n/i18n.c new file mode 100644 index 0000000000..ee34846d1c --- /dev/null +++ b/src/i18n/i18n.c @@ -0,0 +1,42 @@ +#include "i18n.h" +#include "os.h" +#include "globals.h" + +// Import translation tables +extern const char *const g_strings_en[STR_COUNT]; +extern const char *const g_strings_fr[STR_COUNT]; + +// Array of all language tables +static const char *const *const g_language_tables[LANG_COUNT] = { + [LANG_ENGLISH] = g_strings_en, + [LANG_FRENCH] = g_strings_fr, +}; + +language_e i18n_get_language(void) { + // Read from NVM storage + language_e lang = N_storage.language; + + // Validate and return default if invalid + if (lang >= LANG_COUNT) { + return LANG_ENGLISH; + } + return lang; +} + +void i18n_set_language(language_e lang) { + if (lang < LANG_COUNT) { + nvm_write((void *) &N_storage.language, (void *) &lang, sizeof(lang)); + } +} + +const char *i18n_get_string(string_id_e id) { + language_e lang = i18n_get_language(); + + // Bounds checking + if (id >= STR_COUNT || lang >= LANG_COUNT) { + return "???"; + } + + const char *str = g_language_tables[lang][id]; + return (str != NULL) ? str : "???"; +} diff --git a/src/i18n/i18n.h b/src/i18n/i18n.h new file mode 100644 index 0000000000..a204b37f2a --- /dev/null +++ b/src/i18n/i18n.h @@ -0,0 +1,191 @@ +#ifndef I18N_H +#define I18N_H + +#include +#include + +// Supported languages +typedef enum { + LANG_ENGLISH = 0, + LANG_FRENCH = 1, + LANG_COUNT +} language_e; + +// String IDs for all translatable strings +typedef enum { + // Home & Settings + STR_APP_NAME = 0, + STR_VERSION, + STR_DEVELOPER, + STR_COPYRIGHT, + + // Settings switches + STR_BLIND_SIGNING, + STR_BLIND_SIGNING_DESC, + STR_NONCE, + STR_NONCE_DESC, + STR_RAW_MESSAGES, + STR_RAW_MESSAGES_DESC, + STR_SMART_ACCOUNTS, + STR_SMART_ACCOUNTS_DESC, + STR_SMART_ACCOUNTS_WALLET, + STR_SMART_ACCOUNTS_WALLET_DESC, + STR_DEBUG_CONTRACTS, + STR_DEBUG_CONTRACTS_DESC, + STR_DEBUG_CONTRACTS_WALLET, + STR_DEBUG_CONTRACTS_WALLET_DESC, + STR_TRANSACTION_CHECK, + STR_TRANSACTION_CHECK_DESC, + STR_TRANSACTION_HASH, + STR_TRANSACTION_HASH_DESC, + STR_TRANSACTION_HASH_DESC_WALLET, + STR_LANGUAGE, + STR_LANGUAGE_DESC, + + // Common UI actions + STR_SIGN, + STR_REJECT, + STR_APPROVE, + STR_REVIEW, + STR_VERIFY, + STR_CONFIRM, + STR_CANCEL, + STR_BACK_TO_SAFETY, + STR_GO_TO_SETTINGS, + STR_UNABLE_TO_SIGN, + + // Common labels + STR_MESSAGE, + STR_TRANSACTION, + STR_TYPED_MESSAGE, + STR_ACCOUNT, + STR_ADDRESS, + STR_KEY, + STR_AMOUNT, + STR_FROM, + STR_TO, + STR_MAX_FEES, + STR_NETWORK, + STR_CONTRACT, + STR_CONTRACT_ADDRESS, + STR_SMART_CONTRACT, + STR_SMART_CONTRACT_INFO, + STR_SMART_CONTRACT_OWNER, + STR_CONTRACT_OWNER, + STR_THRESHOLD, + STR_YOUR_ROLE, + STR_PARAMETER, + STR_SELECTOR, + STR_TX_HASH, + + // Transaction review + STR_REVIEW_MESSAGE, + STR_REVIEW_TYPED_MESSAGE, + STR_REVIEW_TRANSACTION, + STR_REVIEW_TRANSACTION_TO, + STR_SIGN_MESSAGE, + STR_SIGN_TYPED_MESSAGE, + STR_SIGN_TRANSACTION, + STR_SIGN_TRANSACTION_TO, + STR_SIGN_OPERATION, + STR_REJECT_TRANSACTION, + STR_REJECT_AUTHORIZATION, + STR_INTERACTION_WITH, + STR_DEPLOYED_ON, + STR_A_SMART_CONTRACT, + + // EIP-7702 Authorization + STR_DELEGATE_TO, + STR_DELEGATE_ON_NETWORK, + STR_ON_NETWORK, + STR_REVOKE_ON_NETWORK, + STR_REVIEW_AUTH_UPGRADE, + STR_SIGN_AUTH_UPGRADE, + STR_REVIEW_AUTH_REVOKE, + STR_SIGN_AUTH_REVOKE, + + // Status messages + STR_MESSAGE_SIGNED, + STR_MESSAGE_REJECTED, + STR_TRANSACTION_SIGNED, + STR_TRANSACTION_REJECTED, + + // Warnings & Errors + STR_WARNING, + STR_ERROR, + STR_BLIND_SIGNING_WARNING, + STR_BLIND_SIGNING_ERROR, + STR_BLIND_SIGNING_MUST_ENABLE, + STR_AUTH_CANNOT_BE_SIGNED, + STR_AUTH_NOT_IN_WHITELIST, + STR_ENABLE_SMART_ACCOUNT_SETTING, + + // Transaction Check + STR_ENABLE_TX_CHECK, + STR_TX_CHECK_DESC_LONG, + STR_TX_CHECK_TCS, + STR_TX_CHECK_ENABLED, + STR_YES_ENABLE, + STR_MAYBE_LATER, + STR_HOW_IT_WORKS, + STR_TX_CHECK_INFO_1, + STR_TX_CHECK_INFO_2, + STR_TX_CHECK_INFO_3, + STR_ACCEPT_RISK_AND_SIGN, + STR_ACCEPT_THREAT_AND_SIGN, + + // Safe Account + STR_SIGNER_N, + STR_SAFE_ADDRESS_VALIDATED, + STR_SAFE_ADDRESS_REJECTED, + STR_VERIFY_SAFE_ADDRESS, + + // Privacy keys + STR_PROVIDE_PRIVACY_KEY, + STR_PROVIDE_SECRET_KEY, + + // ETH2 + STR_VERIFY_ETH2_ADDRESS, + + // Etherscan + STR_SCAN_ETHERSCAN, + + // Confirm selector/parameter + STR_VERIFY_FMT, + STR_CONFIRM_FMT, + + // Plugin format string + STR_PLUGIN_TAGLINE_FMT, + + // Must be last + STR_COUNT +} string_id_e; + +/** + * Get the current language setting + * + * @return Current language enum value + */ +language_e i18n_get_language(void); + +/** + * Set the current language + * + * @param[in] lang Language to set + */ +void i18n_set_language(language_e lang); + +/** + * Get a translated string by ID + * + * @param[in] id String ID + * @return Pointer to translated string (never NULL) + */ +const char *i18n_get_string(string_id_e id); + +/** + * Convenience macro for getting strings + */ +#define STR(id) i18n_get_string(STR_##id) + +#endif // I18N_H diff --git a/src/i18n/strings_en.c b/src/i18n/strings_en.c new file mode 100644 index 0000000000..197781b878 --- /dev/null +++ b/src/i18n/strings_en.c @@ -0,0 +1,152 @@ +#include "i18n.h" + +const char *const g_strings_en[STR_COUNT] = { + // Home & Settings + [STR_APP_NAME] = "Ethereum", + [STR_VERSION] = "Version", + [STR_DEVELOPER] = "Developer", + [STR_COPYRIGHT] = "Ledger (c) 2025", + + // Settings switches + [STR_BLIND_SIGNING] = "Blind signing", + [STR_BLIND_SIGNING_DESC] = "Enable transaction blind signing", + [STR_NONCE] = "Nonce", + [STR_NONCE_DESC] = "Display nonce in transactions", + [STR_RAW_MESSAGES] = "Raw messages", + [STR_RAW_MESSAGES_DESC] = "Displays raw content of EIP712 messages", + [STR_SMART_ACCOUNTS] = "Smart accounts", + [STR_SMART_ACCOUNTS_DESC] = "Enable EIP-7702 authorizations", + [STR_SMART_ACCOUNTS_WALLET] = "Smart account upgrade", + [STR_SMART_ACCOUNTS_WALLET_DESC] = "Enable EIP-7702 authorizations for smart contract delegation", + [STR_DEBUG_CONTRACTS] = "Debug contracts", + [STR_DEBUG_CONTRACTS_DESC] = "Display contract\ndata details", + [STR_DEBUG_CONTRACTS_WALLET] = "Debug smart contracts", + [STR_DEBUG_CONTRACTS_WALLET_DESC] = "Display contract data details", + [STR_TRANSACTION_CHECK] = "Transaction Check", + [STR_TRANSACTION_CHECK_DESC] = + "Get real-time warnings about risky transactions. Learn more: ledger.com/tx-check", + [STR_TRANSACTION_HASH] = "Transaction hash", + [STR_TRANSACTION_HASH_DESC] = "Always display the transaction hash", + [STR_TRANSACTION_HASH_DESC_WALLET] = "Always display the transaction or message hash", + [STR_LANGUAGE] = "Language", + [STR_LANGUAGE_DESC] = "Change interface language", + + // Common UI actions + [STR_SIGN] = "Sign", + [STR_REJECT] = "Reject", + [STR_APPROVE] = "Approve", + [STR_REVIEW] = "Review", + [STR_VERIFY] = "Verify", + [STR_CONFIRM] = "Confirm", + [STR_CANCEL] = "Cancel", + [STR_BACK_TO_SAFETY] = "Back to safety", + [STR_GO_TO_SETTINGS] = "Go to settings", + [STR_UNABLE_TO_SIGN] = "Unable to sign", + + // Common labels + [STR_MESSAGE] = "Message", + [STR_TRANSACTION] = "Transaction", + [STR_TYPED_MESSAGE] = "typed message", + [STR_ACCOUNT] = "Account", + [STR_ADDRESS] = "Address", + [STR_KEY] = "Key", + [STR_AMOUNT] = "Amount", + [STR_FROM] = "From", + [STR_TO] = "To", + [STR_MAX_FEES] = "Max fees", + [STR_NETWORK] = "Network", + [STR_CONTRACT] = "Contract", + [STR_CONTRACT_ADDRESS] = "Contract address", + [STR_SMART_CONTRACT] = "Smart contract", + [STR_SMART_CONTRACT_INFO] = "Smart contract information", + [STR_SMART_CONTRACT_OWNER] = "Smart contract owner", + [STR_CONTRACT_OWNER] = "Contract owner", + [STR_THRESHOLD] = "Threshold", + [STR_YOUR_ROLE] = "Your role", + [STR_PARAMETER] = "Parameter", + [STR_SELECTOR] = "Selector", + [STR_TX_HASH] = "Tx hash", + + // Transaction review + [STR_REVIEW_MESSAGE] = "Review message", + [STR_REVIEW_TYPED_MESSAGE] = "Review typed message", + [STR_REVIEW_TRANSACTION] = "Review transaction", + [STR_REVIEW_TRANSACTION_TO] = "Review transaction to %s", + [STR_SIGN_MESSAGE] = "Sign message", + [STR_SIGN_TYPED_MESSAGE] = "Sign typed message", + [STR_SIGN_TRANSACTION] = "Sign transaction", + [STR_SIGN_TRANSACTION_TO] = "Sign transaction to %s?", + [STR_SIGN_OPERATION] = "Sign operation", + [STR_REJECT_TRANSACTION] = "Reject transaction", + [STR_REJECT_AUTHORIZATION] = "Reject authorization", + [STR_INTERACTION_WITH] = "Interaction with", + [STR_DEPLOYED_ON] = "Deployed on", + [STR_A_SMART_CONTRACT] = "a smart contract", + + // EIP-7702 Authorization + [STR_DELEGATE_TO] = "Delegate to", + [STR_DELEGATE_ON_NETWORK] = "Delegate on network", + [STR_ON_NETWORK] = "On network", + [STR_REVOKE_ON_NETWORK] = "Revoke on network", + [STR_REVIEW_AUTH_UPGRADE] = "Review authorization to upgrade into smart contract account?", + [STR_SIGN_AUTH_UPGRADE] = "Sign authorization to upgrade into smart contract account?", + [STR_REVIEW_AUTH_REVOKE] = "Review authorization to revoke smart contract delegation?", + [STR_SIGN_AUTH_REVOKE] = "Sign authorization to revoke smart contract delegation?", + + // Status messages + [STR_MESSAGE_SIGNED] = "Message signed", + [STR_MESSAGE_REJECTED] = "Message rejected", + [STR_TRANSACTION_SIGNED] = "Transaction signed", + [STR_TRANSACTION_REJECTED] = "Transaction rejected", + + // Warnings & Errors + [STR_WARNING] = "Warning", + [STR_ERROR] = "Error", + [STR_BLIND_SIGNING_WARNING] = "This transaction cannot be clear-signed", + [STR_BLIND_SIGNING_ERROR] = "Enable blind signing in the settings to sign this transaction.", + [STR_BLIND_SIGNING_MUST_ENABLE] = "Blind signing must\nbe enabled in\nsettings", + [STR_AUTH_CANNOT_BE_SIGNED] = "This authorization cannot be signed", + [STR_AUTH_NOT_IN_WHITELIST] = + "This authorization involves a delegation to a smart contract which is not in the whitelist.", + [STR_ENABLE_SMART_ACCOUNT_SETTING] = + "Enable smart account upgrade in the settings to sign this authorization.", + + // Transaction Check + [STR_ENABLE_TX_CHECK] = "Enable\nTransaction Check?", + [STR_TX_CHECK_DESC_LONG] = + "Get real-time warnings about risky Ethereum transactions. Powered by service providers.", + [STR_TX_CHECK_TCS] = "By enabling, you accept T&Cs: ledger.com/tx-check", + [STR_TX_CHECK_ENABLED] = "Transaction Check enabled", + [STR_YES_ENABLE] = "Yes, enable", + [STR_MAYBE_LATER] = "Maybe later", + [STR_HOW_IT_WORKS] = "How it works", + [STR_TX_CHECK_INFO_1] = "Transaction is checked for threats before signing.", + [STR_TX_CHECK_INFO_2] = "The result is displayed: Critical threat, potential risk or no threat.", + [STR_TX_CHECK_INFO_3] = + "Scan the QR Code on your Ledger device for details on any threat or risk.", + [STR_ACCEPT_RISK_AND_SIGN] = "Accept risk and sign", + [STR_ACCEPT_THREAT_AND_SIGN] = "Accept threat and sign", + + // Safe Account + [STR_SIGNER_N] = "Signer %d", + [STR_SAFE_ADDRESS_VALIDATED] = "Safe Address validated", + [STR_SAFE_ADDRESS_REJECTED] = "Safe Address rejected", + [STR_VERIFY_SAFE_ADDRESS] = "Verify Safe address", + + // Privacy keys + [STR_PROVIDE_PRIVACY_KEY] = "Provide public\nprivacy key", + [STR_PROVIDE_SECRET_KEY] = "Provide public\nsecret key", + + // ETH2 + [STR_VERIFY_ETH2_ADDRESS] = "Verify ETH2\naddress", + + // Etherscan + [STR_SCAN_ETHERSCAN] = "Scan to view on Etherscan", + + // Confirm selector/parameter + [STR_VERIFY_FMT] = "Verify %s", + [STR_CONFIRM_FMT] = "Confirm %s", + + // Plugin format string + [STR_PLUGIN_TAGLINE_FMT] = "This app enables clear\nsigning transactions for\nthe %s dApp.", +}; diff --git a/src/i18n/strings_fr.c b/src/i18n/strings_fr.c new file mode 100644 index 0000000000..44c1569dfd --- /dev/null +++ b/src/i18n/strings_fr.c @@ -0,0 +1,156 @@ +#include "i18n.h" + +const char *const g_strings_fr[STR_COUNT] = { + // Home & Settings + [STR_APP_NAME] = "Ethereum", + [STR_VERSION] = "Version", + [STR_DEVELOPER] = "Développeur", + [STR_COPYRIGHT] = "Ledger (c) 2025", + + // Settings switches + [STR_BLIND_SIGNING] = "Signature aveugle", + [STR_BLIND_SIGNING_DESC] = "Activer la signature aveugle des transactions", + [STR_NONCE] = "Nonce", + [STR_NONCE_DESC] = "Afficher le nonce dans les transactions", + [STR_RAW_MESSAGES] = "Messages bruts", + [STR_RAW_MESSAGES_DESC] = "Affiche le contenu brut des messages EIP712", + [STR_SMART_ACCOUNTS] = "Comptes intelligents", + [STR_SMART_ACCOUNTS_DESC] = "Activer les autorisations EIP-7702", + [STR_SMART_ACCOUNTS_WALLET] = "Mise à niveau compte intelligent", + [STR_SMART_ACCOUNTS_WALLET_DESC] = + "Activer les autorisations EIP-7702 pour la délégation de contrats intelligents", + [STR_DEBUG_CONTRACTS] = "Déboguer contrats", + [STR_DEBUG_CONTRACTS_DESC] = "Afficher les détails\ndes contrats", + [STR_DEBUG_CONTRACTS_WALLET] = "Déboguer contrats intelligents", + [STR_DEBUG_CONTRACTS_WALLET_DESC] = "Afficher les détails des données contractuelles", + [STR_TRANSACTION_CHECK] = "Vérification de transaction", + [STR_TRANSACTION_CHECK_DESC] = + "Recevez des alertes en temps réel sur les transactions risquées. En savoir plus : ledger.com/tx-check", + [STR_TRANSACTION_HASH] = "Hash de transaction", + [STR_TRANSACTION_HASH_DESC] = "Toujours afficher le hash de transaction", + [STR_TRANSACTION_HASH_DESC_WALLET] = "Toujours afficher le hash de transaction ou message", + [STR_LANGUAGE] = "Langue", + [STR_LANGUAGE_DESC] = "Changer la langue de l'interface", + + // Common UI actions + [STR_SIGN] = "Signer", + [STR_REJECT] = "Rejeter", + [STR_APPROVE] = "Approuver", + [STR_REVIEW] = "Vérifier", + [STR_VERIFY] = "Vérifier", + [STR_CONFIRM] = "Confirmer", + [STR_CANCEL] = "Annuler", + [STR_BACK_TO_SAFETY] = "Retour en sécurité", + [STR_GO_TO_SETTINGS] = "Aller aux paramètres", + [STR_UNABLE_TO_SIGN] = "Impossible de signer", + + // Common labels + [STR_MESSAGE] = "Message", + [STR_TRANSACTION] = "Transaction", + [STR_TYPED_MESSAGE] = "message typé", + [STR_ACCOUNT] = "Compte", + [STR_ADDRESS] = "Adresse", + [STR_KEY] = "Clé", + [STR_AMOUNT] = "Montant", + [STR_FROM] = "De", + [STR_TO] = "À", + [STR_MAX_FEES] = "Frais max", + [STR_NETWORK] = "Réseau", + [STR_CONTRACT] = "Contrat", + [STR_CONTRACT_ADDRESS] = "Adresse du contrat", + [STR_SMART_CONTRACT] = "Contrat intelligent", + [STR_SMART_CONTRACT_INFO] = "Informations contrat intelligent", + [STR_SMART_CONTRACT_OWNER] = "Propriétaire du contrat intelligent", + [STR_CONTRACT_OWNER] = "Propriétaire du contrat", + [STR_THRESHOLD] = "Seuil", + [STR_YOUR_ROLE] = "Votre rôle", + [STR_PARAMETER] = "Paramètre", + [STR_SELECTOR] = "Sélecteur", + [STR_TX_HASH] = "Hash tx", + + // Transaction review + [STR_REVIEW_MESSAGE] = "Vérifier le message", + [STR_REVIEW_TYPED_MESSAGE] = "Vérifier le message typé", + [STR_REVIEW_TRANSACTION] = "Vérifier la transaction", + [STR_REVIEW_TRANSACTION_TO] = "Vérifier la transaction vers %s", + [STR_SIGN_MESSAGE] = "Signer le message", + [STR_SIGN_TYPED_MESSAGE] = "Signer le message typé", + [STR_SIGN_TRANSACTION] = "Signer la transaction", + [STR_SIGN_TRANSACTION_TO] = "Signer la transaction vers %s ?", + [STR_SIGN_OPERATION] = "Signer l'opération", + [STR_REJECT_TRANSACTION] = "Rejeter la transaction", + [STR_REJECT_AUTHORIZATION] = "Rejeter l'autorisation", + [STR_INTERACTION_WITH] = "Interaction avec", + [STR_DEPLOYED_ON] = "Déployé sur", + [STR_A_SMART_CONTRACT] = "un contrat intelligent", + + // EIP-7702 Authorization + [STR_DELEGATE_TO] = "Déléguer à", + [STR_DELEGATE_ON_NETWORK] = "Déléguer sur le réseau", + [STR_ON_NETWORK] = "Sur le réseau", + [STR_REVOKE_ON_NETWORK] = "Révoquer sur le réseau", + [STR_REVIEW_AUTH_UPGRADE] = + "Vérifier l'autorisation de mise à niveau en compte de contrat intelligent ?", + [STR_SIGN_AUTH_UPGRADE] = + "Signer l'autorisation de mise à niveau en compte de contrat intelligent ?", + [STR_REVIEW_AUTH_REVOKE] = "Vérifier l'autorisation de révocation de délégation de contrat intelligent ?", + [STR_SIGN_AUTH_REVOKE] = "Signer l'autorisation de révocation de délégation de contrat intelligent ?", + + // Status messages + [STR_MESSAGE_SIGNED] = "Message signé", + [STR_MESSAGE_REJECTED] = "Message rejeté", + [STR_TRANSACTION_SIGNED] = "Transaction signée", + [STR_TRANSACTION_REJECTED] = "Transaction rejetée", + + // Warnings & Errors + [STR_WARNING] = "Avertissement", + [STR_ERROR] = "Erreur", + [STR_BLIND_SIGNING_WARNING] = "Cette transaction ne peut pas être signée clairement", + [STR_BLIND_SIGNING_ERROR] = "Activez la signature aveugle dans les paramètres pour signer cette transaction.", + [STR_BLIND_SIGNING_MUST_ENABLE] = "La signature aveugle\ndoit être activée\ndans les paramètres", + [STR_AUTH_CANNOT_BE_SIGNED] = "Cette autorisation ne peut pas être signée", + [STR_AUTH_NOT_IN_WHITELIST] = + "Cette autorisation implique une délégation à un contrat intelligent qui n'est pas dans la liste blanche.", + [STR_ENABLE_SMART_ACCOUNT_SETTING] = + "Activez la mise à niveau de compte intelligent dans les paramètres pour signer cette autorisation.", + + // Transaction Check + [STR_ENABLE_TX_CHECK] = "Activer la\nVérification de transaction ?", + [STR_TX_CHECK_DESC_LONG] = + "Recevez des alertes en temps réel sur les transactions Ethereum risquées. Fourni par des prestataires de services.", + [STR_TX_CHECK_TCS] = "En activant, vous acceptez les CGU : ledger.com/tx-check", + [STR_TX_CHECK_ENABLED] = "Vérification de transaction activée", + [STR_YES_ENABLE] = "Oui, activer", + [STR_MAYBE_LATER] = "Peut-être plus tard", + [STR_HOW_IT_WORKS] = "Comment ça marche", + [STR_TX_CHECK_INFO_1] = "La transaction est vérifiée avant la signature.", + [STR_TX_CHECK_INFO_2] = "Le résultat est affiché : Menace critique, risque potentiel ou aucune menace.", + [STR_TX_CHECK_INFO_3] = + "Scannez le QR Code sur votre Ledger pour les détails sur toute menace ou risque.", + [STR_ACCEPT_RISK_AND_SIGN] = "Accepter le risque et signer", + [STR_ACCEPT_THREAT_AND_SIGN] = "Accepter la menace et signer", + + // Safe Account + [STR_SIGNER_N] = "Signataire %d", + [STR_SAFE_ADDRESS_VALIDATED] = "Adresse Safe validée", + [STR_SAFE_ADDRESS_REJECTED] = "Adresse Safe rejetée", + [STR_VERIFY_SAFE_ADDRESS] = "Vérifier l'adresse Safe", + + // Privacy keys + [STR_PROVIDE_PRIVACY_KEY] = "Fournir la clé\npublique de confidentialité", + [STR_PROVIDE_SECRET_KEY] = "Fournir la clé\npublique secrète", + + // ETH2 + [STR_VERIFY_ETH2_ADDRESS] = "Vérifier l'adresse\nETH2", + + // Etherscan + [STR_SCAN_ETHERSCAN] = "Scanner pour voir sur Etherscan", + + // Confirm selector/parameter + [STR_VERIFY_FMT] = "Vérifier %s", + [STR_CONFIRM_FMT] = "Confirmer %s", + + // Plugin format string + [STR_PLUGIN_TAGLINE_FMT] = + "Cette app permet la signature\nclaire de transactions pour\nla dApp %s.", +}; diff --git a/src/nbgl/ui_blind_signing.c b/src/nbgl/ui_blind_signing.c index 7d43259c62..d5513ef65e 100644 --- a/src/nbgl/ui_blind_signing.c +++ b/src/nbgl/ui_blind_signing.c @@ -1,4 +1,5 @@ #include "ui_nbgl.h" +#include "i18n/i18n.h" #ifdef SCREEN_SIZE_WALLET static void ui_error_blind_signing_choice(bool confirm) { @@ -13,14 +14,14 @@ static void ui_error_blind_signing_choice(bool confirm) { void ui_error_blind_signing(void) { #ifdef SCREEN_SIZE_WALLET nbgl_useCaseChoice(&ICON_APP_WARNING, - "This transaction cannot be clear-signed", - "Enable blind signing in the settings to sign this transaction.", - "Go to settings", - "Reject transaction", + STR(BLIND_SIGNING_WARNING), + STR(BLIND_SIGNING_ERROR), + STR(GO_TO_SETTINGS), + STR(REJECT_TRANSACTION), ui_error_blind_signing_choice); #else nbgl_useCaseAction(&C_Alert_circle_14px, - "Blind signing must\nbe enabled in\nsettings", + STR(BLIND_SIGNING_MUST_ENABLE), NULL, ui_idle); #endif diff --git a/src/nbgl/ui_confirm_parameter_selector.c b/src/nbgl/ui_confirm_parameter_selector.c index 5eaa7cd9fe..5047b801b7 100644 --- a/src/nbgl/ui_confirm_parameter_selector.c +++ b/src/nbgl/ui_confirm_parameter_selector.c @@ -1,6 +1,7 @@ #include "ui_nbgl.h" #include "ui_callbacks.h" #include "ui_utils.h" +#include "i18n/i18n.h" #define TITLE_MSG_LEN 20 #define FINISH_MSG_LEN 20 @@ -30,18 +31,18 @@ static void buildScreen(e_confirmation_type confirm_type) { return; } - g_pairs->item = (confirm_type == PARAMETER_CONFIRMATION) ? "Parameter" : "Selector"; + g_pairs->item = (confirm_type == PARAMETER_CONFIRMATION) ? STR(PARAMETER) : STR(SELECTOR); g_pairs->value = strings.tmp.tmp; snprintf(g_titleMsg, TITLE_MSG_LEN, - "Verify %s", - (confirm_type == PARAMETER_CONFIRMATION) ? "parameter" : "selector"); + STR(VERIFY_FMT), + (confirm_type == PARAMETER_CONFIRMATION) ? STR(PARAMETER) : STR(SELECTOR)); // Finish text: replace "Verify" by "Confirm" snprintf(g_finishMsg, FINISH_MSG_LEN, - "Confirm %s", - (confirm_type == PARAMETER_CONFIRMATION) ? "parameter" : "selector"); + STR(CONFIRM_FMT), + (confirm_type == PARAMETER_CONFIRMATION) ? STR(PARAMETER) : STR(SELECTOR)); if (tmpContent.txContent.dataPresent) { op |= BLIND_OPERATION; diff --git a/src/nbgl/ui_display_privacy.c b/src/nbgl/ui_display_privacy.c index ed44c7b42a..5dd803acf7 100644 --- a/src/nbgl/ui_display_privacy.c +++ b/src/nbgl/ui_display_privacy.c @@ -1,6 +1,7 @@ #include "ui_nbgl.h" #include "ui_callbacks.h" #include "ui_utils.h" +#include "i18n/i18n.h" static void reviewChoice(bool confirm) { if (confirm) { @@ -18,9 +19,9 @@ static void buildFirstPage(const char *review_string) { return; } - g_pairs[0].item = "Address"; + g_pairs[0].item = STR(ADDRESS); g_pairs[0].value = strings.common.toAddress; - g_pairs[1].item = "Key"; + g_pairs[1].item = STR(KEY); g_pairs[1].value = strings.common.fullAmount; nbgl_useCaseReview(TYPE_OPERATION, @@ -33,9 +34,9 @@ static void buildFirstPage(const char *review_string) { } void ui_display_privacy_public_key(void) { - buildFirstPage("Provide public\nprivacy key"); + buildFirstPage(STR(PROVIDE_PRIVACY_KEY)); } void ui_display_privacy_shared_secret(void) { - buildFirstPage("Provide public\nsecret key"); + buildFirstPage(STR(PROVIDE_SECRET_KEY)); } diff --git a/src/nbgl/ui_get_eth2_public_key.c b/src/nbgl/ui_get_eth2_public_key.c index 0371fccbb5..fe31f430cb 100644 --- a/src/nbgl/ui_get_eth2_public_key.c +++ b/src/nbgl/ui_get_eth2_public_key.c @@ -2,6 +2,7 @@ #include "ui_callbacks.h" #include "ui_nbgl.h" #include "ui_utils.h" +#include "i18n/i18n.h" #define ETH2_ADDRESS_LENGTH 48 #define ETH2_ADDRESS_STR (ETH2_ADDRESS_LENGTH * 2 + 3) // '0x' + 48 bytes * 2 hex chars + '\0' @@ -18,7 +19,7 @@ static void reviewChoice(bool confirm) { } void ui_display_public_eth2(void) { - const char *title = "Verify ETH2\naddress"; + const char *title = STR(VERIFY_ETH2_ADDRESS); uint8_t title_len = 1; // Initialize lengths to 1 for '\0' character // Compute the title message length diff --git a/src/nbgl/ui_home.c b/src/nbgl/ui_home.c index e448ca0eed..8cf4935544 100644 --- a/src/nbgl/ui_home.c +++ b/src/nbgl/ui_home.c @@ -4,6 +4,7 @@ #include "network.h" #include "cmd_get_tx_simulation.h" #include "mem_utils.h" +#include "i18n/i18n.h" // Global Warning struct for NBGL review flows nbgl_warning_t warning; @@ -25,6 +26,7 @@ enum { EIP7702_TOKEN, DEBUG_TOKEN, HASH_TOKEN, + LANGUAGE_TOKEN, }; enum { @@ -37,12 +39,13 @@ enum { DEBUG_ID, EIP7702_ID, HASH_ID, + LANGUAGE_ID, SETTINGS_SWITCHES_NB }; // settings definition -static const char *const infoTypes[SETTING_INFO_NB] = {"Version", "Developer", "Copyright"}; -static const char *const infoContents[SETTING_INFO_NB] = {APPVERSION, "Ledger", "Ledger (c) 2025"}; +static const char *infoTypes[SETTING_INFO_NB]; +static const char *infoContents[SETTING_INFO_NB]; static nbgl_contentInfoList_t infoList = {0}; static nbgl_contentSwitch_t switches[SETTINGS_SWITCHES_NB] = {0}; @@ -96,6 +99,15 @@ static void setting_toggle_callback(int token, uint8_t index, int page) { switches[HASH_ID].initState = (nbgl_state_t) value; nvm_write((void *) &N_storage.displayHash, (void *) &value, sizeof(value)); break; + case LANGUAGE_TOKEN: { + language_e lang = i18n_get_language(); + lang = (lang == LANG_ENGLISH) ? LANG_FRENCH : LANG_ENGLISH; + i18n_set_language(lang); + switches[LANGUAGE_ID].initState = (lang == LANG_FRENCH) ? ON_STATE : OFF_STATE; + // Refresh the entire UI to apply language change + ui_idle(); + break; + } } } @@ -139,25 +151,33 @@ static const nbgl_icon_details_t *get_home_icon(void) { * @param[in] page to start on */ static void prepare_and_display_home(const char *appname, const char *tagline, uint8_t page) { + // Initialize info fields with translated strings + infoTypes[0] = STR(VERSION); + infoTypes[1] = STR(DEVELOPER); + infoTypes[2] = STR(COPYRIGHT); + infoContents[0] = APPVERSION; + infoContents[1] = "Ledger"; + infoContents[2] = STR(COPYRIGHT); + switches[BLIND_SIGNING_ID].initState = N_storage.dataAllowed ? ON_STATE : OFF_STATE; - switches[BLIND_SIGNING_ID].text = "Blind signing"; - switches[BLIND_SIGNING_ID].subText = "Enable transaction blind signing"; + switches[BLIND_SIGNING_ID].text = STR(BLIND_SIGNING); + switches[BLIND_SIGNING_ID].subText = STR(BLIND_SIGNING_DESC); switches[BLIND_SIGNING_ID].token = BLIND_SIGNING_TOKEN; #ifdef HAVE_PIEZO_SOUND switches[BLIND_SIGNING_ID].tuneId = TUNE_TAP_CASUAL; #endif switches[NONCE_ID].initState = N_storage.displayNonce ? ON_STATE : OFF_STATE; - switches[NONCE_ID].text = "Nonce"; - switches[NONCE_ID].subText = "Display nonce in transactions"; + switches[NONCE_ID].text = STR(NONCE); + switches[NONCE_ID].subText = STR(NONCE_DESC); switches[NONCE_ID].token = NONCE_TOKEN; #ifdef HAVE_PIEZO_SOUND switches[NONCE_ID].tuneId = TUNE_TAP_CASUAL; #endif switches[EIP712_VERBOSE_ID].initState = N_storage.verbose_eip712 ? ON_STATE : OFF_STATE; - switches[EIP712_VERBOSE_ID].text = "Raw messages"; - switches[EIP712_VERBOSE_ID].subText = "Displays raw content of EIP712 messages"; + switches[EIP712_VERBOSE_ID].text = STR(RAW_MESSAGES); + switches[EIP712_VERBOSE_ID].subText = STR(RAW_MESSAGES_DESC); switches[EIP712_VERBOSE_ID].token = EIP712_VERBOSE_TOKEN; #ifdef HAVE_PIEZO_SOUND switches[EIP712_VERBOSE_ID].tuneId = TUNE_TAP_CASUAL; @@ -165,11 +185,11 @@ static void prepare_and_display_home(const char *appname, const char *tagline, u switches[EIP7702_ID].initState = N_storage.eip7702_enable ? ON_STATE : OFF_STATE; #ifdef SCREEN_SIZE_WALLET - switches[EIP7702_ID].text = "Smart account upgrade"; - switches[EIP7702_ID].subText = "Enable EIP-7702 authorizations for smart contract delegation"; + switches[EIP7702_ID].text = STR(SMART_ACCOUNTS_WALLET); + switches[EIP7702_ID].subText = STR(SMART_ACCOUNTS_WALLET_DESC); #else - switches[EIP7702_ID].text = "Smart accounts"; - switches[EIP7702_ID].subText = "Enable EIP-7702 authorizations"; + switches[EIP7702_ID].text = STR(SMART_ACCOUNTS); + switches[EIP7702_ID].subText = STR(SMART_ACCOUNTS_DESC); #endif switches[EIP7702_ID].token = EIP7702_TOKEN; #ifdef HAVE_PIEZO_SOUND @@ -178,11 +198,11 @@ static void prepare_and_display_home(const char *appname, const char *tagline, u switches[DEBUG_ID].initState = N_storage.contractDetails ? ON_STATE : OFF_STATE; #ifdef SCREEN_SIZE_WALLET - switches[DEBUG_ID].text = "Debug smart contracts"; - switches[DEBUG_ID].subText = "Display contract data details"; + switches[DEBUG_ID].text = STR(DEBUG_CONTRACTS_WALLET); + switches[DEBUG_ID].subText = STR(DEBUG_CONTRACTS_WALLET_DESC); #else - switches[DEBUG_ID].text = "Debug contracts"; - switches[DEBUG_ID].subText = "Display contract\ndata details"; + switches[DEBUG_ID].text = STR(DEBUG_CONTRACTS); + switches[DEBUG_ID].subText = STR(DEBUG_CONTRACTS_DESC); #endif switches[DEBUG_ID].token = DEBUG_TOKEN; #ifdef HAVE_PIEZO_SOUND @@ -191,25 +211,33 @@ static void prepare_and_display_home(const char *appname, const char *tagline, u #ifdef HAVE_TRANSACTION_CHECKS switches[TRANSACTION_CHECKS_ID].initState = N_storage.tx_check_enable ? ON_STATE : OFF_STATE; - switches[TRANSACTION_CHECKS_ID].text = "Transaction Check"; - switches[TRANSACTION_CHECKS_ID].subText = - "Get real-time warnings about risky transactions. Learn more: ledger.com/tx-check"; + switches[TRANSACTION_CHECKS_ID].text = STR(TRANSACTION_CHECK); + switches[TRANSACTION_CHECKS_ID].subText = STR(TRANSACTION_CHECK_DESC); switches[TRANSACTION_CHECKS_ID].token = TRANSACTION_CHECKS_TOKEN; switches[TRANSACTION_CHECKS_ID].tuneId = TUNE_TAP_CASUAL; #endif // HAVE_TRANSACTION_CHECKS switches[HASH_ID].initState = N_storage.displayHash ? ON_STATE : OFF_STATE; - switches[HASH_ID].text = "Transaction hash"; + switches[HASH_ID].text = STR(TRANSACTION_HASH); #ifdef SCREEN_SIZE_WALLET - switches[HASH_ID].subText = "Always display the transaction or message hash"; + switches[HASH_ID].subText = STR(TRANSACTION_HASH_DESC_WALLET); #else - switches[HASH_ID].subText = "Always display the transaction hash"; + switches[HASH_ID].subText = STR(TRANSACTION_HASH_DESC); #endif switches[HASH_ID].token = HASH_TOKEN; #ifdef HAVE_PIEZO_SOUND switches[HASH_ID].tuneId = TUNE_TAP_CASUAL; #endif + switches[LANGUAGE_ID].initState = + (i18n_get_language() == LANG_FRENCH) ? ON_STATE : OFF_STATE; + switches[LANGUAGE_ID].text = "Language / Langue"; + switches[LANGUAGE_ID].subText = "English / Français"; + switches[LANGUAGE_ID].token = LANGUAGE_TOKEN; +#ifdef HAVE_PIEZO_SOUND + switches[LANGUAGE_ID].tuneId = TUNE_TAP_CASUAL; +#endif + contents[0].type = SWITCHES_LIST; contents[0].content.switchesList.nbSwitches = SETTINGS_SWITCHES_NB; contents[0].content.switchesList.switches = switches; diff --git a/src/nbgl/ui_no_7702.c b/src/nbgl/ui_no_7702.c index df5b1d1df4..1587d957a0 100644 --- a/src/nbgl/ui_no_7702.c +++ b/src/nbgl/ui_no_7702.c @@ -2,6 +2,7 @@ #include "shared_context.h" #include "ui_callbacks.h" #include "ui_nbgl.h" +#include "i18n/i18n.h" static void ui_error_no_7702_choice(bool confirm) { if (confirm) { @@ -14,12 +15,12 @@ static void ui_error_no_7702_choice(bool confirm) { void ui_error_no_7702(void) { nbgl_useCaseChoice(&ICON_APP_WARNING, #ifdef SCREEN_SIZE_WALLET - "This authorization cannot be signed", + STR(AUTH_CANNOT_BE_SIGNED), #else - "Unable to sign", + STR(UNABLE_TO_SIGN), #endif - "Enable smart account upgrade in the settings to sign this authorization.", - "Go to settings", - "Reject authorization", + STR(ENABLE_SMART_ACCOUNT_SETTING), + STR(GO_TO_SETTINGS), + STR(REJECT_AUTHORIZATION), ui_error_no_7702_choice); } diff --git a/src/nbgl/ui_no_7702_whitelist.c b/src/nbgl/ui_no_7702_whitelist.c index 228c8300a7..b9c5b9c122 100644 --- a/src/nbgl/ui_no_7702_whitelist.c +++ b/src/nbgl/ui_no_7702_whitelist.c @@ -2,6 +2,7 @@ #include "shared_context.h" #include "ui_callbacks.h" #include "ui_nbgl.h" +#include "i18n/i18n.h" static void ui_error_no_7702_whitelist_choice(bool confirm) { UNUSED(confirm); @@ -11,13 +12,12 @@ static void ui_error_no_7702_whitelist_choice(bool confirm) { void ui_error_no_7702_whitelist(void) { nbgl_useCaseChoice(&ICON_APP_WARNING, #ifdef SCREEN_SIZE_WALLET - "This authorization cannot be signed", + STR(AUTH_CANNOT_BE_SIGNED), #else - "Unable to sign", + STR(UNABLE_TO_SIGN), #endif - "This authorization involves a delegation to a smart contract which is not " - "in the whitelist.", - "Back to safety", + STR(AUTH_NOT_IN_WHITELIST), + STR(BACK_TO_SAFETY), "", ui_error_no_7702_whitelist_choice); } diff --git a/src/nbgl/ui_safe_account.c b/src/nbgl/ui_safe_account.c index 45860c1f11..90639335cb 100644 --- a/src/nbgl/ui_safe_account.c +++ b/src/nbgl/ui_safe_account.c @@ -7,6 +7,7 @@ #include "ui_nbgl.h" #include "ui_utils.h" #include "mem_utils.h" +#include "i18n/i18n.h" #define MAX_PAIRS 2 #define TAG_MAX_LEN 10 @@ -124,7 +125,7 @@ static void _prepare_strings(void) { // Populate tag strings ptr = signersInfo->tags.buffer; for (i = 0; i < SAFE_DESC->signers_count; i++) { - snprintf(ptr, TAG_MAX_LEN, "Signer %d", i + 1); + snprintf(ptr, TAG_MAX_LEN, STR(SIGNER_N), i + 1); signersInfo->tags.pointers[i] = ptr; ptr += TAG_MAX_LEN + 1; } @@ -146,11 +147,11 @@ static void setTagValuePairs(void) { uint8_t nbPairs = 0; uint16_t i = 0; - g_pairs[nbPairs].item = "Your role"; + g_pairs[nbPairs].item = STR(YOUR_ROLE); g_pairs[nbPairs].value = ROLE_STR(SAFE_DESC->role); nbPairs++; - g_pairs[nbPairs].item = "Threshold"; + g_pairs[nbPairs].item = STR(THRESHOLD); g_pairs[nbPairs].value = strings.tmp.tmp + ADDRESS_LENGTH_STR; g_pairs[nbPairs].aliasValue = 1; g_pairs[nbPairs].extension = &extensions[1]; @@ -174,12 +175,12 @@ static void review_cb(bool confirm) { if (confirm) { // User confirmed the Safe Account _cleanup(APDU_RESPONSE_OK); - nbgl_useCaseStatus("Safe Address validated", true, ui_idle); + nbgl_useCaseStatus(STR(SAFE_ADDRESS_VALIDATED), true, ui_idle); return; } else { // User rejected the Safe Account _cleanup(APDU_RESPONSE_CONDITION_NOT_SATISFIED); - nbgl_useCaseStatus("Safe Address rejected", false, ui_idle); + nbgl_useCaseStatus(STR(SAFE_ADDRESS_REJECTED), false, ui_idle); } } @@ -203,7 +204,7 @@ void ui_display_safe_account(void) { nbgl_useCaseAddressReview(strings.tmp.tmp, g_pairsList, &C_multisig, - "Verify Safe address", + STR(VERIFY_SAFE_ADDRESS), NULL, review_cb); } diff --git a/src/nbgl/ui_sign_712.c b/src/nbgl/ui_sign_712.c index d91e354e4a..85a6e1c830 100644 --- a/src/nbgl/ui_sign_712.c +++ b/src/nbgl/ui_sign_712.c @@ -6,6 +6,7 @@ #include "cmd_get_tx_simulation.h" #include "ui_utils.h" #include "mem_utils.h" +#include "i18n/i18n.h" /** * Trigger the EIP712 review flow @@ -39,7 +40,7 @@ static void ui_712_start_review(nbgl_operationType_t operationType, nbgl_useCaseAdvancedReview(operationType, g_pairsList, &ICON_APP_REVIEW, - "Review typed message", + STR(REVIEW_TYPED_MESSAGE), NULL, g_finishMsg, NULL, diff --git a/src/nbgl/ui_sign_authorization_7702.c b/src/nbgl/ui_sign_authorization_7702.c index d78031c2e0..afd354bd7b 100644 --- a/src/nbgl/ui_sign_authorization_7702.c +++ b/src/nbgl/ui_sign_authorization_7702.c @@ -5,6 +5,7 @@ #include "ui_nbgl.h" #include "common_ui.h" #include "ui_utils.h" +#include "i18n/i18n.h" static void review7702Choice(bool confirm) { if (confirm) { @@ -24,26 +25,26 @@ void ui_sign_7702_auth(void) { return; } - g_pairs[0].item = "Account"; + g_pairs[0].item = STR(ACCOUNT); g_pairs[0].value = strings.common.fromAddress; - g_pairs[1].item = "Delegate to"; + g_pairs[1].item = STR(DELEGATE_TO); g_pairs[1].value = strings.common.toAddress; #ifdef SCREEN_SIZE_WALLET - g_pairs[2].item = "Delegate on network"; + g_pairs[2].item = STR(DELEGATE_ON_NETWORK); #else - g_pairs[2].item = "On network"; + g_pairs[2].item = STR(ON_NETWORK); #endif g_pairs[2].value = strings.common.network_name; nbgl_useCaseReview(TYPE_OPERATION, g_pairsList, &ICON_APP_REVIEW, - "Review authorization to upgrade into smart contract account?", + STR(REVIEW_AUTH_UPGRADE), NULL, #ifdef SCREEN_SIZE_WALLET - "Sign authorization to upgrade into smart contract account?", + STR(SIGN_AUTH_UPGRADE), #else - "Sign operation", + STR(SIGN_OPERATION), #endif review7702Choice); } diff --git a/src/nbgl/ui_sign_message.c b/src/nbgl/ui_sign_message.c index 6c8352e6cd..e1428478a5 100644 --- a/src/nbgl/ui_sign_message.c +++ b/src/nbgl/ui_sign_message.c @@ -2,6 +2,7 @@ #include "ui_nbgl.h" #include "cmd_get_tx_simulation.h" #include "ui_utils.h" +#include "i18n/i18n.h" #define FINISH_MSG_LEN 32 // TODO Re-activate when partners are ready for eip191 @@ -45,13 +46,13 @@ void ui_191_start(const char *message) { ui_tx_simulation_finish_str()); g_pairsList->wrapping = true; - g_pairs->item = "Message"; + g_pairs->item = STR(MESSAGE); g_pairs->value = message; nbgl_useCaseAdvancedReview(TYPE_MESSAGE | SKIPPABLE_OPERATION, g_pairsList, &ICON_APP_REVIEW, - "Review message", + STR(REVIEW_MESSAGE), NULL, g_finishMsg, NULL, diff --git a/src/nbgl/ui_sign_revocation_7702.c b/src/nbgl/ui_sign_revocation_7702.c index 113250c55c..0e7af7f781 100644 --- a/src/nbgl/ui_sign_revocation_7702.c +++ b/src/nbgl/ui_sign_revocation_7702.c @@ -4,6 +4,7 @@ #include "nbgl_use_case.h" #include "common_ui.h" #include "ui_utils.h" +#include "i18n/i18n.h" static void review7702Choice(bool confirm) { if (confirm) { @@ -23,20 +24,20 @@ void ui_sign_7702_revocation(void) { return; } - g_pairs[0].item = "Account"; + g_pairs[0].item = STR(ACCOUNT); g_pairs[0].value = strings.common.fromAddress; - g_pairs[1].item = "Revoke on network"; + g_pairs[1].item = STR(REVOKE_ON_NETWORK); g_pairs[1].value = strings.common.network_name; nbgl_useCaseReview(TYPE_OPERATION, g_pairsList, &ICON_APP_REVIEW, - "Review authorization to revoke smart contract delegation?", + STR(REVIEW_AUTH_REVOKE), NULL, #ifdef SCREEN_SIZE_WALLET - "Sign authorization to revoke smart contract delegation?", + STR(SIGN_AUTH_REVOKE), #else - "Sign operation", + STR(SIGN_OPERATION), #endif review7702Choice); } diff --git a/src/nbgl/ui_tx_simulation.c b/src/nbgl/ui_tx_simulation.c index 5070ebddc6..b394b307cc 100644 --- a/src/nbgl/ui_tx_simulation.c +++ b/src/nbgl/ui_tx_simulation.c @@ -6,6 +6,7 @@ #include "ui_callbacks.h" #include "ui_callbacks.h" #include "cmd_get_tx_simulation.h" +#include "i18n/i18n.h" #ifdef HAVE_TRANSACTION_CHECKS @@ -48,9 +49,9 @@ static void ui_tx_simulation_explain(void) { layoutDescription.onActionCallback = opt_in_explain_cb; layoutCtx = nbgl_layoutGet(&layoutDescription); const char *rowTexts[HOW_TO_INFO_NB] = { - "Transaction is checked for threats before signing.", - "The result is displayed: Critical threat, potential risk or no threat.", - "Scan the QR Code on your Ledger device for details on any threat or risk.", + STR(TX_CHECK_INFO_1), + STR(TX_CHECK_INFO_2), + STR(TX_CHECK_INFO_3), }; const nbgl_icon_details_t *rowIcons[HOW_TO_INFO_NB] = { &PRIVACY_ICON, @@ -62,7 +63,7 @@ static void ui_tx_simulation_explain(void) { nbgl_layoutAddHeader(layoutCtx, &headerDesc); // add title - info.title = "How it works"; + info.title = STR(HOW_IT_WORKS); info.nbRows = HOW_TO_INFO_NB; info.rowTexts = rowTexts; info.rowIcons = rowIcons; @@ -80,7 +81,7 @@ static void ui_tx_simulation_explain(void) { */ static void finalise_opt_in(bool confirm, nbgl_callback_t callback) { if (confirm) { - nbgl_useCaseStatus("Transaction Check enabled", true, callback); + nbgl_useCaseStatus(STR(TX_CHECK_ENABLED), true, callback); } else { callback(); } @@ -131,8 +132,8 @@ void ui_tx_simulation_opt_in(bool response_expected) { nbgl_layout_t *layoutCtx = NULL; nbgl_layoutDescription_t layoutDescription = {0}; nbgl_contentCenter_t info = {0}; - nbgl_layoutChoiceButtons_t buttonsInfo = {.topText = "Yes, enable", - .bottomText = "Maybe later", + nbgl_layoutChoiceButtons_t buttonsInfo = {.topText = STR(YES_ENABLE), + .bottomText = STR(MAYBE_LATER), .token = WARNING_CHOICE_TOKEN, .style = ROUNDED_AND_FOOTER_STYLE, .tuneId = TUNE_TAP_CASUAL}; @@ -154,11 +155,9 @@ void ui_tx_simulation_opt_in(bool response_expected) { nbgl_layoutAddHeader(layoutCtx, &headerDesc); // add main content - info.title = "Enable\nTransaction Check?"; - info.description = - "Get real-time warnings about risky Ethereum transactions. " - "Powered by service providers."; - info.subText = "By enabling, you accept T&Cs: ledger.com/tx-check"; + info.title = STR(ENABLE_TX_CHECK); + info.description = STR(TX_CHECK_DESC_LONG); + info.subText = STR(TX_CHECK_TCS); nbgl_layoutAddContentCenter(layoutCtx, &info); // add button and footer on bottom @@ -180,11 +179,11 @@ void ui_tx_simulation_opt_in(bool response_expected) { */ const char *ui_tx_simulation_finish_str(void) { if (warning.predefinedSet & SET_BIT(W3C_THREAT_DETECTED_WARN)) { - return "Accept threat and sign"; + return STR(ACCEPT_THREAT_AND_SIGN); } if ((warning.predefinedSet & SET_BIT(W3C_RISK_DETECTED_WARN)) || (warning.predefinedSet & SET_BIT(BLIND_SIGNING_WARN))) { - return "Accept risk and sign"; + return STR(ACCEPT_RISK_AND_SIGN); } - return "Sign"; + return STR(SIGN); } diff --git a/src/shared_context.h b/src/shared_context.h index ee36b34487..fdee4c4e5a 100644 --- a/src/shared_context.h +++ b/src/shared_context.h @@ -27,6 +27,7 @@ typedef struct internalStorage_t { #endif bool eip7702_enable; bool displayHash; + uint8_t language; // language_e from i18n.h bool initialized; } internalStorage_t;