diff --git a/l10n.yaml b/l10n.yaml new file mode 100644 index 000000000..ecc8be829 --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,9 @@ +arb-dir: lib/l10n +template-arb-file: app_en.arb +output-localization-file: app_localizations.dart +untranslated-messages-file: untranslated_messages.json +output-class: AppLocalizations +preferred-supported-locales: ['en'] +use-deferred-loading: true +gen-inputs-and-outputs-list: outputs.json +synthetic-package: false \ No newline at end of file diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb new file mode 100644 index 000000000..10e018f72 --- /dev/null +++ b/lib/l10n/app_ar.arb @@ -0,0 +1,75 @@ +{ + "@@locale": "ar", + "appTitle": "Stack Wallet", + "@appTitle": { + "description": "The title of the application" + }, + "wallets": "المحافظ", + "@wallets": { + "description": "Label for the wallets section" + }, + "settings": "الإعدادات", + "@settings": { + "description": "Label for the settings section" + }, + "exchange": "التبادل", + "@exchange": { + "description": "Label for the exchange section" + }, + "buy": "شراء", + "@buy": { + "description": "Label for the buy section" + }, + "notifications": "الإشعارات", + "@notifications": { + "description": "Label for the notifications section" + }, + "continueButton": "متابعة", + "@continueButton": { + "description": "Continue button text" + }, + "welcomeTagline": "محفظة متعددة العملات مفتوحة المصدر للجميع", + "@welcomeTagline": { + "description": "Main tagline shown on welcome/intro screen" + }, + "getStartedButton": "ابدأ", + "@getStartedButton": { + "description": "Button text for starting wallet setup on mobile" + }, + "saveChanges": "حفظ التغييرات", + "@saveChanges": { + "description": "Save changes button text" + }, + "contractDetails": "تفاصيل العقد", + "@contractDetails": { + "description": "Contract details page title" + }, + "contractAddress": "عنوان العقد", + "@contractAddress": { + "description": "Label for contract address field" + }, + "name": "الاسم", + "@name": { + "description": "Label for name field" + }, + "youCanChangeItLaterInSettings": "يمكنك تغييره لاحقاً في الإعدادات", + "@youCanChangeItLaterInSettings": { + "description": "Informational text about changing settings later" + }, + "easyCrypto": "العملة المشفرة السهلة", + "@easyCrypto": { + "description": "Easy Crypto option label" + }, + "recommended": "موصى به", + "@recommended": { + "description": "Recommended option label" + }, + "incognito": "مجهول", + "@incognito": { + "description": "Incognito option label" + }, + "privacyConscious": "واعي بالخصوصية", + "@privacyConscious": { + "description": "Privacy conscious option label" + } +} \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb new file mode 100644 index 000000000..5f0c42049 --- /dev/null +++ b/lib/l10n/app_en.arb @@ -0,0 +1,357 @@ +{ + "@@locale": "en", + "@@last_modified": "2024-08-19T00:00:00.000Z", + + "appTitle": "Stack Wallet", + "@appTitle": { + "description": "The title of the application" + }, + + "walletsTab": "Wallets", + "@walletsTab": { + "description": "Bottom navigation tab label for wallets view" + }, + "exchangeTab": "Exchange", + "@exchangeTab": { + "description": "Bottom navigation tab label for exchange view" + }, + "buyTab": "Buy", + "@buyTab": { + "description": "Bottom navigation tab label for buy view" + }, + "settingsTab": "Settings", + "@settingsTab": { + "description": "Bottom navigation tab label for settings view" + }, + "notificationsTitle": "Notifications", + "@notificationsTitle": { + "description": "AppBar title for notifications screen" + }, + "addressBookTitle": "Address Book", + "@addressBookTitle": { + "description": "AppBar title for address book screen" + }, + "homeTitle": "Home", + "@homeTitle": { + "description": "AppBar title for home screen" + }, + "walletViewTitle": "Wallet", + "@walletViewTitle": { + "description": "AppBar title for wallet details screen" + }, + "sendTitle": "Send", + "@sendTitle": { + "description": "AppBar title for send screen" + }, + "sendFromTitle": "Send from", + "@sendFromTitle": { + "description": "AppBar title for send from screen" + }, + "receiveTitle": "Receive", + "@receiveTitle": { + "description": "AppBar title for receive screen" + }, + "swapTitle": "Swap", + "@swapTitle": { + "description": "AppBar title for swap screen" + }, + "tokensTitle": "Tokens", + "@tokensTitle": { + "description": "AppBar title for tokens screen" + }, + + "saveButton": "Save", + "@saveButton": { + "description": "Generic save button label used across forms" + }, + "cancelButton": "Cancel", + "@cancelButton": { + "description": "Generic cancel button label used across dialogs" + }, + "continueButton": "Continue", + "@continueButton": { + "description": "Continue button text for multi-step processes" + }, + "editButton": "Edit", + "@editButton": { + "description": "Edit button label" + }, + "deleteButton": "Delete", + "@deleteButton": { + "description": "Delete button label" + }, + "nextButton": "Next", + "@nextButton": { + "description": "Next button for navigation" + }, + "closeButton": "Close", + "@closeButton": { + "description": "Close button for dialogs and modals" + }, + "okButton": "OK", + "@okButton": { + "description": "OK button for confirmation dialogs" + }, + "yesButton": "Yes", + "@yesButton": { + "description": "Yes button for confirmation dialogs" + }, + "noButton": "No", + "@noButton": { + "description": "No button for confirmation dialogs" + }, + "copyButton": "Copy", + "@copyButton": { + "description": "Copy button for copying text to clipboard" + }, + "sendButton": "Send", + "@sendButton": { + "description": "Send button for transactions" + }, + "receiveButton": "Receive", + "@receiveButton": { + "description": "Receive button for receiving transactions" + }, + "addButton": "Add", + "@addButton": { + "description": "Add button for creating new items" + }, + + "nameLabel": "Name", + "@nameLabel": { + "description": "Label for name input fields" + }, + "amountLabel": "Amount", + "@amountLabel": { + "description": "Label for amount input fields" + }, + "addressLabel": "Address", + "@addressLabel": { + "description": "Label for address input fields" + }, + "feeLabel": "Fee", + "@feeLabel": { + "description": "Label for fee input fields" + }, + "noteLabel": "Note", + "@noteLabel": { + "description": "Label for note input fields" + }, + "passwordLabel": "Password", + "@passwordLabel": { + "description": "Label for password input fields" + }, + "searchHint": "Search...", + "@searchHint": { + "description": "Placeholder text for search fields" + }, + "enterPasswordHint": "Enter password", + "@enterPasswordHint": { + "description": "Placeholder text for password fields" + }, + "enterAmountHint": "0.00", + "@enterAmountHint": { + "description": "Placeholder text for amount fields" + }, + "optionalHint": "Optional", + "@optionalHint": { + "description": "Hint text for optional fields" + }, + + "requiredFieldError": "This field is required", + "@requiredFieldError": { + "description": "Error message for required fields that are empty" + }, + "invalidEmailError": "Please enter a valid email address", + "@invalidEmailError": { + "description": "Error message for invalid email format" + }, + "invalidAddressError": "Please enter a valid address", + "@invalidAddressError": { + "description": "Error message for invalid address format" + }, + "insufficientFundsError": "Insufficient funds", + "@insufficientFundsError": { + "description": "Error message when user has insufficient funds" + }, + "networkError": "Network connection failed", + "@networkError": { + "description": "Error message for network connection failures" + }, + "transactionFailed": "Transaction failed", + "@transactionFailed": { + "description": "Error message for failed transactions" + }, + + "loadingStatus": "Loading...", + "@loadingStatus": { + "description": "Status message while loading" + }, + "processingStatus": "Processing...", + "@processingStatus": { + "description": "Status message while processing" + }, + "syncingStatus": "Syncing...", + "@syncingStatus": { + "description": "Status message while syncing" + }, + "completedStatus": "Completed", + "@completedStatus": { + "description": "Status message when operation is completed" + }, + "pendingStatus": "Pending", + "@pendingStatus": { + "description": "Status message when operation is pending" + }, + "confirmedStatus": "Confirmed", + "@confirmedStatus": { + "description": "Status message when transaction is confirmed" + }, + + "wallets": "Wallets", + "@wallets": { + "description": "Label for the wallets section" + }, + "settings": "Settings", + "@settings": { + "description": "Label for the settings section" + }, + "exchange": "Exchange", + "@exchange": { + "description": "Label for the exchange section" + }, + "buy": "Buy", + "@buy": { + "description": "Label for the buy section" + }, + "notifications": "Notifications", + "@notifications": { + "description": "Label for the notifications section" + }, + "saveChanges": "Save changes", + "@saveChanges": { + "description": "Save changes button text" + }, + "contractDetails": "Contract details", + "@contractDetails": { + "description": "Contract details page title" + }, + "contractAddress": "Contract address", + "@contractAddress": { + "description": "Label for contract address field" + }, + "symbolLabel": "Symbol", + "@symbolLabel": { + "description": "Label for symbol field" + }, + "typeLabel": "Type", + "@typeLabel": { + "description": "Label for type field" + }, + "decimalsLabel": "Decimals", + "@decimalsLabel": { + "description": "Label for decimals field" + }, + "name": "Name", + "@name": { + "description": "Label for name field" + }, + "youCanChangeItLaterInSettings": "You can change it later in Settings", + "@youCanChangeItLaterInSettings": { + "description": "Informational text about changing settings later" + }, + "easyCrypto": "Easy Crypto", + "@easyCrypto": { + "description": "Easy Crypto option label" + }, + "recommended": "Recommended", + "@recommended": { + "description": "Recommended option label" + }, + "incognito": "Incognito", + "@incognito": { + "description": "Incognito option label" + }, + "privacyConscious": "Privacy conscious", + "@privacyConscious": { + "description": "Privacy conscious option label" + }, + + "welcomeTagline": "An open-source, multicoin wallet for everyone", + "@welcomeTagline": { + "description": "Main tagline shown on welcome/intro screen" + }, + "getStartedButton": "Get started", + "@getStartedButton": { + "description": "Button text for starting wallet setup on mobile" + }, + "createNewWalletButton": "Create new {appPrefix}", + "@createNewWalletButton": { + "description": "Button text for creating new wallet on desktop", + "placeholders": { + "appPrefix": { + "type": "String", + "description": "Application prefix (e.g., Stack)" + } + } + }, + "restoreFromBackupButton": "Restore from {appPrefix} backup", + "@restoreFromBackupButton": { + "description": "Button text for restoring from backup on desktop", + "placeholders": { + "appPrefix": { + "type": "String", + "description": "Application prefix (e.g., Stack)" + } + } + }, + "privacyAgreementText": "By using {appName}, you agree to the ", + "@privacyAgreementText": { + "description": "First part of privacy agreement text", + "placeholders": { + "appName": { + "type": "String", + "description": "Application name" + } + } + }, + "termsOfServiceLinkText": "Terms of service", + "@termsOfServiceLinkText": { + "description": "Link text for terms of service" + }, + "privacyAgreementConjunction": " and ", + "@privacyAgreementConjunction": { + "description": "Conjunction between terms and privacy policy links" + }, + "privacyPolicyLinkText": "Privacy policy", + "@privacyPolicyLinkText": { + "description": "Link text for privacy policy" + }, + + "enterPinTitle": "Enter PIN", + "@enterPinTitle": { + "description": "Title text for PIN entry screen" + }, + "useBiometricsButton": "Use biometrics", + "@useBiometricsButton": { + "description": "Button text for using biometric authentication" + }, + "loadingWalletsMessage": "Loading wallets...", + "@loadingWalletsMessage": { + "description": "Loading message while wallets are being loaded" + }, + "incorrectPinTryAgainError": "Incorrect PIN. Please try again", + "@incorrectPinTryAgainError": { + "description": "Error message for incorrect PIN entry" + }, + "incorrectPinThrottleError": "Incorrect PIN entered too many times. Please wait {waitTime}", + "@incorrectPinThrottleError": { + "description": "Error message when PIN attempts are throttled", + "placeholders": { + "waitTime": { + "type": "String", + "description": "Time to wait before trying again" + } + } + } +} \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb new file mode 100644 index 000000000..b56c62b6d --- /dev/null +++ b/lib/l10n/app_es.arb @@ -0,0 +1,75 @@ +{ + "@@locale": "es", + "appTitle": "Stack Wallet", + "@appTitle": { + "description": "The title of the application" + }, + "wallets": "Billeteras", + "@wallets": { + "description": "Label for the wallets section" + }, + "settings": "Configuración", + "@settings": { + "description": "Label for the settings section" + }, + "exchange": "Intercambio", + "@exchange": { + "description": "Label for the exchange section" + }, + "buy": "Comprar", + "@buy": { + "description": "Label for the buy section" + }, + "notifications": "Notificaciones", + "@notifications": { + "description": "Label for the notifications section" + }, + "continueButton": "Continuar", + "@continueButton": { + "description": "Continue button text" + }, + "welcomeTagline": "Una billetera multicripto de código abierto para todos", + "@welcomeTagline": { + "description": "Main tagline shown on welcome/intro screen" + }, + "getStartedButton": "Empezar", + "@getStartedButton": { + "description": "Button text for starting wallet setup on mobile" + }, + "saveChanges": "Guardar cambios", + "@saveChanges": { + "description": "Save changes button text" + }, + "contractDetails": "Detalles del contrato", + "@contractDetails": { + "description": "Contract details page title" + }, + "contractAddress": "Dirección del contrato", + "@contractAddress": { + "description": "Label for contract address field" + }, + "name": "Nombre", + "@name": { + "description": "Label for name field" + }, + "youCanChangeItLaterInSettings": "Puedes cambiarlo más tarde en Configuración", + "@youCanChangeItLaterInSettings": { + "description": "Informational text about changing settings later" + }, + "easyCrypto": "Crypto Fácil", + "@easyCrypto": { + "description": "Easy Crypto option label" + }, + "recommended": "Recomendado", + "@recommended": { + "description": "Recommended option label" + }, + "incognito": "Incógnito", + "@incognito": { + "description": "Incognito option label" + }, + "privacyConscious": "Consciente de la privacidad", + "@privacyConscious": { + "description": "Privacy conscious option label" + } +} \ No newline at end of file diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart new file mode 100644 index 000000000..fee70633d --- /dev/null +++ b/lib/l10n/app_localizations.dart @@ -0,0 +1,623 @@ +import 'dart:async'; + +import 'package:flutter/widgets.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:intl/intl.dart' as intl; + +import 'app_localizations_ar.dart' deferred as app_localizations_ar; +import 'app_localizations_en.dart' deferred as app_localizations_en; +import 'app_localizations_es.dart' deferred as app_localizations_es; + +// ignore_for_file: type=lint + +/// Callers can lookup localized strings with an instance of AppLocalizations +/// returned by `AppLocalizations.of(context)`. +/// +/// Applications need to include `AppLocalizations.delegate()` in their app's +/// `localizationDelegates` list, and the locales they support in the app's +/// `supportedLocales` list. For example: +/// +/// ```dart +/// import 'l10n/app_localizations.dart'; +/// +/// return MaterialApp( +/// localizationsDelegates: AppLocalizations.localizationsDelegates, +/// supportedLocales: AppLocalizations.supportedLocales, +/// home: MyApplicationHome(), +/// ); +/// ``` +/// +/// ## Update pubspec.yaml +/// +/// Please make sure to update your pubspec.yaml to include the following +/// packages: +/// +/// ```yaml +/// dependencies: +/// # Internationalization support. +/// flutter_localizations: +/// sdk: flutter +/// intl: any # Use the pinned version from flutter_localizations +/// +/// # Rest of dependencies +/// ``` +/// +/// ## iOS Applications +/// +/// iOS applications define key application metadata, including supported +/// locales, in an Info.plist file that is built into the application bundle. +/// To configure the locales supported by your app, you’ll need to edit this +/// file. +/// +/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file. +/// Then, in the Project Navigator, open the Info.plist file under the Runner +/// project’s Runner folder. +/// +/// Next, select the Information Property List item, select Add Item from the +/// Editor menu, then select Localizations from the pop-up menu. +/// +/// Select and expand the newly-created Localizations item then, for each +/// locale your application supports, add a new item and select the locale +/// you wish to add from the pop-up menu in the Value field. This list should +/// be consistent with the languages listed in the AppLocalizations.supportedLocales +/// property. +abstract class AppLocalizations { + AppLocalizations(String locale) + : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + + final String localeName; + + static AppLocalizations? of(BuildContext context) { + return Localizations.of(context, AppLocalizations); + } + + static const LocalizationsDelegate delegate = + _AppLocalizationsDelegate(); + + /// A list of this localizations delegate along with the default localizations + /// delegates. + /// + /// Returns a list of localizations delegates containing this delegate along with + /// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, + /// and GlobalWidgetsLocalizations.delegate. + /// + /// Additional delegates can be added by appending to this list in + /// MaterialApp. This list does not have to be used at all if a custom list + /// of delegates is preferred or required. + static const List> localizationsDelegates = + >[ + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; + + /// A list of this localizations delegate's supported locales. + static const List supportedLocales = [ + Locale('en'), + Locale('ar'), + Locale('es'), + ]; + + /// The title of the application + /// + /// In en, this message translates to: + /// **'Stack Wallet'** + String get appTitle; + + /// Bottom navigation tab label for wallets view + /// + /// In en, this message translates to: + /// **'Wallets'** + String get walletsTab; + + /// Bottom navigation tab label for exchange view + /// + /// In en, this message translates to: + /// **'Exchange'** + String get exchangeTab; + + /// Bottom navigation tab label for buy view + /// + /// In en, this message translates to: + /// **'Buy'** + String get buyTab; + + /// Bottom navigation tab label for settings view + /// + /// In en, this message translates to: + /// **'Settings'** + String get settingsTab; + + /// AppBar title for notifications screen + /// + /// In en, this message translates to: + /// **'Notifications'** + String get notificationsTitle; + + /// AppBar title for address book screen + /// + /// In en, this message translates to: + /// **'Address Book'** + String get addressBookTitle; + + /// AppBar title for home screen + /// + /// In en, this message translates to: + /// **'Home'** + String get homeTitle; + + /// AppBar title for wallet details screen + /// + /// In en, this message translates to: + /// **'Wallet'** + String get walletViewTitle; + + /// AppBar title for send screen + /// + /// In en, this message translates to: + /// **'Send'** + String get sendTitle; + + /// AppBar title for send from screen + /// + /// In en, this message translates to: + /// **'Send from'** + String get sendFromTitle; + + /// AppBar title for receive screen + /// + /// In en, this message translates to: + /// **'Receive'** + String get receiveTitle; + + /// AppBar title for swap screen + /// + /// In en, this message translates to: + /// **'Swap'** + String get swapTitle; + + /// AppBar title for tokens screen + /// + /// In en, this message translates to: + /// **'Tokens'** + String get tokensTitle; + + /// Generic save button label used across forms + /// + /// In en, this message translates to: + /// **'Save'** + String get saveButton; + + /// Generic cancel button label used across dialogs + /// + /// In en, this message translates to: + /// **'Cancel'** + String get cancelButton; + + /// Continue button text for multi-step processes + /// + /// In en, this message translates to: + /// **'Continue'** + String get continueButton; + + /// Edit button label + /// + /// In en, this message translates to: + /// **'Edit'** + String get editButton; + + /// Delete button label + /// + /// In en, this message translates to: + /// **'Delete'** + String get deleteButton; + + /// Next button for navigation + /// + /// In en, this message translates to: + /// **'Next'** + String get nextButton; + + /// Close button for dialogs and modals + /// + /// In en, this message translates to: + /// **'Close'** + String get closeButton; + + /// OK button for confirmation dialogs + /// + /// In en, this message translates to: + /// **'OK'** + String get okButton; + + /// Yes button for confirmation dialogs + /// + /// In en, this message translates to: + /// **'Yes'** + String get yesButton; + + /// No button for confirmation dialogs + /// + /// In en, this message translates to: + /// **'No'** + String get noButton; + + /// Copy button for copying text to clipboard + /// + /// In en, this message translates to: + /// **'Copy'** + String get copyButton; + + /// Send button for transactions + /// + /// In en, this message translates to: + /// **'Send'** + String get sendButton; + + /// Receive button for receiving transactions + /// + /// In en, this message translates to: + /// **'Receive'** + String get receiveButton; + + /// Add button for creating new items + /// + /// In en, this message translates to: + /// **'Add'** + String get addButton; + + /// Label for name input fields + /// + /// In en, this message translates to: + /// **'Name'** + String get nameLabel; + + /// Label for amount input fields + /// + /// In en, this message translates to: + /// **'Amount'** + String get amountLabel; + + /// Label for address input fields + /// + /// In en, this message translates to: + /// **'Address'** + String get addressLabel; + + /// Label for fee input fields + /// + /// In en, this message translates to: + /// **'Fee'** + String get feeLabel; + + /// Label for note input fields + /// + /// In en, this message translates to: + /// **'Note'** + String get noteLabel; + + /// Label for password input fields + /// + /// In en, this message translates to: + /// **'Password'** + String get passwordLabel; + + /// Placeholder text for search fields + /// + /// In en, this message translates to: + /// **'Search...'** + String get searchHint; + + /// Placeholder text for password fields + /// + /// In en, this message translates to: + /// **'Enter password'** + String get enterPasswordHint; + + /// Placeholder text for amount fields + /// + /// In en, this message translates to: + /// **'0.00'** + String get enterAmountHint; + + /// Hint text for optional fields + /// + /// In en, this message translates to: + /// **'Optional'** + String get optionalHint; + + /// Error message for required fields that are empty + /// + /// In en, this message translates to: + /// **'This field is required'** + String get requiredFieldError; + + /// Error message for invalid email format + /// + /// In en, this message translates to: + /// **'Please enter a valid email address'** + String get invalidEmailError; + + /// Error message for invalid address format + /// + /// In en, this message translates to: + /// **'Please enter a valid address'** + String get invalidAddressError; + + /// Error message when user has insufficient funds + /// + /// In en, this message translates to: + /// **'Insufficient funds'** + String get insufficientFundsError; + + /// Error message for network connection failures + /// + /// In en, this message translates to: + /// **'Network connection failed'** + String get networkError; + + /// Error message for failed transactions + /// + /// In en, this message translates to: + /// **'Transaction failed'** + String get transactionFailed; + + /// Status message while loading + /// + /// In en, this message translates to: + /// **'Loading...'** + String get loadingStatus; + + /// Status message while processing + /// + /// In en, this message translates to: + /// **'Processing...'** + String get processingStatus; + + /// Status message while syncing + /// + /// In en, this message translates to: + /// **'Syncing...'** + String get syncingStatus; + + /// Status message when operation is completed + /// + /// In en, this message translates to: + /// **'Completed'** + String get completedStatus; + + /// Status message when operation is pending + /// + /// In en, this message translates to: + /// **'Pending'** + String get pendingStatus; + + /// Status message when transaction is confirmed + /// + /// In en, this message translates to: + /// **'Confirmed'** + String get confirmedStatus; + + /// Label for the wallets section + /// + /// In en, this message translates to: + /// **'Wallets'** + String get wallets; + + /// Label for the settings section + /// + /// In en, this message translates to: + /// **'Settings'** + String get settings; + + /// Label for the exchange section + /// + /// In en, this message translates to: + /// **'Exchange'** + String get exchange; + + /// Label for the buy section + /// + /// In en, this message translates to: + /// **'Buy'** + String get buy; + + /// Label for the notifications section + /// + /// In en, this message translates to: + /// **'Notifications'** + String get notifications; + + /// Save changes button text + /// + /// In en, this message translates to: + /// **'Save changes'** + String get saveChanges; + + /// Contract details page title + /// + /// In en, this message translates to: + /// **'Contract details'** + String get contractDetails; + + /// Label for contract address field + /// + /// In en, this message translates to: + /// **'Contract address'** + String get contractAddress; + + /// Label for symbol field + /// + /// In en, this message translates to: + /// **'Symbol'** + String get symbolLabel; + + /// Label for type field + /// + /// In en, this message translates to: + /// **'Type'** + String get typeLabel; + + /// Label for decimals field + /// + /// In en, this message translates to: + /// **'Decimals'** + String get decimalsLabel; + + /// Label for name field + /// + /// In en, this message translates to: + /// **'Name'** + String get name; + + /// Informational text about changing settings later + /// + /// In en, this message translates to: + /// **'You can change it later in Settings'** + String get youCanChangeItLaterInSettings; + + /// Easy Crypto option label + /// + /// In en, this message translates to: + /// **'Easy Crypto'** + String get easyCrypto; + + /// Recommended option label + /// + /// In en, this message translates to: + /// **'Recommended'** + String get recommended; + + /// Incognito option label + /// + /// In en, this message translates to: + /// **'Incognito'** + String get incognito; + + /// Privacy conscious option label + /// + /// In en, this message translates to: + /// **'Privacy conscious'** + String get privacyConscious; + + /// Main tagline shown on welcome/intro screen + /// + /// In en, this message translates to: + /// **'An open-source, multicoin wallet for everyone'** + String get welcomeTagline; + + /// Button text for starting wallet setup on mobile + /// + /// In en, this message translates to: + /// **'Get started'** + String get getStartedButton; + + /// Button text for creating new wallet on desktop + /// + /// In en, this message translates to: + /// **'Create new {appPrefix}'** + String createNewWalletButton(String appPrefix); + + /// Button text for restoring from backup on desktop + /// + /// In en, this message translates to: + /// **'Restore from {appPrefix} backup'** + String restoreFromBackupButton(String appPrefix); + + /// First part of privacy agreement text + /// + /// In en, this message translates to: + /// **'By using {appName}, you agree to the '** + String privacyAgreementText(String appName); + + /// Link text for terms of service + /// + /// In en, this message translates to: + /// **'Terms of service'** + String get termsOfServiceLinkText; + + /// Conjunction between terms and privacy policy links + /// + /// In en, this message translates to: + /// **' and '** + String get privacyAgreementConjunction; + + /// Link text for privacy policy + /// + /// In en, this message translates to: + /// **'Privacy policy'** + String get privacyPolicyLinkText; + + /// Title text for PIN entry screen + /// + /// In en, this message translates to: + /// **'Enter PIN'** + String get enterPinTitle; + + /// Button text for using biometric authentication + /// + /// In en, this message translates to: + /// **'Use biometrics'** + String get useBiometricsButton; + + /// Loading message while wallets are being loaded + /// + /// In en, this message translates to: + /// **'Loading wallets...'** + String get loadingWalletsMessage; + + /// Error message for incorrect PIN entry + /// + /// In en, this message translates to: + /// **'Incorrect PIN. Please try again'** + String get incorrectPinTryAgainError; + + /// Error message when PIN attempts are throttled + /// + /// In en, this message translates to: + /// **'Incorrect PIN entered too many times. Please wait {waitTime}'** + String incorrectPinThrottleError(String waitTime); +} + +class _AppLocalizationsDelegate + extends LocalizationsDelegate { + const _AppLocalizationsDelegate(); + + @override + Future load(Locale locale) { + return lookupAppLocalizations(locale); + } + + @override + bool isSupported(Locale locale) => + ['ar', 'en', 'es'].contains(locale.languageCode); + + @override + bool shouldReload(_AppLocalizationsDelegate old) => false; +} + +Future lookupAppLocalizations(Locale locale) { + // Lookup logic when only language code is specified. + switch (locale.languageCode) { + case 'ar': + return app_localizations_ar.loadLibrary().then( + (dynamic _) => app_localizations_ar.AppLocalizationsAr(), + ); + case 'en': + return app_localizations_en.loadLibrary().then( + (dynamic _) => app_localizations_en.AppLocalizationsEn(), + ); + case 'es': + return app_localizations_es.loadLibrary().then( + (dynamic _) => app_localizations_es.AppLocalizationsEs(), + ); + } + + throw FlutterError( + 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.', + ); +} diff --git a/lib/l10n/app_localizations_ar.dart b/lib/l10n/app_localizations_ar.dart new file mode 100644 index 000000000..e9f66da1c --- /dev/null +++ b/lib/l10n/app_localizations_ar.dart @@ -0,0 +1,258 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Arabic (`ar`). +class AppLocalizationsAr extends AppLocalizations { + AppLocalizationsAr([String locale = 'ar']) : super(locale); + + @override + String get appTitle => 'محفظة ستاك'; + + @override + String get walletsTab => 'المحافظ'; + + @override + String get exchangeTab => 'التبادل'; + + @override + String get buyTab => 'شراء'; + + @override + String get settingsTab => 'الإعدادات'; + + @override + String get notificationsTitle => 'الإشعارات'; + + @override + String get addressBookTitle => 'دفتر العناوين'; + + @override + String get homeTitle => 'الرئيسية'; + + @override + String get walletViewTitle => 'المحفظة'; + + @override + String get sendTitle => 'إرسال'; + + @override + String get sendFromTitle => 'إرسال من'; + + @override + String get receiveTitle => 'استقبال'; + + @override + String get swapTitle => 'تبديل'; + + @override + String get tokensTitle => 'الرموز المميزة'; + + @override + String get saveButton => 'حفظ'; + + @override + String get cancelButton => 'إلغاء'; + + @override + String get continueButton => 'متابعة'; + + @override + String get editButton => 'تعديل'; + + @override + String get deleteButton => 'حذف'; + + @override + String get nextButton => 'التالي'; + + @override + String get closeButton => 'إغلاق'; + + @override + String get okButton => 'موافق'; + + @override + String get yesButton => 'نعم'; + + @override + String get noButton => 'لا'; + + @override + String get copyButton => 'نسخ'; + + @override + String get sendButton => 'إرسال'; + + @override + String get receiveButton => 'استقبال'; + + @override + String get addButton => 'إضافة'; + + @override + String get nameLabel => 'الاسم'; + + @override + String get amountLabel => 'المبلغ'; + + @override + String get addressLabel => 'العنوان'; + + @override + String get feeLabel => 'الرسوم'; + + @override + String get noteLabel => 'ملاحظة'; + + @override + String get passwordLabel => 'كلمة المرور'; + + @override + String get searchHint => 'البحث...'; + + @override + String get enterPasswordHint => 'أدخل كلمة المرور'; + + @override + String get enterAmountHint => '0.00'; + + @override + String get optionalHint => 'اختياري'; + + @override + String get requiredFieldError => 'هذا الحقل مطلوب'; + + @override + String get invalidEmailError => 'يرجى إدخال عنوان بريد إلكتروني صحيح'; + + @override + String get invalidAddressError => 'يرجى إدخال عنوان صحيح'; + + @override + String get insufficientFundsError => 'أموال غير كافية'; + + @override + String get networkError => 'فشل في الاتصال بالشبكة'; + + @override + String get transactionFailed => 'فشلت المعاملة'; + + @override + String get loadingStatus => 'جاري التحميل...'; + + @override + String get processingStatus => 'جاري المعالجة...'; + + @override + String get syncingStatus => 'جاري المزامنة...'; + + @override + String get completedStatus => 'مكتمل'; + + @override + String get pendingStatus => 'معلق'; + + @override + String get confirmedStatus => 'مؤكد'; + + @override + String get wallets => 'المحافظ'; + + @override + String get settings => 'الإعدادات'; + + @override + String get exchange => 'التبادل'; + + @override + String get buy => 'شراء'; + + @override + String get notifications => 'الإشعارات'; + + @override + String get saveChanges => 'حفظ التغييرات'; + + @override + String get contractDetails => 'تفاصيل العقد'; + + @override + String get contractAddress => 'عنوان العقد'; + + @override + String get symbolLabel => 'الرمز'; + + @override + String get typeLabel => 'النوع'; + + @override + String get decimalsLabel => 'الكسور العشرية'; + + @override + String get name => 'الاسم'; + + @override + String get youCanChangeItLaterInSettings => 'يمكنك تغييره لاحقاً في الإعدادات'; + + @override + String get easyCrypto => 'عملة رقمية سهلة'; + + @override + String get recommended => 'موصى به'; + + @override + String get incognito => 'مجهول'; + + @override + String get privacyConscious => 'واعي للخصوصية'; + + @override + String get welcomeTagline => 'محفظة متعددة العملات ومفتوحة المصدر للجميع'; + + @override + String get getStartedButton => 'ابدأ'; + + @override + String createNewWalletButton(String appPrefix) { + return 'إنشاء $appPrefix جديد'; + } + + @override + String restoreFromBackupButton(String appPrefix) { + return 'استعادة من نسخة احتياطية $appPrefix'; + } + + @override + String privacyAgreementText(String appName) { + return 'باستخدام $appName، فإنك توافق على '; + } + + @override + String get termsOfServiceLinkText => 'شروط الخدمة'; + + @override + String get privacyAgreementConjunction => ' و '; + + @override + String get privacyPolicyLinkText => 'سياسة الخصوصية'; + + @override + String get enterPinTitle => 'أدخل رقم التعريف الشخصي'; + + @override + String get useBiometricsButton => 'استخدم القياسات الحيوية'; + + @override + String get loadingWalletsMessage => 'جاري تحميل المحافظ...'; + + @override + String get incorrectPinTryAgainError => 'رقم التعريف الشخصي غير صحيح. يرجى المحاولة مرة أخرى'; + + @override + String incorrectPinThrottleError(String waitTime) { + return 'تم إدخال رقم التعريف الشخصي بشكل خاطئ مرات كثيرة. يرجى الانتظار $waitTime'; + } +} diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart new file mode 100644 index 000000000..13f6b8314 --- /dev/null +++ b/lib/l10n/app_localizations_en.dart @@ -0,0 +1,258 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for English (`en`). +class AppLocalizationsEn extends AppLocalizations { + AppLocalizationsEn([String locale = 'en']) : super(locale); + + @override + String get appTitle => 'Stack Wallet'; + + @override + String get walletsTab => 'Wallets'; + + @override + String get exchangeTab => 'Exchange'; + + @override + String get buyTab => 'Buy'; + + @override + String get settingsTab => 'Settings'; + + @override + String get notificationsTitle => 'Notifications'; + + @override + String get addressBookTitle => 'Address Book'; + + @override + String get homeTitle => 'Home'; + + @override + String get walletViewTitle => 'Wallet'; + + @override + String get sendTitle => 'Send'; + + @override + String get sendFromTitle => 'Send from'; + + @override + String get receiveTitle => 'Receive'; + + @override + String get swapTitle => 'Swap'; + + @override + String get tokensTitle => 'Tokens'; + + @override + String get saveButton => 'Save'; + + @override + String get cancelButton => 'Cancel'; + + @override + String get continueButton => 'Continue'; + + @override + String get editButton => 'Edit'; + + @override + String get deleteButton => 'Delete'; + + @override + String get nextButton => 'Next'; + + @override + String get closeButton => 'Close'; + + @override + String get okButton => 'OK'; + + @override + String get yesButton => 'Yes'; + + @override + String get noButton => 'No'; + + @override + String get copyButton => 'Copy'; + + @override + String get sendButton => 'Send'; + + @override + String get receiveButton => 'Receive'; + + @override + String get addButton => 'Add'; + + @override + String get nameLabel => 'Name'; + + @override + String get amountLabel => 'Amount'; + + @override + String get addressLabel => 'Address'; + + @override + String get feeLabel => 'Fee'; + + @override + String get noteLabel => 'Note'; + + @override + String get passwordLabel => 'Password'; + + @override + String get searchHint => 'Search...'; + + @override + String get enterPasswordHint => 'Enter password'; + + @override + String get enterAmountHint => '0.00'; + + @override + String get optionalHint => 'Optional'; + + @override + String get requiredFieldError => 'This field is required'; + + @override + String get invalidEmailError => 'Please enter a valid email address'; + + @override + String get invalidAddressError => 'Please enter a valid address'; + + @override + String get insufficientFundsError => 'Insufficient funds'; + + @override + String get networkError => 'Network connection failed'; + + @override + String get transactionFailed => 'Transaction failed'; + + @override + String get loadingStatus => 'Loading...'; + + @override + String get processingStatus => 'Processing...'; + + @override + String get syncingStatus => 'Syncing...'; + + @override + String get completedStatus => 'Completed'; + + @override + String get pendingStatus => 'Pending'; + + @override + String get confirmedStatus => 'Confirmed'; + + @override + String get wallets => 'Wallets'; + + @override + String get settings => 'Settings'; + + @override + String get exchange => 'Exchange'; + + @override + String get buy => 'Buy'; + + @override + String get notifications => 'Notifications'; + + @override + String get saveChanges => 'Save changes'; + + @override + String get contractDetails => 'Contract details'; + + @override + String get contractAddress => 'Contract address'; + + @override + String get symbolLabel => 'Symbol'; + + @override + String get typeLabel => 'Type'; + + @override + String get decimalsLabel => 'Decimals'; + + @override + String get name => 'Name'; + + @override + String get youCanChangeItLaterInSettings => 'You can change it later in Settings'; + + @override + String get easyCrypto => 'Easy Crypto'; + + @override + String get recommended => 'Recommended'; + + @override + String get incognito => 'Incognito'; + + @override + String get privacyConscious => 'Privacy conscious'; + + @override + String get welcomeTagline => 'An open-source, multicoin wallet for everyone'; + + @override + String get getStartedButton => 'Get started'; + + @override + String createNewWalletButton(String appPrefix) { + return 'Create new $appPrefix'; + } + + @override + String restoreFromBackupButton(String appPrefix) { + return 'Restore from $appPrefix backup'; + } + + @override + String privacyAgreementText(String appName) { + return 'By using $appName, you agree to the '; + } + + @override + String get termsOfServiceLinkText => 'Terms of service'; + + @override + String get privacyAgreementConjunction => ' and '; + + @override + String get privacyPolicyLinkText => 'Privacy policy'; + + @override + String get enterPinTitle => 'Enter PIN'; + + @override + String get useBiometricsButton => 'Use biometrics'; + + @override + String get loadingWalletsMessage => 'Loading wallets...'; + + @override + String get incorrectPinTryAgainError => 'Incorrect PIN. Please try again'; + + @override + String incorrectPinThrottleError(String waitTime) { + return 'Incorrect PIN entered too many times. Please wait $waitTime'; + } +} diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart new file mode 100644 index 000000000..792fbdbb3 --- /dev/null +++ b/lib/l10n/app_localizations_es.dart @@ -0,0 +1,258 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Spanish Castilian (`es`). +class AppLocalizationsEs extends AppLocalizations { + AppLocalizationsEs([String locale = 'es']) : super(locale); + + @override + String get appTitle => 'Stack Wallet'; + + @override + String get walletsTab => 'Billeteras'; + + @override + String get exchangeTab => 'Intercambio'; + + @override + String get buyTab => 'Comprar'; + + @override + String get settingsTab => 'Configuración'; + + @override + String get notificationsTitle => 'Notificaciones'; + + @override + String get addressBookTitle => 'Libreta de direcciones'; + + @override + String get homeTitle => 'Inicio'; + + @override + String get walletViewTitle => 'Billetera'; + + @override + String get sendTitle => 'Enviar'; + + @override + String get sendFromTitle => 'Enviar desde'; + + @override + String get receiveTitle => 'Recibir'; + + @override + String get swapTitle => 'Intercambiar'; + + @override + String get tokensTitle => 'Tokens'; + + @override + String get saveButton => 'Guardar'; + + @override + String get cancelButton => 'Cancelar'; + + @override + String get continueButton => 'Continuar'; + + @override + String get editButton => 'Editar'; + + @override + String get deleteButton => 'Eliminar'; + + @override + String get nextButton => 'Siguiente'; + + @override + String get closeButton => 'Cerrar'; + + @override + String get okButton => 'OK'; + + @override + String get yesButton => 'Sí'; + + @override + String get noButton => 'No'; + + @override + String get copyButton => 'Copiar'; + + @override + String get sendButton => 'Enviar'; + + @override + String get receiveButton => 'Recibir'; + + @override + String get addButton => 'Añadir'; + + @override + String get nameLabel => 'Nombre'; + + @override + String get amountLabel => 'Cantidad'; + + @override + String get addressLabel => 'Dirección'; + + @override + String get feeLabel => 'Comisión'; + + @override + String get noteLabel => 'Nota'; + + @override + String get passwordLabel => 'Contraseña'; + + @override + String get searchHint => 'Buscar...'; + + @override + String get enterPasswordHint => 'Ingresa la contraseña'; + + @override + String get enterAmountHint => '0.00'; + + @override + String get optionalHint => 'Opcional'; + + @override + String get requiredFieldError => 'Este campo es obligatorio'; + + @override + String get invalidEmailError => 'Por favor ingresa una dirección de correo electrónico válida'; + + @override + String get invalidAddressError => 'Por favor ingresa una dirección válida'; + + @override + String get insufficientFundsError => 'Fondos insuficientes'; + + @override + String get networkError => 'Error de conexión de red'; + + @override + String get transactionFailed => 'La transacción falló'; + + @override + String get loadingStatus => 'Cargando...'; + + @override + String get processingStatus => 'Procesando...'; + + @override + String get syncingStatus => 'Sincronizando...'; + + @override + String get completedStatus => 'Completado'; + + @override + String get pendingStatus => 'Pendiente'; + + @override + String get confirmedStatus => 'Confirmado'; + + @override + String get wallets => 'Billeteras'; + + @override + String get settings => 'Configuración'; + + @override + String get exchange => 'Intercambio'; + + @override + String get buy => 'Comprar'; + + @override + String get notifications => 'Notificaciones'; + + @override + String get saveChanges => 'Guardar cambios'; + + @override + String get contractDetails => 'Detalles del contrato'; + + @override + String get contractAddress => 'Dirección del contrato'; + + @override + String get symbolLabel => 'Símbolo'; + + @override + String get typeLabel => 'Tipo'; + + @override + String get decimalsLabel => 'Decimales'; + + @override + String get name => 'Nombre'; + + @override + String get youCanChangeItLaterInSettings => 'Puedes cambiarlo más tarde en Configuración'; + + @override + String get easyCrypto => 'Cripto fácil'; + + @override + String get recommended => 'Recomendado'; + + @override + String get incognito => 'Incógnito'; + + @override + String get privacyConscious => 'Consciente de la privacidad'; + + @override + String get welcomeTagline => 'Una billetera de código abierto y multidivisa para todos'; + + @override + String get getStartedButton => 'Comenzar'; + + @override + String createNewWalletButton(String appPrefix) { + return 'Crear nuevo $appPrefix'; + } + + @override + String restoreFromBackupButton(String appPrefix) { + return 'Restaurar desde copia de seguridad de $appPrefix'; + } + + @override + String privacyAgreementText(String appName) { + return 'Al usar $appName, aceptas los '; + } + + @override + String get termsOfServiceLinkText => 'Términos de servicio'; + + @override + String get privacyAgreementConjunction => ' y la '; + + @override + String get privacyPolicyLinkText => 'Política de privacidad'; + + @override + String get enterPinTitle => 'Ingresa el PIN'; + + @override + String get useBiometricsButton => 'Usar biometría'; + + @override + String get loadingWalletsMessage => 'Cargando billeteras...'; + + @override + String get incorrectPinTryAgainError => 'PIN incorrecto. Por favor inténtalo de nuevo'; + + @override + String incorrectPinThrottleError(String waitTime) { + return 'PIN incorrecto ingresado demasiadas veces. Por favor espera $waitTime'; + } +} diff --git a/lib/l10n/categories/buttons_en.arb b/lib/l10n/categories/buttons_en.arb new file mode 100644 index 000000000..f940de188 --- /dev/null +++ b/lib/l10n/categories/buttons_en.arb @@ -0,0 +1,89 @@ +{ + "@@locale": "en", + "@@context": "Button labels and action text", + + "saveButton": "Save", + "@saveButton": { + "description": "Generic save button label used across forms" + }, + "cancelButton": "Cancel", + "@cancelButton": { + "description": "Generic cancel button label used across dialogs" + }, + "continueButton": "Continue", + "@continueButton": { + "description": "Continue button text for multi-step processes" + }, + "submitButton": "Submit", + "@submitButton": { + "description": "Submit button for forms" + }, + "editButton": "Edit", + "@editButton": { + "description": "Edit button label" + }, + "deleteButton": "Delete", + "@deleteButton": { + "description": "Delete button label" + }, + "nextButton": "Next", + "@nextButton": { + "description": "Next button for navigation" + }, + "previousButton": "Previous", + "@previousButton": { + "description": "Previous button for navigation" + }, + "closeButton": "Close", + "@closeButton": { + "description": "Close button for dialogs and modals" + }, + "okButton": "OK", + "@okButton": { + "description": "OK button for confirmation dialogs" + }, + "yesButton": "Yes", + "@yesButton": { + "description": "Yes button for confirmation dialogs" + }, + "noButton": "No", + "@noButton": { + "description": "No button for confirmation dialogs" + }, + "copyButton": "Copy", + "@copyButton": { + "description": "Copy button for copying text to clipboard" + }, + "shareButton": "Share", + "@shareButton": { + "description": "Share button for sharing content" + }, + "viewDetailsButton": "View Details", + "@viewDetailsButton": { + "description": "View details button for expanding content" + }, + "sendButton": "Send", + "@sendButton": { + "description": "Send button for transactions" + }, + "receiveButton": "Receive", + "@receiveButton": { + "description": "Receive button for receiving transactions" + }, + "refreshButton": "Refresh", + "@refreshButton": { + "description": "Refresh button for updating content" + }, + "addButton": "Add", + "@addButton": { + "description": "Add button for creating new items" + }, + "removeButton": "Remove", + "@removeButton": { + "description": "Remove button for deleting items" + }, + "selectButton": "Select", + "@selectButton": { + "description": "Select button for choosing options" + } +} \ No newline at end of file diff --git a/lib/l10n/categories/dialogs_en.arb b/lib/l10n/categories/dialogs_en.arb new file mode 100644 index 000000000..6330e7c58 --- /dev/null +++ b/lib/l10n/categories/dialogs_en.arb @@ -0,0 +1,105 @@ +{ + "@@locale": "en", + "@@context": "Dialog titles, content, and modal text", + + "confirmDeleteTitle": "Confirm Delete", + "@confirmDeleteTitle": { + "description": "Title for delete confirmation dialogs" + }, + "confirmDeleteMessage": "Are you sure you want to delete this item?", + "@confirmDeleteMessage": { + "description": "Confirmation message for delete dialogs" + }, + "unsavedChangesTitle": "Unsaved Changes", + "@unsavedChangesTitle": { + "description": "Title for unsaved changes dialog" + }, + "unsavedChangesMessage": "You have unsaved changes. Do you want to continue?", + "@unsavedChangesMessage": { + "description": "Message for unsaved changes confirmation" + }, + "warningTitle": "Warning", + "@warningTitle": { + "description": "Generic warning dialog title" + }, + "errorTitle": "Error", + "@errorTitle": { + "description": "Generic error dialog title" + }, + "successTitle": "Success", + "@successTitle": { + "description": "Generic success dialog title" + }, + "infoTitle": "Information", + "@infoTitle": { + "description": "Generic information dialog title" + }, + "confirmTitle": "Confirm", + "@confirmTitle": { + "description": "Generic confirmation dialog title" + }, + "backupWarningTitle": "Backup Warning", + "@backupWarningTitle": { + "description": "Title for backup warning dialogs" + }, + "securityWarningTitle": "Security Warning", + "@securityWarningTitle": { + "description": "Title for security warning dialogs" + }, + "privacyWarningTitle": "Privacy Warning", + "@privacyWarningTitle": { + "description": "Title for privacy warning dialogs" + }, + "transactionConfirmTitle": "Confirm Transaction", + "@transactionConfirmTitle": { + "description": "Title for transaction confirmation dialogs" + }, + "walletDeleteTitle": "Delete Wallet", + "@walletDeleteTitle": { + "description": "Title for wallet deletion dialogs" + }, + "contactDeleteTitle": "Delete Contact", + "@contactDeleteTitle": { + "description": "Title for contact deletion dialogs" + }, + "aboutTitle": "About", + "@aboutTitle": { + "description": "Title for about dialog" + }, + "helpTitle": "Help", + "@helpTitle": { + "description": "Title for help dialog" + }, + "settingsTitle": "Settings", + "@settingsTitle": { + "description": "Title for settings dialog" + }, + "termsTitle": "Terms of Service", + "@termsTitle": { + "description": "Title for terms of service dialog" + }, + "privacyPolicyTitle": "Privacy Policy", + "@privacyPolicyTitle": { + "description": "Title for privacy policy dialog" + }, + "licenseTitle": "License", + "@licenseTitle": { + "description": "Title for license dialog" + }, + "creditsTitle": "Credits", + "@creditsTitle": { + "description": "Title for credits dialog" + }, + "versionTitle": "Version", + "@versionTitle": { + "description": "Title for version dialog" + }, + "updateAvailableTitle": "Update Available", + "@updateAvailableTitle": { + "description": "Title for update available dialog" + }, + "maintenanceTitle": "Maintenance", + "@maintenanceTitle": { + "description": "Title for maintenance dialog" + } +} \ No newline at end of file diff --git a/lib/l10n/categories/errors_en.arb b/lib/l10n/categories/errors_en.arb new file mode 100644 index 000000000..ecfceba30 --- /dev/null +++ b/lib/l10n/categories/errors_en.arb @@ -0,0 +1,101 @@ +{ + "@@locale": "en", + "@@context": "Error messages and status feedback", + + "networkError": "Network connection failed", + "@networkError": { + "description": "Error message for network connection failures" + }, + "serverError": "Server error occurred", + "@serverError": { + "description": "Error message for server-side errors" + }, + "requestTimeout": "Request timeout", + "@requestTimeout": { + "description": "Error message for request timeouts" + }, + "invalidResponse": "Invalid response from server", + "@invalidResponse": { + "description": "Error message for invalid server responses" + }, + "authenticationError": "Authentication failed", + "@authenticationError": { + "description": "Error message for authentication failures" + }, + "incorrectPin": "Incorrect PIN", + "@incorrectPin": { + "description": "Error message for incorrect PIN entry" + }, + "accountLocked": "Account locked", + "@accountLocked": { + "description": "Error message when account is locked" + }, + "transactionFailed": "Transaction failed", + "@transactionFailed": { + "description": "Error message for failed transactions" + }, + "broadcastError": "Failed to broadcast transaction", + "@broadcastError": { + "description": "Error message for transaction broadcast failures" + }, + "walletLoadError": "Failed to load wallet", + "@walletLoadError": { + "description": "Error message when wallet fails to load" + }, + "syncError": "Synchronization failed", + "@syncError": { + "description": "Error message for wallet sync failures" + }, + "connectionError": "Connection error", + "@connectionError": { + "description": "Generic connection error message" + }, + "unknownError": "An unknown error occurred", + "@unknownError": { + "description": "Generic error message for unknown errors" + }, + "loadingStatus": "Loading...", + "@loadingStatus": { + "description": "Status message while loading" + }, + "processingStatus": "Processing...", + "@processingStatus": { + "description": "Status message while processing" + }, + "syncingStatus": "Syncing...", + "@syncingStatus": { + "description": "Status message while syncing" + }, + "completedStatus": "Completed", + "@completedStatus": { + "description": "Status message when operation is completed" + }, + "failedStatus": "Failed", + "@failedStatus": { + "description": "Status message when operation failed" + }, + "pendingStatus": "Pending", + "@pendingStatus": { + "description": "Status message when operation is pending" + }, + "confirmedStatus": "Confirmed", + "@confirmedStatus": { + "description": "Status message when transaction is confirmed" + }, + "unconfirmedStatus": "Unconfirmed", + "@unconfirmedStatus": { + "description": "Status message when transaction is unconfirmed" + }, + "successMessage": "Operation completed successfully", + "@successMessage": { + "description": "Generic success message" + }, + "transactionSentMessage": "Transaction sent successfully", + "@transactionSentMessage": { + "description": "Success message for sent transactions" + }, + "settingsSavedMessage": "Settings saved successfully", + "@settingsSavedMessage": { + "description": "Success message when settings are saved" + } +} \ No newline at end of file diff --git a/lib/l10n/categories/forms_en.arb b/lib/l10n/categories/forms_en.arb new file mode 100644 index 000000000..9ab10c3b3 --- /dev/null +++ b/lib/l10n/categories/forms_en.arb @@ -0,0 +1,105 @@ +{ + "@@locale": "en", + "@@context": "Form field labels, hints, and validation text", + + "nameLabel": "Name", + "@nameLabel": { + "description": "Label for name input fields" + }, + "amountLabel": "Amount", + "@amountLabel": { + "description": "Label for amount input fields" + }, + "addressLabel": "Address", + "@addressLabel": { + "description": "Label for address input fields" + }, + "feeLabel": "Fee", + "@feeLabel": { + "description": "Label for fee input fields" + }, + "noteLabel": "Note", + "@noteLabel": { + "description": "Label for note input fields" + }, + "passwordLabel": "Password", + "@passwordLabel": { + "description": "Label for password input fields" + }, + "emailLabel": "Email", + "@emailLabel": { + "description": "Label for email input fields" + }, + "phoneLabel": "Phone", + "@phoneLabel": { + "description": "Label for phone input fields" + }, + "descriptionLabel": "Description", + "@descriptionLabel": { + "description": "Label for description input fields" + }, + "titleLabel": "Title", + "@titleLabel": { + "description": "Label for title input fields" + }, + "searchHint": "Search...", + "@searchHint": { + "description": "Placeholder text for search fields" + }, + "enterPasswordHint": "Enter password", + "@enterPasswordHint": { + "description": "Placeholder text for password fields" + }, + "enterAmountHint": "0.00", + "@enterAmountHint": { + "description": "Placeholder text for amount fields" + }, + "enterAddressHint": "Enter recipient address", + "@enterAddressHint": { + "description": "Placeholder text for address fields" + }, + "enterNameHint": "Enter name", + "@enterNameHint": { + "description": "Placeholder text for name fields" + }, + "optionalHint": "Optional", + "@optionalHint": { + "description": "Hint text for optional fields" + }, + "requiredFieldError": "This field is required", + "@requiredFieldError": { + "description": "Error message for required fields that are empty" + }, + "invalidEmailError": "Please enter a valid email address", + "@invalidEmailError": { + "description": "Error message for invalid email format" + }, + "invalidAddressError": "Please enter a valid address", + "@invalidAddressError": { + "description": "Error message for invalid address format" + }, + "insufficientFundsError": "Insufficient funds", + "@insufficientFundsError": { + "description": "Error message when user has insufficient funds" + }, + "passwordTooShortError": "Password must be at least 8 characters", + "@passwordTooShortError": { + "description": "Error message for passwords that are too short" + }, + "passwordsDoNotMatchError": "Passwords do not match", + "@passwordsDoNotMatchError": { + "description": "Error message when password confirmation doesn't match" + }, + "invalidAmountError": "Please enter a valid amount", + "@invalidAmountError": { + "description": "Error message for invalid amount format" + }, + "amountTooLowError": "Amount too low", + "@amountTooLowError": { + "description": "Error message when amount is below minimum" + }, + "amountTooHighError": "Amount too high", + "@amountTooHighError": { + "description": "Error message when amount exceeds maximum" + } +} \ No newline at end of file diff --git a/lib/l10n/categories/navigation_en.arb b/lib/l10n/categories/navigation_en.arb new file mode 100644 index 000000000..613a47add --- /dev/null +++ b/lib/l10n/categories/navigation_en.arb @@ -0,0 +1,73 @@ +{ + "@@locale": "en", + "@@context": "Navigation labels and menu items", + + "walletsTab": "Wallets", + "@walletsTab": { + "description": "Bottom navigation tab label for wallets view" + }, + "exchangeTab": "Exchange", + "@exchangeTab": { + "description": "Bottom navigation tab label for exchange view" + }, + "buyTab": "Buy", + "@buyTab": { + "description": "Bottom navigation tab label for buy view" + }, + "settingsTab": "Settings", + "@settingsTab": { + "description": "Bottom navigation tab label for settings view" + }, + "notificationsTitle": "Notifications", + "@notificationsTitle": { + "description": "AppBar title for notifications screen" + }, + "sendFromTitle": "Send from", + "@sendFromTitle": { + "description": "AppBar title for send from screen" + }, + "swapTitle": "Swap", + "@swapTitle": { + "description": "AppBar title for swap screen" + }, + "fusionTitle": "Fusion", + "@fusionTitle": { + "description": "AppBar title for fusion screen" + }, + "churnTitle": "Churn", + "@churnTitle": { + "description": "AppBar title for churn screen" + }, + "addressBookTitle": "Address Book", + "@addressBookTitle": { + "description": "AppBar title for address book screen" + }, + "homeTitle": "Home", + "@homeTitle": { + "description": "AppBar title for home screen" + }, + "walletViewTitle": "Wallet", + "@walletViewTitle": { + "description": "AppBar title for wallet details screen" + }, + "ordinalViewTitle": "Ordinals", + "@ordinalViewTitle": { + "description": "AppBar title for ordinals screen" + }, + "tokensTitle": "Tokens", + "@tokensTitle": { + "description": "AppBar title for tokens screen" + }, + "backButton": "Back", + "@backButton": { + "description": "Back navigation button label" + }, + "menuButton": "Menu", + "@menuButton": { + "description": "Menu navigation button label" + }, + "searchHint": "Search...", + "@searchHint": { + "description": "Search field placeholder text" + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index c75000950..e1e5ec569 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -19,6 +19,7 @@ import 'package:cs_monero/cs_monero.dart' as lib_monero; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -36,6 +37,7 @@ import 'db/hive/db.dart'; import 'db/isar/main_db.dart'; import 'db/special_migrations.dart'; import 'db/sqlite/firo_cache.dart'; +import 'l10n/app_localizations.dart'; import 'models/exchange/change_now/exchange_transaction.dart'; import 'models/exchange/change_now/exchange_transaction_status.dart'; import 'models/exchange/response_objects/trade.dart'; @@ -707,12 +709,21 @@ class _MaterialAppWithThemeState extends ConsumerState // }); final colorScheme = ref.watch(colorProvider.state).state; + final localeService = ref.watch(localeServiceChangeNotifierProvider); return MaterialApp( key: GlobalKey(), navigatorKey: ref.read(pNavKey), title: AppConfig.appName, onGenerateRoute: RouteGenerator.generateRoute, + locale: localeService.currentLocale, + localizationsDelegates: const [ + AppLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: AppLocalizations.supportedLocales, theme: ThemeData( extensions: [colorScheme], highlightColor: colorScheme.highlight, diff --git a/lib/pages/intro_view.dart b/lib/pages/intro_view.dart index ef84551d4..8a59f4b39 100644 --- a/lib/pages/intro_view.dart +++ b/lib/pages/intro_view.dart @@ -15,6 +15,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:url_launcher/url_launcher.dart'; +import '../l10n/app_localizations.dart'; import '../app_config.dart'; import '../pages_desktop_specific/password/create_password_view.dart'; @@ -128,7 +129,7 @@ class _IntroViewState extends ConsumerState { if (isDesktop) const SizedBox(height: 20), if (isDesktop) SecondaryButton( - label: "Restore from ${AppConfig.prefix} backup", + label: AppLocalizations.of(context)!.restoreFromBackupButton(AppConfig.prefix), onPressed: () { Navigator.of(context).pushNamed( CreatePasswordView.routeName, @@ -174,7 +175,7 @@ class IntroAboutText extends StatelessWidget { @override Widget build(BuildContext context) { return Text( - AppConfig.shortDescriptionText, + AppLocalizations.of(context)!.welcomeTagline, textAlign: TextAlign.center, style: !isDesktop @@ -197,11 +198,11 @@ class PrivacyAndTOSText extends StatelessWidget { text: TextSpan( style: STextStyles.label(context).copyWith(fontSize: fontSize), children: [ - const TextSpan( - text: "By using ${AppConfig.appName}, you agree to the ", + TextSpan( + text: AppLocalizations.of(context)!.privacyAgreementText(AppConfig.appName), ), TextSpan( - text: "Terms of service", + text: AppLocalizations.of(context)!.termsOfServiceLinkText, style: STextStyles.richLink(context).copyWith(fontSize: fontSize), recognizer: TapGestureRecognizer() @@ -214,9 +215,9 @@ class PrivacyAndTOSText extends StatelessWidget { ); }, ), - const TextSpan(text: " and "), + TextSpan(text: AppLocalizations.of(context)!.privacyAgreementConjunction), TextSpan( - text: "Privacy policy", + text: AppLocalizations.of(context)!.privacyPolicyLinkText, style: STextStyles.richLink(context).copyWith(fontSize: fontSize), recognizer: TapGestureRecognizer() @@ -251,7 +252,7 @@ class GetStartedButton extends StatelessWidget { context, ).pushNamed(StackPrivacyCalls.routeName, arguments: false); }, - child: Text("Get started", style: STextStyles.button(context)), + child: Text(AppLocalizations.of(context)!.getStartedButton, style: STextStyles.button(context)), ) : SizedBox( width: double.infinity, @@ -266,7 +267,7 @@ class GetStartedButton extends StatelessWidget { ).pushNamed(StackPrivacyCalls.routeName, arguments: false); }, child: Text( - "Create new ${AppConfig.prefix}", + AppLocalizations.of(context)!.createNewWalletButton(AppConfig.prefix), style: STextStyles.button(context).copyWith(fontSize: 20), ), ), diff --git a/lib/pages/pinpad_views/lock_screen_view.dart b/lib/pages/pinpad_views/lock_screen_view.dart index 7a21a99c3..cc42e85c8 100644 --- a/lib/pages/pinpad_views/lock_screen_view.dart +++ b/lib/pages/pinpad_views/lock_screen_view.dart @@ -13,6 +13,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mutex/mutex.dart'; +import '../../l10n/app_localizations.dart'; import '../../notifications/show_flush_bar.dart'; import '../../providers/global/secure_store_provider.dart'; @@ -157,7 +158,7 @@ class _LockscreenViewState extends ConsumerState { ), opaqueBG: true, context: context, - message: "Loading wallets...", + message: AppLocalizations.of(context)!.loadingWalletsMessage, ); if (loadSuccess == null || loadSuccess == false) { @@ -381,8 +382,7 @@ class _LockscreenViewState extends ConsumerState { unawaited( showFloatingFlushBar( type: FlushBarType.warning, - message: - "Incorrect PIN entered too many times. Please wait $prettyTime", + message: AppLocalizations.of(context)!.incorrectPinThrottleError(prettyTime), context: context, iconAsset: Assets.svg.alertCircle, ), @@ -404,7 +404,7 @@ class _LockscreenViewState extends ConsumerState { unawaited( showFloatingFlushBar( type: FlushBarType.warning, - message: "Incorrect PIN. Please try again", + message: AppLocalizations.of(context)!.incorrectPinTryAgainError, context: context, iconAsset: Assets.svg.alertCircle, ), @@ -452,7 +452,7 @@ class _LockscreenViewState extends ConsumerState { if (ref.read(prefsChangeNotifierProvider).useBiometrics == true) CustomTextButton( - text: "Use biometrics", + text: AppLocalizations.of(context)!.useBiometricsButton, onTap: () async { await _checkUseBiometrics(); }, @@ -477,7 +477,7 @@ class _LockscreenViewState extends ConsumerState { children: [ Center( child: Text( - "Enter PIN", + AppLocalizations.of(context)!.enterPinTitle, style: STextStyles.pageTitleH1(context), ), ), diff --git a/lib/services/l10n_service.dart b/lib/services/l10n_service.dart new file mode 100644 index 000000000..f77ad9477 --- /dev/null +++ b/lib/services/l10n_service.dart @@ -0,0 +1,234 @@ +/* + * This file is part of Stack Wallet. + * + * Copyright (c) 2023 Cypher Stack + * All Rights Reserved. + * The code is distributed under GPLv3 license, see LICENSE file for details. + * Generated by Cypher Stack on 2024-08-19 + * + */ + +import 'package:flutter/material.dart'; + +import '../l10n/app_localizations.dart'; + +/// Helper service to simplify localization access throughout the application. +/// This service provides convenient methods to access localized strings +/// organized by category (navigation, buttons, forms, errors, dialogs). +class L10nService { + static AppLocalizations? _localizations; + + /// Initialize the service with the current BuildContext. + /// This should be called once when the app starts or when context changes. + static void init(BuildContext context) { + _localizations = AppLocalizations.of(context); + } + + /// Get the current AppLocalizations instance. + /// Returns null if not initialized. + static AppLocalizations? get current => _localizations; + + // Navigation-related text access methods + + /// Get navigation tab labels and AppBar titles + static String nav(String key) { + if (_localizations == null) return key; + + switch (key) { + case 'walletsTab': + return _localizations!.walletsTab; + case 'exchangeTab': + return _localizations!.exchangeTab; + case 'buyTab': + return _localizations!.buyTab; + case 'settingsTab': + return _localizations!.settingsTab; + case 'notificationsTitle': + return _localizations!.notificationsTitle; + case 'addressBookTitle': + return _localizations!.addressBookTitle; + case 'homeTitle': + return _localizations!.homeTitle; + case 'walletViewTitle': + return _localizations!.walletViewTitle; + case 'sendTitle': + return _localizations!.sendTitle; + case 'receiveTitle': + return _localizations!.receiveTitle; + case 'swapTitle': + return _localizations!.swapTitle; + case 'tokensTitle': + return _localizations!.tokensTitle; + default: + return key; + } + } + + /// Get button labels and action text + static String btn(String key) { + if (_localizations == null) return key; + + switch (key) { + case 'save': + return _localizations!.saveButton; + case 'cancel': + return _localizations!.cancelButton; + case 'continue': + return _localizations!.continueButton; + case 'edit': + return _localizations!.editButton; + case 'delete': + return _localizations!.deleteButton; + case 'next': + return _localizations!.nextButton; + case 'close': + return _localizations!.closeButton; + case 'ok': + return _localizations!.okButton; + case 'yes': + return _localizations!.yesButton; + case 'no': + return _localizations!.noButton; + case 'copy': + return _localizations!.copyButton; + case 'send': + return _localizations!.sendButton; + case 'receive': + return _localizations!.receiveButton; + case 'add': + return _localizations!.addButton; + default: + return key; + } + } + + /// Get form field labels and input hints + static String form(String key) { + if (_localizations == null) return key; + + switch (key) { + case 'name': + return _localizations!.nameLabel; + case 'amount': + return _localizations!.amountLabel; + case 'address': + return _localizations!.addressLabel; + case 'fee': + return _localizations!.feeLabel; + case 'note': + return _localizations!.noteLabel; + case 'password': + return _localizations!.passwordLabel; + case 'searchHint': + return _localizations!.searchHint; + case 'enterPasswordHint': + return _localizations!.enterPasswordHint; + case 'enterAmountHint': + return _localizations!.enterAmountHint; + case 'optionalHint': + return _localizations!.optionalHint; + default: + return key; + } + } + + /// Get error messages and validation text + static String error(String key) { + if (_localizations == null) return key; + + switch (key) { + case 'required': + return _localizations!.requiredFieldError; + case 'invalidEmail': + return _localizations!.invalidEmailError; + case 'invalidAddress': + return _localizations!.invalidAddressError; + case 'insufficientFunds': + return _localizations!.insufficientFundsError; + case 'network': + return _localizations!.networkError; + case 'transactionFailed': + return _localizations!.transactionFailed; + default: + return key; + } + } + + /// Get status messages + static String status(String key) { + if (_localizations == null) return key; + + switch (key) { + case 'loading': + return _localizations!.loadingStatus; + case 'processing': + return _localizations!.processingStatus; + case 'syncing': + return _localizations!.syncingStatus; + case 'completed': + return _localizations!.completedStatus; + case 'pending': + return _localizations!.pendingStatus; + case 'confirmed': + return _localizations!.confirmedStatus; + default: + return key; + } + } + + // Convenience methods for common use cases + + /// Quick access to AppBar titles + static String appBarTitle(String screenName) { + return nav('${screenName}Title'); + } + + /// Quick access to tab labels + static String tabLabel(String tabName) { + return nav('${tabName}Tab'); + } + + /// Quick access to form labels + static String formLabel(String fieldName) { + return form(fieldName); + } + + /// Quick access to button labels + static String buttonLabel(String buttonName) { + return btn(buttonName); + } + + /// Quick access to error messages + static String errorMessage(String errorType) { + return error(errorType); + } + + /// Quick access to status messages + static String statusMessage(String statusType) { + return status(statusType); + } + + // Dynamic content helpers for future use + + /// Format amount with currency (for future parameterized translations) + static String formatAmount(String currency, double value) { + // TODO: Implement parameterized translation when ARB supports it + return '$value $currency'; + } + + /// Format transaction status (for future parameterized translations) + static String formatTransaction(String type, String status) { + // TODO: Implement parameterized translation when ARB supports it + return '$type: $status'; + } + + /// Handle pluralization (for future implementation) + static String plural(String key, int count) { + // TODO: Implement proper pluralization when ARB supports it + if (count == 1) { + return key; + } else { + return '${key}s'; + } + } +} diff --git a/lib/services/locale_service.dart b/lib/services/locale_service.dart index 8cfb6f765..8a9deea61 100644 --- a/lib/services/locale_service.dart +++ b/lib/services/locale_service.dart @@ -17,6 +17,14 @@ class LocaleService extends ChangeNotifier { String _locale = "en_US"; // use default String get locale => _locale; + + Locale get currentLocale { + final parts = _locale.split('_'); + if (parts.length == 2) { + return Locale(parts[0], parts[1]); + } + return Locale(parts[0]); + } Future loadLocale({bool notify = true}) async { _locale = Platform.isWindows @@ -26,4 +34,25 @@ class LocaleService extends ChangeNotifier { notifyListeners(); } } + + void setLocale(String newLocale, {bool notify = true}) { + // Convert simple locale codes to full locale strings. + switch (newLocale) { + case 'en': + _locale = 'en_US'; + break; + case 'es': + _locale = 'es_ES'; + break; + case 'ar': + _locale = 'ar_SA'; + break; + default: + _locale = newLocale; + } + + if (notify) { + notifyListeners(); + } + } } diff --git a/pubspec.lock b/pubspec.lock index 4ef194c2b..a267d1067 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -813,11 +813,11 @@ packages: dependency: "direct main" description: path: "." - ref: f0b1300140d45c13e7722f8f8d20308efeba8449 - resolved-ref: f0b1300140d45c13e7722f8f8d20308efeba8449 + ref: "794ab2d7b88b34d64a89518f9b9f41dcc235aca1" + resolved-ref: "794ab2d7b88b34d64a89518f9b9f41dcc235aca1" url: "https://github.com/cypherstack/electrum_adapter.git" source: git - version: "3.0.0" + version: "3.0.2" emojis: dependency: "direct main" description: @@ -981,6 +981,11 @@ packages: url: "https://pub.dev" source: hosted version: "7.2.0" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_mwebd: dependency: "direct main" description: @@ -1119,8 +1124,8 @@ packages: dependency: "direct main" description: path: "." - ref: afaad488f5215a9c2c211e5e2f8460237eef60f1 - resolved-ref: afaad488f5215a9c2c211e5e2f8460237eef60f1 + ref: "540d0bc7dc27a97d45d63f412f26818a7f3b8b51" + resolved-ref: "540d0bc7dc27a97d45d63f412f26818a7f3b8b51" url: "https://github.com/cypherstack/fusiondart.git" source: git version: "1.0.0" @@ -1285,10 +1290,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.19.0" io: dependency: transitive description: @@ -1963,11 +1968,10 @@ packages: socks_socket: dependency: transitive description: - path: "." - ref: master - resolved-ref: e6232c53c1595469931ababa878759a067c02e94 - url: "https://github.com/cypherstack/socks_socket.git" - source: git + name: socks_socket + sha256: "53bc7eae40a3aa16ea810b0e9de3bb23ba7beb0b40d09357b89190f2f44374cc" + url: "https://pub.dev" + source: hosted version: "1.1.1" solana: dependency: "direct main" @@ -2200,8 +2204,8 @@ packages: dependency: "direct main" description: path: "." - ref: "752f054b65c500adb9cad578bf183a978e012502" - resolved-ref: "752f054b65c500adb9cad578bf183a978e012502" + ref: "16c9e709e984ec89e8715ce378b038c93ad7add3" + resolved-ref: "16c9e709e984ec89e8715ce378b038c93ad7add3" url: "https://github.com/cypherstack/tor.git" source: git version: "0.0.1" diff --git a/scripts/app_config/templates/pubspec.template b/scripts/app_config/templates/pubspec.template index 84826bc28..03be06b4f 100644 --- a/scripts/app_config/templates/pubspec.template +++ b/scripts/app_config/templates/pubspec.template @@ -20,6 +20,8 @@ environment: dependencies: flutter: sdk: flutter + flutter_localizations: + sdk: flutter ffi: ^2.0.1 mutex: ^3.0.0 web_socket_channel: ^2.4.0 @@ -124,7 +126,7 @@ dependencies: mobile_scanner: ^7.0.1 image: ^4.3.0 wakelock_plus: ^1.2.8 - intl: ^0.17.0 + intl: ^0.19.0 devicelocale: git: url: https://github.com/cypherstack/flutter-devicelocale @@ -312,6 +314,9 @@ flutter: # the material Icons class. uses-material-design: true + # Add i18n support. + generate: true + # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg