diff --git a/secant.xcodeproj/project.pbxproj b/secant.xcodeproj/project.pbxproj index 01101ec..cce1d9b 100644 --- a/secant.xcodeproj/project.pbxproj +++ b/secant.xcodeproj/project.pbxproj @@ -1138,12 +1138,12 @@ 2E35F99027B28E6800EB79CD /* TextFields */ = { isa = PBXGroup; children = ( + 2E35F99127B28E7600EB79CD /* SingleLineTextField.swift */, + 2EDA07A527EDE31100D6F09B /* Components */, 9E7225F4288AC6F300DF7F17 /* MultiLineTextField */, 9E7FE0F0282E80C100C374E8 /* TCATextField */, - 2E35F99127B28E7600EB79CD /* SingleLineTextField.swift */, 9E5BF64C2823E84300BA3F17 /* TransactionAddress */, 9E5BF64B2823C91200BA3F17 /* TransactionAmount */, - 2EDA07A527EDE31100D6F09B /* Components */, ); path = TextFields; sourceTree = ""; @@ -1622,7 +1622,6 @@ 9E7FE0BB282D1DC200C374E8 /* Utils */ = { isa = PBXGroup; children = ( - 9E0F573F297E7F00005304FA /* Logging */, 9E7FE0D4282D281800C374E8 /* Array+Chunked.swift */, F9C165B3274031F600592F76 /* Bindings.swift */, 0DACFA7E27208CE00039EEA5 /* Clamped.swift */, @@ -1640,6 +1639,7 @@ 0DACFA8027208D940039EEA5 /* UInt+SuperscriptText.swift */, 0D7CE63327349B5D0020E050 /* View+WhenDraggable.swift */, F9EEB8152742C2210032EEB8 /* WithStateBinding.swift */, + 9E0F573F297E7F00005304FA /* Logging */, ); path = Utils; sourceTree = ""; @@ -2405,9 +2405,10 @@ inputFileListPaths = ( ); inputPaths = ( - "$(SRCROOT)/swiftlint.yml", "$(SRCROOT)/secant/Resources/Colors.xcassets", "$(SRCROOT)/secant/Resources/Assets/xcassets", + "$(SRCROOT)/secant/Resources/Localizable.strings", + "$(SRCROOT)/swiftgen.yml", ); name = SwiftGen; outputFileListPaths = ( @@ -2415,6 +2416,7 @@ outputPaths = ( "$(DERIVED_FILE_DIR)/Resources/Generated/XCAssets+Generated.swift", "$(DERIVED_FILE_DIR)/Resources/Generated/Fonts+Generated.swift", + "$(DERIVED_FILE_DIR)/Resources/Generated/L10n.swift", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -2503,10 +2505,10 @@ inputFileListPaths = ( ); inputPaths = ( - "$(SRCROOT)/swiftlint.yml", "$(SRCROOT)/secant/Resources/Colors.xcassets", "$(SRCROOT)/secant/Resources/Assets/xcassets", - "$(SRCROOT)/Resources/Localizable.strings", + "$(SRCROOT)/secant/Resources/Localizable.strings", + "$(SRCROOT)/swiftgen.yml", ); name = SwiftGen; outputFileListPaths = ( diff --git a/secant/Dependencies/LocalAuthentication/LocalAuthenticationLiveKey.swift b/secant/Dependencies/LocalAuthentication/LocalAuthenticationLiveKey.swift index af9e7a4..cc04b00 100644 --- a/secant/Dependencies/LocalAuthentication/LocalAuthenticationLiveKey.swift +++ b/secant/Dependencies/LocalAuthentication/LocalAuthenticationLiveKey.swift @@ -13,7 +13,7 @@ extension LocalAuthenticationClient: DependencyKey { authenticate: { let context = LAContext() var error: NSError? - let reason = "The Following content requires authentication." + let reason = L10n.LocalAuthentication.reason do { /// Biometrics validation diff --git a/secant/Dependencies/SDKSynchronizer/SDKSynchronizerMocks.swift b/secant/Dependencies/SDKSynchronizer/SDKSynchronizerMocks.swift index 7ab38d6..e3554af 100644 --- a/secant/Dependencies/SDKSynchronizer/SDKSynchronizerMocks.swift +++ b/secant/Dependencies/SDKSynchronizer/SDKSynchronizerMocks.swift @@ -166,9 +166,12 @@ class MockSDKSynchronizerClient: SDKSynchronizerClient { } func getUnifiedAddress(account: Int) -> UnifiedAddress? { - // swiftlint:disable line_length force_try + // swiftlint:disable force_try try! UnifiedAddress( - encoding: "utest1zkkkjfxkamagznjr6ayemffj2d2gacdwpzcyw669pvg06xevzqslpmm27zjsctlkstl2vsw62xrjktmzqcu4yu9zdhdxqz3kafa4j2q85y6mv74rzjcgjg8c0ytrg7dwyzwtgnuc76h", + encoding: """ + utest1zkkkjfxkamagznjr6ayemffj2d2gacdwpzcyw669pvg06xevzqslpmm27zjsctlkstl2vsw62xrjktmzqcu4yu9zdhdxqz3kafa4j2q85y6mv74rzjcgjg8c0ytrg7dwyz\ + wtgnuc76h + """, network: .testnet ) } diff --git a/secant/Dependencies/SupportDataGenerator/SupportDataGenerator.swift b/secant/Dependencies/SupportDataGenerator/SupportDataGenerator.swift index 401fa0c..4959a47 100644 --- a/secant/Dependencies/SupportDataGenerator/SupportDataGenerator.swift +++ b/secant/Dependencies/SupportDataGenerator/SupportDataGenerator.swift @@ -44,7 +44,7 @@ private protocol SupportDataGeneratorItem { private struct TimeItem: SupportDataGeneratorItem { private enum Constants { - static let timeKey = "Current time" + static let timeKey = L10n.SupportData.TimeItem.time } let dateFormatter: DateFormatter @@ -62,9 +62,9 @@ private struct TimeItem: SupportDataGeneratorItem { private struct AppVersionItem: SupportDataGeneratorItem { private enum Constants { - static let bundleIdentifierKey = "App identifier" - static let versionKey = "App version" - static let unknownVersion = "Unknown" + static let bundleIdentifierKey = L10n.SupportData.AppVersionItem.bundleIdentifier + static let versionKey = L10n.SupportData.AppVersionItem.version + static let unknownVersion = L10n.General.unknown } func generate() -> [(String, String)] { @@ -88,7 +88,7 @@ private struct AppVersionItem: SupportDataGeneratorItem { private struct SystemVersionItem: SupportDataGeneratorItem { private enum Constants { - static let systemVersionKey = "iOS version" + static let systemVersionKey = L10n.SupportData.SystemVersionItem.version } func generate() -> [(String, String)] { @@ -98,8 +98,8 @@ private struct SystemVersionItem: SupportDataGeneratorItem { private struct DeviceModelItem: SupportDataGeneratorItem { private enum Constants { - static let deviceModelKey = "Device" - static let unknownDevice = "unknown" + static let deviceModelKey = L10n.SupportData.DeviceModelItem.device + static let unknownDevice = L10n.General.unknown } func generate() -> [(String, String)] { @@ -117,17 +117,17 @@ private struct DeviceModelItem: SupportDataGeneratorItem { private struct LocaleItem: SupportDataGeneratorItem { private enum Constants { - static let localKey = "Locale" - static let groupingSeparatorKey = "Currency grouping separato" - static let decimalSeparatorKey = "Currency decimal separator" - static let unknownSeparator = "unknown" + static let localeKey = L10n.SupportData.LocaleItem.locale + static let groupingSeparatorKey = L10n.SupportData.LocaleItem.groupingSeparator + static let decimalSeparatorKey = L10n.SupportData.LocaleItem.decimalSeparator + static let unknownSeparator = L10n.General.unknown } func generate() -> [(String, String)] { let locale = Locale.current return [ - (Constants.localKey, locale.identifier), + (Constants.localeKey, locale.identifier), (Constants.groupingSeparatorKey, locale.groupingSeparator ?? Constants.unknownSeparator), (Constants.decimalSeparatorKey, locale.decimalSeparator ?? Constants.unknownSeparator) ] @@ -136,8 +136,8 @@ private struct LocaleItem: SupportDataGeneratorItem { private struct FreeDiskSpaceItem: SupportDataGeneratorItem { private enum Constants { - static let freeDiskSpaceKey = "Usable storage" - static let freeDiskSpaceUnknown = "unknown" + static let freeDiskSpaceKey = L10n.SupportData.FreeDiskSpaceItem.freeDiskSpace + static let freeDiskSpaceUnknown = L10n.General.unknown } func generate() -> [(String, String)] { @@ -162,12 +162,12 @@ private struct FreeDiskSpaceItem: SupportDataGeneratorItem { private struct PermissionsItems: SupportDataGeneratorItem { private enum Constants { - static let permissionsKey = "Permissions" - static let cameraPermKey = "Camera access" - static let faceIDAvailable = "FaceID available" - static let touchIDAvailable = "TouchID available" - static let yesText = "yes" - static let noText = "no" + static let permissionsKey = L10n.SupportData.PermissionItem.permissions + static let cameraPermKey = L10n.SupportData.PermissionItem.camera + static let faceIDAvailable = L10n.SupportData.PermissionItem.faceID + static let touchIDAvailable = L10n.SupportData.PermissionItem.touchID + static let yesText = L10n.General.yes + static let noText = L10n.General.no } func generate() -> [(String, String)] { diff --git a/secant/Dependencies/WalletConfigProvider/UserDefaultsWalletConfigStorage.swift b/secant/Dependencies/WalletConfigProvider/UserDefaultsWalletConfigStorage.swift index 6018e7e..b493b8a 100644 --- a/secant/Dependencies/WalletConfigProvider/UserDefaultsWalletConfigStorage.swift +++ b/secant/Dependencies/WalletConfigProvider/UserDefaultsWalletConfigStorage.swift @@ -29,7 +29,7 @@ struct UserDefaultsWalletConfigStorage { let rawFlags = try PropertyListDecoder().decode(WalletConfig.RawFlags.self, from: data) return WalletConfig(flags: rawFlags) } catch { - LoggerProxy.debug("Error when deocding feature flags from user defaults: \(error)") + LoggerProxy.debug("Error when decoding feature flags from user defaults: \(error)") throw InternalError.unableToDeserializeData } } diff --git a/secant/Features/AddressDetails/AddressDetailsStore.swift b/secant/Features/AddressDetails/AddressDetailsStore.swift index dd3061e..86c44a0 100644 --- a/secant/Features/AddressDetails/AddressDetailsStore.swift +++ b/secant/Features/AddressDetails/AddressDetailsStore.swift @@ -16,15 +16,15 @@ struct AddressDetailsReducer: ReducerProtocol { var uAddress: UnifiedAddress? var unifiedAddress: String { - uAddress?.stringEncoded ?? "could not extract UA" + uAddress?.stringEncoded ?? L10n.AddressDetails.Error.cantExtractUnifiedAddress } var transparentAddress: String { - uAddress?.transparentReceiver()?.stringEncoded ?? "could not extract transparent receiver from UA" + uAddress?.transparentReceiver()?.stringEncoded ?? L10n.AddressDetails.Error.cantExtractTransparentAddress } var saplingAddress: String { - uAddress?.saplingReceiver()?.stringEncoded ?? "could not extract sapling receiver from UA" + uAddress?.saplingReceiver()?.stringEncoded ?? L10n.AddressDetails.Error.cantExtractSaplingAddress } } diff --git a/secant/Features/AddressDetails/AddressDetailsView.swift b/secant/Features/AddressDetails/AddressDetailsView.swift index 2a2673c..82f3491 100644 --- a/secant/Features/AddressDetails/AddressDetailsView.swift +++ b/secant/Features/AddressDetails/AddressDetailsView.swift @@ -19,7 +19,7 @@ struct AddressDetailsView: View { qrCode(viewStore.unifiedAddress) .padding(30) - Text("\(viewStore.unifiedAddress)") + Text(viewStore.unifiedAddress) .onTapGesture { viewStore.send(.copyUnifiedAddressToPastboard) } @@ -30,7 +30,7 @@ struct AddressDetailsView: View { qrCode(viewStore.saplingAddress) .padding(30) - Text("\(viewStore.saplingAddress)") + Text(viewStore.saplingAddress) .onTapGesture { viewStore.send(.copySaplingAddressToPastboard) } @@ -41,7 +41,7 @@ struct AddressDetailsView: View { qrCode(viewStore.transparentAddress) .padding(30) - Text("\(viewStore.transparentAddress)") + Text(viewStore.transparentAddress) .onTapGesture { viewStore.send(.copyTransparentAddressToPastboard) } diff --git a/secant/Features/BalanceBreakdown/BalanceBreakdownStore.swift b/secant/Features/BalanceBreakdown/BalanceBreakdownStore.swift index b77df34..240cfb0 100644 --- a/secant/Features/BalanceBreakdown/BalanceBreakdownStore.swift +++ b/secant/Features/BalanceBreakdown/BalanceBreakdownStore.swift @@ -65,7 +65,7 @@ struct BalanceBreakdownReducer: ReducerProtocol { case .updateLatestBlock: guard let latestBlockNumber = sdkSynchronizer.latestScannedSynchronizerState?.latestScannedHeight, let latestBlock = numberFormatter.string(NSDecimalNumber(value: latestBlockNumber)) else { - state.latestBlock = "unknown" + state.latestBlock = L10n.General.unknown return .none } state.latestBlock = "\(latestBlock)" @@ -79,7 +79,7 @@ struct BalanceBreakdownReducer: ReducerProtocol { extension BalanceBreakdownReducer.State { static let placeholder = BalanceBreakdownReducer.State( autoShieldingThreshold: Zatoshi(1_000_000), - latestBlock: "unknown", + latestBlock: L10n.General.unknown, shieldedBalance: Balance.zero, transparentBalance: Balance.zero ) diff --git a/secant/Features/ExportLogs/ExportLogsStore.swift b/secant/Features/ExportLogs/ExportLogsStore.swift index 004d1b9..6c1aaf9 100644 --- a/secant/Features/ExportLogs/ExportLogsStore.swift +++ b/secant/Features/ExportLogs/ExportLogsStore.swift @@ -81,9 +81,9 @@ struct ExportLogsReducer: ReducerProtocol { case let .failed(errorDescription): // TODO: [#527] address the error here https://github.com/zcash/secant-ios-wallet/issues/527 state.alert = AlertState( - title: TextState("Error when exporting logs"), - message: TextState("Error: \(errorDescription)"), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.ExportLogs.Alert.Failed.title), + message: TextState(L10n.ExportLogs.Alert.Failed.message(errorDescription)), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) return .none diff --git a/secant/Features/Home/HomeView.swift b/secant/Features/Home/HomeView.swift index b013ba0..5d35c05 100644 --- a/secant/Features/Home/HomeView.swift +++ b/secant/Features/Home/HomeView.swift @@ -112,7 +112,7 @@ extension HomeView { .font(.system(size: 20)) } - Text("\(viewStore.synchronizerStatusSnapshot.message)") + Text(viewStore.synchronizerStatusSnapshot.message) } .foregroundColor(Asset.Colors.Mfp.primary.color) } diff --git a/secant/Features/ImportWallet/ImportBirthdayView.swift b/secant/Features/ImportWallet/ImportBirthdayView.swift index 29ffc63..d91682b 100644 --- a/secant/Features/ImportWallet/ImportBirthdayView.swift +++ b/secant/Features/ImportWallet/ImportBirthdayView.swift @@ -14,20 +14,20 @@ struct ImportBirthdayView: View { var body: some View { WithViewStore(store) { viewStore in VStack { - Text("importWallet.birthday.description") + Text(L10n.ImportWallet.Birthday.description) .font(.system(size: 16)) .fontWeight(.bold) .foregroundColor(Asset.Colors.Mfp.fontDark.color) TextField( - "importWallet.birthday.placeholder", + L10n.ImportWallet.Birthday.placeholder, text: viewStore.bindingForRedactableBirthday(viewStore.birthdayHeight) ) .keyboardType(.numberPad) .autocapitalization(.none) .importSeedEditorModifier() - Button("importWallet.button.restoreWallet") { + Button(L10n.ImportWallet.Button.restoreWallet) { viewStore.send(.restoreWallet) } .activeButtonStyle diff --git a/secant/Features/ImportWallet/ImportWalletStore.swift b/secant/Features/ImportWallet/ImportWalletStore.swift index 807d009..fc9bf77 100644 --- a/secant/Features/ImportWallet/ImportWalletStore.swift +++ b/secant/Features/ImportWallet/ImportWalletStore.swift @@ -30,7 +30,7 @@ struct ImportWalletReducer: ReducerProtocol { var mnemonicStatus: String { if isValidMnemonic { - return "VALID SEED PHRASE" + return L10n.ImportWallet.Seed.valid } else { return "\(wordsCount)/\(maxWordsCount)" } @@ -118,10 +118,10 @@ struct ImportWalletReducer: ReducerProtocol { // notify user // TODO: [#221] Proper Error/Success handling (https://github.com/zcash/secant-ios-wallet/issues/221) state.alert = AlertState( - title: TextState("Success"), - message: TextState("The wallet has been successfully recovered."), + title: TextState(L10n.General.success), + message: TextState(L10n.ImportWallet.Alert.Success.message), dismissButton: .default( - TextState("Ok"), + TextState(L10n.General.ok), action: .send(.successfullyRecovered) ) ) @@ -130,10 +130,10 @@ struct ImportWalletReducer: ReducerProtocol { } catch { // TODO: [#221] Proper Error/Success handling (https://github.com/zcash/secant-ios-wallet/issues/221) state.alert = AlertState( - title: TextState("Failed to restore wallet"), - message: TextState("Error: \(error.localizedDescription)"), + title: TextState(L10n.ImportWallet.Alert.Failed.title), + message: TextState(L10n.ImportWallet.Alert.Failed.message(error.localizedDescription)), dismissButton: .default( - TextState("Ok"), + TextState(L10n.General.ok), action: .send(.dismissAlert) ) ) diff --git a/secant/Features/Profile/ProfileStore.swift b/secant/Features/Profile/ProfileStore.swift index 121e83c..5ce0e1f 100644 --- a/secant/Features/Profile/ProfileStore.swift +++ b/secant/Features/Profile/ProfileStore.swift @@ -18,7 +18,7 @@ struct ProfileReducer: ReducerProtocol { var sdkVersion = "" var unifiedAddress: String { - addressDetailsState.uAddress?.stringEncoded ?? "could not extract UA" + addressDetailsState.uAddress?.stringEncoded ?? L10n.ReceiveZec.Error.cantExtractUnifiedAddress } } diff --git a/secant/Features/Root/RootDebug.swift b/secant/Features/Root/RootDebug.swift index a18bf34..a7c0351 100644 --- a/secant/Features/Root/RootDebug.swift +++ b/secant/Features/Root/RootDebug.swift @@ -39,12 +39,12 @@ extension RootReducer { case .debug(.rescanBlockchain): state.debugState.rescanDialog = .init( - title: TextState("Rescan"), - message: TextState("Select the rescan you want"), + title: TextState(L10n.Root.Debug.Dialog.Rescan.title), + message: TextState(L10n.Root.Debug.Dialog.Rescan.message), buttons: [ - .default(TextState("Quick rescan"), action: .send(.debug(.quickRescan))), - .default(TextState("Full rescan"), action: .send(.debug(.fullRescan))), - .cancel(TextState("Cancel")) + .default(TextState(L10n.Root.Debug.Dialog.Rescan.Option.quick), action: .send(.debug(.quickRescan))), + .default(TextState(L10n.Root.Debug.Dialog.Rescan.Option.full), action: .send(.debug(.fullRescan))), + .cancel(TextState(L10n.General.cancel)) ] ) return .none @@ -65,9 +65,9 @@ extension RootReducer { if let errorDescription { // TODO: [#221] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/221) state.alert = AlertState( - title: TextState("Rewind failed"), - message: TextState("Error: \(errorDescription)"), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.Root.Debug.Alert.Rewind.Failed.title), + message: TextState(L10n.Root.Debug.Alert.Rewind.Failed.message(errorDescription)), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) } else { do { @@ -75,9 +75,9 @@ extension RootReducer { } catch { // TODO: [#221] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/221) state.alert = AlertState( - title: TextState("Can't start sync process after rewind"), - message: TextState("Error: \(error.localizedDescription)"), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.Root.Debug.Alert.Rewind.CantStartSync.title), + message: TextState(L10n.Root.Debug.Alert.Rewind.CantStartSync.message(error.localizedDescription)), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) } } @@ -108,7 +108,7 @@ extension RootReducer { private func rewind(policy: RewindPolicy, sourceAction: DebugAction) -> EffectPublisher { guard let rewindPublisher = sdkSynchronizer.rewind(policy) else { - return EffectTask(value: .debug(.rewindDone("SDKSynchronizer not initilized. rewindPublisher is nil", .debug(sourceAction)))) + return EffectTask(value: .debug(.rewindDone(L10n.Root.Debug.Error.Rewind.sdkSynchronizerNotInitialized, .debug(sourceAction)))) } return rewindPublisher .replaceEmpty(with: Void()) diff --git a/secant/Features/Root/RootDestination.swift b/secant/Features/Root/RootDestination.swift index 357ec16..99c5405 100644 --- a/secant/Features/Root/RootDestination.swift +++ b/secant/Features/Root/RootDestination.swift @@ -115,10 +115,10 @@ extension RootReducer { case let .destination(.deeplinkFailed(url, errorDescription)): // TODO: [#221] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/221) state.destinationState.alert = AlertState( - title: TextState("Failed to process deeplink."), - message: TextState("Deeplink: \(url))\nError: \(errorDescription)"), + title: TextState(L10n.Root.Destination.Alert.FailedToProcessDeeplink.title), + message: TextState(L10n.Root.Destination.Alert.FailedToProcessDeeplink.message(url, errorDescription)), dismissButton: .default( - TextState("Ok"), + TextState(L10n.General.ok), action: .send(.destination(.dismissAlert)) ) ) diff --git a/secant/Features/Root/RootInitialization.swift b/secant/Features/Root/RootInitialization.swift index 1589f3c..c1738a2 100644 --- a/secant/Features/Root/RootInitialization.swift +++ b/secant/Features/Root/RootInitialization.swift @@ -82,17 +82,17 @@ extension RootReducer { // TODO: [#221] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/221) state.appInitializationState = .failed state.alert = AlertState( - title: TextState("Wallet initialisation failed."), - message: TextState("App initialisation state: failed"), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.Root.Initialization.Alert.Failed.title), + message: TextState(L10n.Root.Initialization.Alert.WalletStateFailed.message(walletState)), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) case .keysMissing: // TODO: [#221] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/221) state.appInitializationState = .keysMissing state.alert = AlertState( - title: TextState("Wallet initialisation failed."), - message: TextState("App initialisation state: keysMissing."), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.Root.Initialization.Alert.Failed.title), + message: TextState(L10n.Root.Initialization.Alert.WalletStateFailed.message(walletState)), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) case .initialized, .filesMissing: @@ -123,9 +123,9 @@ extension RootReducer { state.appInitializationState = .failed // TODO: [#221] Handle fatal error more properly (https://github.com/zcash/secant-ios-wallet/issues/221) state.alert = AlertState( - title: TextState("Wallet initialisation failed."), - message: TextState("Can't load seed phrase from local storage."), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.Root.Initialization.Alert.Failed.title), + message: TextState(L10n.Root.Initialization.Alert.CantLoadSeedPhrase.message), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) return .none } @@ -151,9 +151,9 @@ extension RootReducer { state.appInitializationState = .failed // TODO: [#221] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/221) state.alert = AlertState( - title: TextState("Failed to initialize the SDK"), - message: TextState("Error: \(error.localizedDescription)"), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.Root.Initialization.Alert.SdkInitFailed.title), + message: TextState(L10n.Root.Initialization.Alert.Error.message(error.localizedDescription)), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) return .none } @@ -163,9 +163,9 @@ extension RootReducer { state.appInitializationState = .failed // TODO: [#221] Handle fatal error more properly (https://github.com/zcash/secant-ios-wallet/issues/221) state.alert = AlertState( - title: TextState("Wallet initialisation failed."), - message: TextState("Can't load seed phrase from local storage."), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.Root.Initialization.Alert.Failed.title), + message: TextState(L10n.Root.Initialization.Alert.CantLoadSeedPhrase.message), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) return .none } @@ -210,9 +210,9 @@ extension RootReducer { } catch { // TODO: [#201] - merge with issue 221 (https://github.com/zcash/secant-ios-wallet/issues/221) and its Error States state.alert = AlertState( - title: TextState("Wallet initialisation failed."), - message: TextState("Can't create new wallet. Error: \(error.localizedDescription)"), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.Root.Initialization.Alert.Failed.title), + message: TextState(L10n.Root.Initialization.Alert.CantCreateNewWallet.message(error.localizedDescription)), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) } @@ -224,24 +224,26 @@ extension RootReducer { } catch { // TODO: [#221] error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221) state.alert = AlertState( - title: TextState("Wallet initialisation failed."), - message: TextState("Can't store information that user passed phrase backup test. Error: \(error.localizedDescription)"), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.Root.Initialization.Alert.Failed.title), + message: TextState( + L10n.Root.Initialization.Alert.CantStoreThatUserPassedPhraseBackupTest.message(error.localizedDescription) + ), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) } return .none case .initialization(.nukeWalletRequest): state.destinationState.alert = AlertState( - title: TextState("Wipe of the wallet"), - message: TextState("Are you sure?"), + title: TextState(L10n.Root.Initialization.Alert.Wipe.title), + message: TextState(L10n.Root.Initialization.Alert.Wipe.message), buttons: [ .destructive( - TextState("Yes"), + TextState(L10n.General.yes), action: .send(.initialization(.nukeWallet)) ), .cancel( - TextState("No"), + TextState(L10n.General.no), action: .send(.destination(.dismissAlert)) ) ] @@ -272,9 +274,9 @@ extension RootReducer { case .nukeWalletFailed: // TODO: [#221] error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221) state.alert = AlertState( - title: TextState("Nuke of the wallet failed"), + title: TextState(L10n.Root.Initialization.Alert.WipeFailed.title), message: TextState(""), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) let backDestination: EffectTask diff --git a/secant/Features/Root/RootView.swift b/secant/Features/Root/RootView.swift index 2683ea9..2094c52 100644 --- a/secant/Features/Root/RootView.swift +++ b/secant/Features/Root/RootView.swift @@ -123,7 +123,7 @@ private extension RootView { @ViewBuilder func debugView(_ viewStore: RootViewStore) -> some View { VStack(alignment: .leading) { if viewStore.destinationState.previousDestination == .home { - Button("general.back") { + Button(L10n.General.back) { viewStore.goToDestination(.home) } .activeButtonStyle @@ -132,42 +132,42 @@ private extension RootView { } List { - Section(header: Text("Navigation Stack Destinations")) { - Button("Go To Sandbox (navigation proof)") { + Section(header: Text(L10n.Root.Debug.title)) { + Button(L10n.Root.Debug.Option.gotoSandbox) { viewStore.goToDestination(.sandbox) } - Button("Go To Onboarding") { + Button(L10n.Root.Debug.Option.gotoOnboarding) { viewStore.goToDestination(.onboarding) } - Button("Go To Phrase Validation Demo") { + Button(L10n.Root.Debug.Option.gotoPhraseValidationDemo) { viewStore.goToDestination(.phraseValidation) } - Button("Restart the app") { + Button(L10n.Root.Debug.Option.restartApp) { viewStore.goToDestination(.welcome) } - Button("Test Crash Reporter") { + Button(L10n.Root.Debug.Option.testCrashReporter) { viewStore.send(.debug(.testCrashReporter)) } - Button("Export logs") { + Button(L10n.Root.Debug.Option.exportLogs) { viewStore.send(.exportLogs(.start)) } .disabled(viewStore.exportLogsState.exportLogsDisabled) - Button("Rescan Blockchain") { + Button(L10n.Root.Debug.Option.rescanBlockchain) { viewStore.send(.debug(.rescanBlockchain)) } - Button("[Be careful] Nuke Wallet") { + Button(L10n.Root.Debug.Option.nukeWallet) { viewStore.send(.initialization(.nukeWalletRequest)) } } - Section(header: Text("Feature flags")) { + Section(header: Text(L10n.Root.Debug.featureFlags)) { let flags = viewStore.state.walletConfig.flags .map { FeatureFlagWrapper(name: $0.key, isEnabled: $0.value) } .sorted() @@ -204,7 +204,7 @@ private extension RootView { dismiss: .debug(.cancelRescan) ) } - .navigationBarTitle("Startup") + .navigationBarTitle(L10n.Root.Debug.navigationTitle) } } diff --git a/secant/Features/Scan/ScanStore.swift b/secant/Features/Scan/ScanStore.swift index 657c211..504149e 100644 --- a/secant/Features/Scan/ScanStore.swift +++ b/secant/Features/Scan/ScanStore.swift @@ -68,9 +68,9 @@ struct ScanReducer: ReducerProtocol { } catch { // TODO: [#322] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/322) state.alert = AlertState( - title: TextState("Can't initialize the camera"), - message: TextState("Error: \(error.localizedDescription)"), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.Scan.Alert.CantInitializeCamera.title), + message: TextState(L10n.Scan.Alert.CantInitializeCamera.message(error.localizedDescription)), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) } return .none @@ -117,9 +117,9 @@ struct ScanReducer: ReducerProtocol { } catch { // TODO: [#322] handle torch errors (https://github.com/zcash/secant-ios-wallet/issues/322) state.alert = AlertState( - title: TextState("Can't initialize the camera"), - message: TextState("Error: \(error.localizedDescription)"), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.Scan.Alert.CantInitializeCamera.title), + message: TextState(L10n.Scan.Alert.CantInitializeCamera.message(error.localizedDescription)), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) } return .none diff --git a/secant/Features/Scan/ScanView.swift b/secant/Features/Scan/ScanView.swift index 6eef881..20b0365 100644 --- a/secant/Features/Scan/ScanView.swift +++ b/secant/Features/Scan/ScanView.swift @@ -38,7 +38,7 @@ struct ScanView: View { .padding(.bottom, 10) if let scannedValue = viewStore.scannedValue { - Text("\(scannedValue)") + Text(scannedValue) .foregroundColor(viewStore.isValidValue ? .green : .red) } else { Text(L10n.Scan.scanning) diff --git a/secant/Features/Settings/SettingsStore.swift b/secant/Features/Settings/SettingsStore.swift index d47131a..3a99698 100644 --- a/secant/Features/Settings/SettingsStore.swift +++ b/secant/Features/Settings/SettingsStore.swift @@ -63,9 +63,9 @@ struct SettingsReducer: ReducerProtocol { } catch { // TODO: [#221] - merge with issue 221 (https://github.com/zcash/secant-ios-wallet/issues/221) and its Error States state.alert = AlertState( - title: TextState("Can't backup wallet"), - message: TextState("Error: \(error.localizedDescription)"), - dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert)) + title: TextState(L10n.Settings.Alert.CantBackupWallet.title), + message: TextState(L10n.Settings.Alert.CantBackupWallet.message(error.localizedDescription)), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert)) ) return .none } @@ -104,12 +104,9 @@ struct SettingsReducer: ReducerProtocol { state.supportData = SupportDataGenerator.generate() } else { state.alert = AlertState( - title: TextState("Can't send email"), - message: TextState(""" - It looks like that you don't have any email account configured on your device. Therefore it's not possible to send a support \ - email. - """), - dismissButton: .default(TextState("Ok"), action: .send(.sendSupportMailFinished)) + title: TextState(L10n.Settings.Alert.CantSendEmail.title), + message: TextState(L10n.Settings.Alert.CantSendEmail.message), + dismissButton: .default(TextState(L10n.General.ok), action: .send(.sendSupportMailFinished)) ) } diff --git a/secant/Features/WalletEventsFlow/WalletEventsFlowStore.swift b/secant/Features/WalletEventsFlow/WalletEventsFlowStore.swift index 9c93e38..193faf3 100644 --- a/secant/Features/WalletEventsFlow/WalletEventsFlowStore.swift +++ b/secant/Features/WalletEventsFlow/WalletEventsFlowStore.swift @@ -42,7 +42,7 @@ struct WalletEventsFlowReducer: ReducerProtocol { @Dependency(\.pasteboard) var pasteboard @Dependency(\.sdkSynchronizer) var sdkSynchronizer @Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment - + // swiftlint:disable:next cyclomatic_complexity func reduce(into state: inout State, action: Action) -> ComposableArchitecture.EffectTask { switch action { @@ -104,17 +104,14 @@ struct WalletEventsFlowReducer: ReducerProtocol { case .warnBeforeLeavingApp(let blockExplorerURL): state.alert = AlertState( - title: TextState("You are exiting your wallet"), - message: TextState(""" - While usually an acceptable risk, you will possibly exposing your behavior and interest in this transaction by going online. \ - OH NOES! What will you do? - """), + title: TextState(L10n.WalletEvent.Alert.LeavingApp.title), + message: TextState(L10n.WalletEvent.Alert.LeavingApp.message), primaryButton: .cancel( - TextState("NEVERMIND"), + TextState(L10n.WalletEvent.Alert.LeavingApp.Button.nevermind), action: .send(.dismissAlert) ), secondaryButton: .default( - TextState("SEE TX ONLINE"), + TextState(L10n.WalletEvent.Alert.LeavingApp.Button.seeOnline), action: .send(.openBlockExplorer(blockExplorerURL)) ) ) diff --git a/secant/Models/SyncStatusSnapshot.swift b/secant/Models/SyncStatusSnapshot.swift index c12238d..8dc7f71 100644 --- a/secant/Models/SyncStatusSnapshot.swift +++ b/secant/Models/SyncStatusSnapshot.swift @@ -22,28 +22,28 @@ struct SyncStatusSnapshot: Equatable { static func snapshotFor(state: SyncStatus) -> SyncStatusSnapshot { switch state { case .enhancing: - return SyncStatusSnapshot(state, "Enhancing tx") + return SyncStatusSnapshot(state, L10n.Sync.Message.enhancing) case .fetching: - return SyncStatusSnapshot(state, "fetching UTXOs") + return SyncStatusSnapshot(state, L10n.Sync.Message.fetchingUTXO) case .disconnected: - return SyncStatusSnapshot(state, "disconnected") + return SyncStatusSnapshot(state, L10n.Sync.Message.disconnected) case .stopped: - return SyncStatusSnapshot(state, "Stopped") + return SyncStatusSnapshot(state, L10n.Sync.Message.stopped) case .synced: - return SyncStatusSnapshot(state, "Up-To-Date") + return SyncStatusSnapshot(state, L10n.Sync.Message.uptodate) case .unprepared: - return SyncStatusSnapshot(state, "Unprepared") + return SyncStatusSnapshot(state, L10n.Sync.Message.unprepared) case .error(let err): - return SyncStatusSnapshot(state, "Error: \(err.localizedDescription)") + return SyncStatusSnapshot(state, L10n.Sync.Message.error(err.localizedDescription)) case .syncing(let progress): - return SyncStatusSnapshot(state, "\(String(format: "%0.1f", progress.progress * 100))% Synced") + return SyncStatusSnapshot(state, L10n.Sync.Message.sync(String(format: "%0.1f", progress.progress * 100))) } } } diff --git a/secant/Models/WalletEvent.swift b/secant/Models/WalletEvent.swift index f30cca0..c9d69f6 100644 --- a/secant/Models/WalletEvent.swift +++ b/secant/Models/WalletEvent.swift @@ -40,12 +40,12 @@ extension WalletEvent { case .shielded(let zatoshi): // TODO: [#390] implement design once shielding is supported // https://github.com/zcash/secant-ios-wallet/issues/390 - Text("shielded wallet event \(zatoshi.decimalString())") + Text(L10n.WalletEvent.Row.shielded(zatoshi.decimalString())) .padding(.leading, 30) case .walletImport: // TODO: [#391] implement design once shielding is supported // https://github.com/zcash/secant-ios-wallet/issues/391 - Text("wallet import wallet event") + Text(L10n.WalletEvent.Row.import) .padding(.leading, 30) } } @@ -64,11 +64,11 @@ extension WalletEvent { case .shielded(let zatoshi): // TODO: [#390] implement design once shielding is supported // https://github.com/zcash/secant-ios-wallet/issues/390 - Text("shielded \(zatoshi.decimalString()) detail") + Text(L10n.WalletEvent.Detail.shielded(zatoshi.decimalString())) case .walletImport: // TODO: [#391] implement design once shielding is supported // https://github.com/zcash/secant-ios-wallet/issues/391 - Text("wallet import wallet event") + Text(L10n.WalletEvent.Detail.import) } } } diff --git a/secant/Resources/Generated/L10n.swift b/secant/Resources/Generated/L10n.swift index 4aa8387..b3f93a1 100644 --- a/secant/Resources/Generated/L10n.swift +++ b/secant/Resources/Generated/L10n.swift @@ -25,6 +25,14 @@ internal enum L10n { internal static let ta = L10n.tr("Localizable", "addressDetails.ta", fallback: "Transparent Address") /// Unified Address internal static let ua = L10n.tr("Localizable", "addressDetails.ua", fallback: "Unified Address") + internal enum Error { + /// could not extract sapling receiver from UA + internal static let cantExtractSaplingAddress = L10n.tr("Localizable", "addressDetails.error.cantExtractSaplingAddress", fallback: "could not extract sapling receiver from UA") + /// could not extract transparent receiver from UA + internal static let cantExtractTransparentAddress = L10n.tr("Localizable", "addressDetails.error.cantExtractTransparentAddress", fallback: "could not extract transparent receiver from UA") + /// could not extract UA + internal static let cantExtractUnifiedAddress = L10n.tr("Localizable", "addressDetails.error.cantExtractUnifiedAddress", fallback: "could not extract UA") + } } internal enum Balance { /// %@ ZEC Available @@ -52,9 +60,41 @@ internal enum L10n { /// possible roll back internal static let rollBack = L10n.tr("Localizable", "error.rollBack", fallback: "possible roll back") } + internal enum ExportLogs { + internal enum Alert { + internal enum Failed { + /// Error: %@ + internal static func message(_ p1: Any) -> String { + return L10n.tr("Localizable", "exportLogs.alert.failed.message", String(describing: p1), fallback: "Error: %@") + } + /// Error when exporting logs + internal static let title = L10n.tr("Localizable", "exportLogs.alert.failed.title", fallback: "Error when exporting logs") + } + } + } + internal enum Field { + internal enum Multiline { + /// char limit exceeded + internal static let charLimitExceeded = L10n.tr("Localizable", "field.multiline.charLimitExceeded", fallback: "char limit exceeded") + } + internal enum TransactionAddress { + /// To: + internal static let to = L10n.tr("Localizable", "field.transactionAddress.to", fallback: "To:") + /// Valid Zcash Address + internal static let validZcashAddress = L10n.tr("Localizable", "field.transactionAddress.validZcashAddress", fallback: "Valid Zcash Address") + } + internal enum TransactionAmount { + /// Amount: + internal static let amount = L10n.tr("Localizable", "field.transactionAmount.amount", fallback: "Amount:") + /// ZEC Amount + internal static let zecAmount = L10n.tr("Localizable", "field.transactionAmount.zecAmount", fallback: "ZEC Amount") + } + } internal enum General { /// Back internal static let back = L10n.tr("Localizable", "general.back", fallback: "Back") + /// Cancel + internal static let cancel = L10n.tr("Localizable", "general.cancel", fallback: "Cancel") /// Clear internal static let clear = L10n.tr("Localizable", "general.clear", fallback: "Clear") /// Close @@ -65,10 +105,20 @@ internal enum L10n { internal static let max = L10n.tr("Localizable", "general.max", fallback: "Max") /// Next internal static let next = L10n.tr("Localizable", "general.next", fallback: "Next") + /// No + internal static let no = L10n.tr("Localizable", "general.no", fallback: "No") + /// Ok + internal static let ok = L10n.tr("Localizable", "general.ok", fallback: "Ok") /// Send internal static let send = L10n.tr("Localizable", "general.send", fallback: "Send") /// Skip internal static let skip = L10n.tr("Localizable", "general.skip", fallback: "Skip") + /// Success + internal static let success = L10n.tr("Localizable", "general.success", fallback: "Success") + /// Unknown + internal static let unknown = L10n.tr("Localizable", "general.unknown", fallback: "Unknown") + /// Yes + internal static let yes = L10n.tr("Localizable", "general.yes", fallback: "Yes") } internal enum Home { /// Receive ZEC @@ -85,6 +135,22 @@ internal enum L10n { internal static let description = L10n.tr("Localizable", "importWallet.description", fallback: "Enter your secret backup seed phrase.") /// Wallet Import internal static let title = L10n.tr("Localizable", "importWallet.title", fallback: "Wallet Import") + internal enum Alert { + internal enum Failed { + /// Error: %@ + internal static func message(_ p1: Any) -> String { + return L10n.tr("Localizable", "importWallet.alert.failed.message", String(describing: p1), fallback: "Error: %@") + } + /// Failed to restore wallet + internal static let title = L10n.tr("Localizable", "importWallet.alert.failed.title", fallback: "Failed to restore wallet") + } + internal enum Success { + /// The wallet has been successfully recovered. + internal static let message = L10n.tr("Localizable", "importWallet.alert.success.message", fallback: "The wallet has been successfully recovered.") + /// Success + internal static let title = L10n.tr("Localizable", "importWallet.alert.success.title", fallback: "Success") + } + } internal enum Birthday { /// Do you know the wallet's creation date? This will allow a faster sync. If you don't know the wallet's birthday, don't worry! internal static let description = L10n.tr("Localizable", "importWallet.birthday.description", fallback: "Do you know the wallet's creation date? This will allow a faster sync. If you don't know the wallet's birthday, don't worry!") @@ -97,6 +163,14 @@ internal enum L10n { /// Restore wallet internal static let restoreWallet = L10n.tr("Localizable", "importWallet.button.restoreWallet", fallback: "Restore wallet") } + internal enum Seed { + /// VALID SEED PHRASE + internal static let valid = L10n.tr("Localizable", "importWallet.seed.valid", fallback: "VALID SEED PHRASE") + } + } + internal enum LocalAuthentication { + /// The Following content requires authentication. + internal static let reason = L10n.tr("Localizable", "localAuthentication.reason", fallback: "The Following content requires authentication.") } internal enum Nefs { /// Not enough space on disk to do synchronisation! @@ -143,6 +217,10 @@ internal enum L10n { internal enum ReceiveZec { /// Your Address internal static let yourAddress = L10n.tr("Localizable", "receiveZec.yourAddress", fallback: "Your Address") + internal enum Error { + /// could not extract UA + internal static let cantExtractUnifiedAddress = L10n.tr("Localizable", "receiveZec.error.cantExtractUnifiedAddress", fallback: "could not extract UA") + } } internal enum RecoveryPhraseBackupValidation { /// Drag the words below to match your backed-up copy. @@ -182,11 +260,152 @@ internal enum L10n { internal static let goNext = L10n.tr("Localizable", "recoveryPhraseTestPreamble.button.goNext", fallback: "By understanding and preparing") } } + internal enum Root { + internal enum Debug { + /// Feature flags + internal static let featureFlags = L10n.tr("Localizable", "root.debug.featureFlags", fallback: "Feature flags") + /// Startup + internal static let navigationTitle = L10n.tr("Localizable", "root.debug.navigationTitle", fallback: "Startup") + /// Debug options + internal static let title = L10n.tr("Localizable", "root.debug.title", fallback: "Debug options") + internal enum Alert { + internal enum Rewind { + internal enum CantStartSync { + /// Error: %@ + internal static func message(_ p1: Any) -> String { + return L10n.tr("Localizable", "root.debug.alert.rewind.cantStartSync.message", String(describing: p1), fallback: "Error: %@") + } + /// Can't start sync process after rewind + internal static let title = L10n.tr("Localizable", "root.debug.alert.rewind.cantStartSync.title", fallback: "Can't start sync process after rewind") + } + internal enum Failed { + /// Error: %@ + internal static func message(_ p1: Any) -> String { + return L10n.tr("Localizable", "root.debug.alert.rewind.failed.message", String(describing: p1), fallback: "Error: %@") + } + /// Rewind failed + internal static let title = L10n.tr("Localizable", "root.debug.alert.rewind.failed.title", fallback: "Rewind failed") + } + } + } + internal enum Dialog { + internal enum Rescan { + /// Select the rescan you want + internal static let message = L10n.tr("Localizable", "root.debug.dialog.rescan.message", fallback: "Select the rescan you want") + /// Rescan + internal static let title = L10n.tr("Localizable", "root.debug.dialog.rescan.title", fallback: "Rescan") + internal enum Option { + /// Full rescan + internal static let full = L10n.tr("Localizable", "root.debug.dialog.rescan.option.full", fallback: "Full rescan") + /// Quick rescan + internal static let quick = L10n.tr("Localizable", "root.debug.dialog.rescan.option.quick", fallback: "Quick rescan") + } + } + } + internal enum Error { + internal enum Rewind { + /// SDKSynchronizer not initilized. rewindPublisher is nil + internal static let sdkSynchronizerNotInitialized = L10n.tr("Localizable", "root.debug.error.rewind.sdkSynchronizerNotInitialized", fallback: "SDKSynchronizer not initilized. rewindPublisher is nil") + } + } + internal enum Option { + /// Export logs + internal static let exportLogs = L10n.tr("Localizable", "root.debug.option.exportLogs", fallback: "Export logs") + /// Go To Onboarding + internal static let gotoOnboarding = L10n.tr("Localizable", "root.debug.option.gotoOnboarding", fallback: "Go To Onboarding") + /// Go To Phrase Validation Demo + internal static let gotoPhraseValidationDemo = L10n.tr("Localizable", "root.debug.option.gotoPhraseValidationDemo", fallback: "Go To Phrase Validation Demo") + /// Go To Sandbox (navigation proof) + internal static let gotoSandbox = L10n.tr("Localizable", "root.debug.option.gotoSandbox", fallback: "Go To Sandbox (navigation proof)") + /// [Be careful] Nuke Wallet + internal static let nukeWallet = L10n.tr("Localizable", "root.debug.option.nukeWallet", fallback: "[Be careful] Nuke Wallet") + /// Rescan Blockchain + internal static let rescanBlockchain = L10n.tr("Localizable", "root.debug.option.rescanBlockchain", fallback: "Rescan Blockchain") + /// Restart the app + internal static let restartApp = L10n.tr("Localizable", "root.debug.option.restartApp", fallback: "Restart the app") + /// Test Crash Reporter + internal static let testCrashReporter = L10n.tr("Localizable", "root.debug.option.testCrashReporter", fallback: "Test Crash Reporter") + } + } + internal enum Destination { + internal enum Alert { + internal enum FailedToProcessDeeplink { + /// Deeplink: (%@)) + /// Error: (%@) + internal static func message(_ p1: Any, _ p2: Any) -> String { + return L10n.tr("Localizable", "root.destination.alert.failedToProcessDeeplink.message", String(describing: p1), String(describing: p2), fallback: "Deeplink: (%@))\nError: (%@)") + } + /// Failed to process deeplink. + internal static let title = L10n.tr("Localizable", "root.destination.alert.failedToProcessDeeplink.title", fallback: "Failed to process deeplink.") + } + } + } + internal enum Initialization { + internal enum Alert { + internal enum CantCreateNewWallet { + /// Can't create new wallet. Error: %@ + internal static func message(_ p1: Any) -> String { + return L10n.tr("Localizable", "root.initialization.alert.cantCreateNewWallet.message", String(describing: p1), fallback: "Can't create new wallet. Error: %@") + } + } + internal enum CantLoadSeedPhrase { + /// Can't load seed phrase from local storage. + internal static let message = L10n.tr("Localizable", "root.initialization.alert.cantLoadSeedPhrase.message", fallback: "Can't load seed phrase from local storage.") + } + internal enum CantStoreThatUserPassedPhraseBackupTest { + /// Can't store information that user passed phrase backup test. Error: %@ + internal static func message(_ p1: Any) -> String { + return L10n.tr("Localizable", "root.initialization.alert.cantStoreThatUserPassedPhraseBackupTest.message", String(describing: p1), fallback: "Can't store information that user passed phrase backup test. Error: %@") + } + } + internal enum Error { + /// Error: %@ + internal static func message(_ p1: Any) -> String { + return L10n.tr("Localizable", "root.initialization.alert.error.message", String(describing: p1), fallback: "Error: %@") + } + } + internal enum Failed { + /// Wallet initialisation failed. + internal static let title = L10n.tr("Localizable", "root.initialization.alert.failed.title", fallback: "Wallet initialisation failed.") + } + internal enum SdkInitFailed { + /// Failed to initialize the SDK + internal static let title = L10n.tr("Localizable", "root.initialization.alert.sdkInitFailed.title", fallback: "Failed to initialize the SDK") + } + internal enum WalletStateFailed { + /// App initialisation state: %@. + internal static func message(_ p1: Any) -> String { + return L10n.tr("Localizable", "root.initialization.alert.walletStateFailed.message", String(describing: p1), fallback: "App initialisation state: %@.") + } + } + internal enum Wipe { + /// Are you sure? + internal static let message = L10n.tr("Localizable", "root.initialization.alert.wipe.message", fallback: "Are you sure?") + /// Wipe of the wallet + internal static let title = L10n.tr("Localizable", "root.initialization.alert.wipe.title", fallback: "Wipe of the wallet") + } + internal enum WipeFailed { + /// Nuke of the wallet failed + internal static let title = L10n.tr("Localizable", "root.initialization.alert.wipeFailed.title", fallback: "Nuke of the wallet failed") + } + } + } + } internal enum Scan { /// We will validate any Zcash URI and take you to the appropriate action. internal static let info = L10n.tr("Localizable", "scan.info", fallback: "We will validate any Zcash URI and take you to the appropriate action.") /// Scanning... internal static let scanning = L10n.tr("Localizable", "scan.scanning", fallback: "Scanning...") + internal enum Alert { + internal enum CantInitializeCamera { + /// Error: %@ + internal static func message(_ p1: Any) -> String { + return L10n.tr("Localizable", "scan.alert.cantInitializeCamera.message", String(describing: p1), fallback: "Error: %@") + } + /// Can't initialize the camera + internal static let title = L10n.tr("Localizable", "scan.alert.cantInitializeCamera.title", fallback: "Can't initialize the camera") + } + } } internal enum Send { /// address: %@ @@ -229,6 +448,88 @@ internal enum L10n { internal static let feedback = L10n.tr("Localizable", "settings.feedback", fallback: "Send us feedback!") /// Settings internal static let title = L10n.tr("Localizable", "settings.title", fallback: "Settings") + internal enum Alert { + internal enum CantBackupWallet { + /// Error: %@ + internal static func message(_ p1: Any) -> String { + return L10n.tr("Localizable", "settings.alert.cantBackupWallet.message", String(describing: p1), fallback: "Error: %@") + } + /// Can't backup wallet + internal static let title = L10n.tr("Localizable", "settings.alert.cantBackupWallet.title", fallback: "Can't backup wallet") + } + internal enum CantSendEmail { + /// It looks like that you don't have any email account configured on your device. Therefore it's not possible to send a support email. + internal static let message = L10n.tr("Localizable", "settings.alert.cantSendEmail.message", fallback: "It looks like that you don't have any email account configured on your device. Therefore it's not possible to send a support email.") + /// Can't send email + internal static let title = L10n.tr("Localizable", "settings.alert.cantSendEmail.title", fallback: "Can't send email") + } + } + } + internal enum SupportData { + internal enum AppVersionItem { + /// App identifier + internal static let bundleIdentifier = L10n.tr("Localizable", "supportData.appVersionItem.bundleIdentifier", fallback: "App identifier") + /// App version + internal static let version = L10n.tr("Localizable", "supportData.appVersionItem.version", fallback: "App version") + } + internal enum DeviceModelItem { + /// Device + internal static let device = L10n.tr("Localizable", "supportData.deviceModelItem.device", fallback: "Device") + } + internal enum FreeDiskSpaceItem { + /// Usable storage + internal static let freeDiskSpace = L10n.tr("Localizable", "supportData.freeDiskSpaceItem.freeDiskSpace", fallback: "Usable storage") + } + internal enum LocaleItem { + /// Currency decimal separator + internal static let decimalSeparator = L10n.tr("Localizable", "supportData.localeItem.decimalSeparator", fallback: "Currency decimal separator") + /// Currency grouping separator + internal static let groupingSeparator = L10n.tr("Localizable", "supportData.localeItem.groupingSeparator", fallback: "Currency grouping separator") + /// Locale + internal static let locale = L10n.tr("Localizable", "supportData.localeItem.locale", fallback: "Locale") + } + internal enum PermissionItem { + /// Camera access + internal static let camera = L10n.tr("Localizable", "supportData.permissionItem.camera", fallback: "Camera access") + /// FaceID available + internal static let faceID = L10n.tr("Localizable", "supportData.permissionItem.faceID", fallback: "FaceID available") + /// Permissions + internal static let permissions = L10n.tr("Localizable", "supportData.permissionItem.permissions", fallback: "Permissions") + /// TouchID available + internal static let touchID = L10n.tr("Localizable", "supportData.permissionItem.touchID", fallback: "TouchID available") + } + internal enum SystemVersionItem { + /// iOS version + internal static let version = L10n.tr("Localizable", "supportData.systemVersionItem.version", fallback: "iOS version") + } + internal enum TimeItem { + /// Current time + internal static let time = L10n.tr("Localizable", "supportData.timeItem.time", fallback: "Current time") + } + } + internal enum Sync { + internal enum Message { + /// disconnected + internal static let disconnected = L10n.tr("Localizable", "sync.message.disconnected", fallback: "disconnected") + /// Enhancing tx + internal static let enhancing = L10n.tr("Localizable", "sync.message.enhancing", fallback: "Enhancing tx") + /// Error: %@ + internal static func error(_ p1: Any) -> String { + return L10n.tr("Localizable", "sync.message.error", String(describing: p1), fallback: "Error: %@") + } + /// fetching UTXOs + internal static let fetchingUTXO = L10n.tr("Localizable", "sync.message.fetchingUTXO", fallback: "fetching UTXOs") + /// Stopped + internal static let stopped = L10n.tr("Localizable", "sync.message.stopped", fallback: "Stopped") + /// %@ Synced + internal static func sync(_ p1: Any) -> String { + return L10n.tr("Localizable", "sync.message.sync", String(describing: p1), fallback: "%@ Synced") + } + /// Unprepared + internal static let unprepared = L10n.tr("Localizable", "sync.message.unprepared", fallback: "Unprepared") + /// Up-To-Date + internal static let uptodate = L10n.tr("Localizable", "sync.message.uptodate", fallback: "Up-To-Date") + } } internal enum Transaction { /// Confirmed @@ -308,6 +609,38 @@ internal enum L10n { internal static let phraseAgain = L10n.tr("Localizable", "validationSuccess.button.phraseAgain", fallback: "Show me my phrase again") } } + internal enum WalletEvent { + internal enum Alert { + internal enum LeavingApp { + /// While usually an acceptable risk, you will possibly exposing your behavior and interest in this transaction by going online. OH NOES! What will you do? + internal static let message = L10n.tr("Localizable", "walletEvent.alert.leavingApp.message", fallback: "While usually an acceptable risk, you will possibly exposing your behavior and interest in this transaction by going online. OH NOES! What will you do?") + /// You are exiting your wallet + internal static let title = L10n.tr("Localizable", "walletEvent.alert.leavingApp.title", fallback: "You are exiting your wallet") + internal enum Button { + /// NEVERMIND + internal static let nevermind = L10n.tr("Localizable", "walletEvent.alert.leavingApp.button.nevermind", fallback: "NEVERMIND") + /// SEE TX ONLINE + internal static let seeOnline = L10n.tr("Localizable", "walletEvent.alert.leavingApp.button.seeOnline", fallback: "SEE TX ONLINE") + } + } + } + internal enum Detail { + /// wallet import wallet event + internal static let `import` = L10n.tr("Localizable", "walletEvent.detail.import", fallback: "wallet import wallet event") + /// shielded %@ detail + internal static func shielded(_ p1: Any) -> String { + return L10n.tr("Localizable", "walletEvent.detail.shielded", String(describing: p1), fallback: "shielded %@ detail") + } + } + internal enum Row { + /// wallet import wallet event + internal static let `import` = L10n.tr("Localizable", "walletEvent.row.import", fallback: "wallet import wallet event") + /// shielded wallet event %@ + internal static func shielded(_ p1: Any) -> String { + return L10n.tr("Localizable", "walletEvent.row.shielded", String(describing: p1), fallback: "shielded wallet event %@") + } + } + } internal enum WelcomeScreen { /// Just Loading, one sec internal static let subtitle = L10n.tr("Localizable", "welcomeScreen.subtitle", fallback: "Just Loading, one sec") diff --git a/secant/Resources/Localizable.strings b/secant/Resources/Localizable.strings index 23f9ff3..d6cfacc 100644 --- a/secant/Resources/Localizable.strings +++ b/secant/Resources/Localizable.strings @@ -55,6 +55,11 @@ "importWallet.button.importPrivateKey" = "Import a private or viewing key"; "importWallet.birthday.description" = "Do you know the wallet's creation date? This will allow a faster sync. If you don't know the wallet's birthday, don't worry!"; "importWallet.birthday.placeholder" = "Enter birthday height"; +"importWallet.seed.valid" = "VALID SEED PHRASE"; +"importWallet.alert.success.title" = "Success"; +"importWallet.alert.success.message" = "The wallet has been successfully recovered."; +"importWallet.alert.failed.title" = "Failed to restore wallet"; +"importWallet.alert.failed.message" = "Error: %@"; // MARK: - Home Screen "home.sendZec" = "Send ZEC"; @@ -64,11 +69,15 @@ // MARK: - Receive ZEC (Formerly Profile Screen) "receiveZec.yourAddress" = "Your Address"; +"receiveZec.error.cantExtractUnifiedAddress" = "could not extract UA"; // MARK: - Address Details "addressDetails.ua" = "Unified Address"; "addressDetails.sa" = "Sapling Address"; "addressDetails.ta" = "Transparent Address"; +"addressDetails.error.cantExtractUnifiedAddress" = "could not extract UA"; +"addressDetails.error.cantExtractTransparentAddress" = "could not extract transparent receiver from UA"; +"addressDetails.error.cantExtractSaplingAddress" = "could not extract sapling receiver from UA"; // MARK: - Balance Breakdown "balanceBreakdown.blockId" = "Block: %@"; @@ -80,6 +89,8 @@ // MARK: - Scan "scan.info" = "We will validate any Zcash URI and take you to the appropriate action."; "scan.scanning" = "Scanning..."; +"scan.alert.cantInitializeCamera.title" = "Can't initialize the camera"; +"scan.alert.cantInitializeCamera.message" = "Error: %@"; // MARK: - Send "send.title" = "Send Zcash"; @@ -99,6 +110,20 @@ "settings.exportLogs" = "Export & share logs"; "settings.feedback" = "Send us feedback!"; "settings.title" = "Settings"; +"settings.alert.cantBackupWallet.title" = "Can't backup wallet"; +"settings.alert.cantBackupWallet.message" = "Error: %@"; +"settings.alert.cantSendEmail.title" = "Can't send email"; +"settings.alert.cantSendEmail.message" = "It looks like that you don't have any email account configured on your device. Therefore it's not possible to send a support email."; + +// MARK: - Sync message +"sync.message.enhancing" = "Enhancing tx"; +"sync.message.fetchingUTXO" = "fetching UTXOs"; +"sync.message.disconnected" = "disconnected"; +"sync.message.stopped" = "Stopped"; +"sync.message.uptodate" = "Up-To-Date"; +"sync.message.unprepared" = "Unprepared"; +"sync.message.error" = "Error: %@"; +"sync.message.sync" = "%@ Synced"; // MARK: - Transactions "transactions.title" = "Transactions"; @@ -134,7 +159,90 @@ "general.clear" = "Clear"; "general.close" = "Close"; "general.max" = "Max"; +"general.ok" = "Ok"; +"general.yes" = "Yes"; +"general.no" = "No"; +"general.cancel" = "Cancel"; +"general.success" = "Success"; +"general.unknown" = "Unknown"; "balance" = "%@ ZEC"; "balance.available" = "%@ ZEC Available"; "qrCodeFor" = "QR Code for %@"; "general.dateNotAvailable" = "date not available"; + +// MARK: - Wallet event +"walletEvent.row.shielded" = "shielded wallet event %@"; +"walletEvent.row.import" = "wallet import wallet event"; +"walletEvent.detail.shielded" = "shielded %@ detail"; +"walletEvent.detail.import" = "wallet import wallet event"; +"walletEvent.alert.leavingApp.title" = "You are exiting your wallet"; +"walletEvent.alert.leavingApp.message" = "While usually an acceptable risk, you will possibly exposing your behavior and interest in this transaction by going online. OH NOES! What will you do?"; +"walletEvent.alert.leavingApp.button.nevermind" = "NEVERMIND"; +"walletEvent.alert.leavingApp.button.seeOnline" = "SEE TX ONLINE"; + +// MARK: - Local authentication +"localAuthentication.reason" = "The Following content requires authentication."; + +// MARK: - Support Data +"supportData.timeItem.time" = "Current time"; +"supportData.appVersionItem.bundleIdentifier" = "App identifier"; +"supportData.appVersionItem.version" = "App version"; +"supportData.systemVersionItem.version" = "iOS version"; +"supportData.deviceModelItem.device" = "Device"; +"supportData.localeItem.locale" = "Locale"; +"supportData.localeItem.groupingSeparator" = "Currency grouping separator"; +"supportData.localeItem.decimalSeparator" = "Currency decimal separator"; +"supportData.freeDiskSpaceItem.freeDiskSpace" = "Usable storage"; +"supportData.permissionItem.permissions" = "Permissions"; +"supportData.permissionItem.camera" = "Camera access"; +"supportData.permissionItem.faceID" = "FaceID available"; +"supportData.permissionItem.touchID" = "TouchID available"; + +// MARK: - Root +"root.initialization.alert.failed.title" = "Wallet initialisation failed."; +"root.initialization.alert.error.message" = "Error: %@"; +"root.initialization.alert.sdkInitFailed.title" = "Failed to initialize the SDK"; +"root.initialization.alert.walletStateFailed.message" = "App initialisation state: %@."; +"root.initialization.alert.cantLoadSeedPhrase.message" = "Can't load seed phrase from local storage."; +"root.initialization.alert.cantCreateNewWallet.message" = "Can't create new wallet. Error: %@"; +"root.initialization.alert.cantStoreThatUserPassedPhraseBackupTest.message" = "Can't store information that user passed phrase backup test. Error: %@"; +"root.initialization.alert.wipe.title" = "Wipe of the wallet"; +"root.initialization.alert.wipe.message" = "Are you sure?"; +"root.initialization.alert.wipeFailed.title" = "Nuke of the wallet failed"; + +"root.destination.alert.failedToProcessDeeplink.title" = "Failed to process deeplink."; +"root.destination.alert.failedToProcessDeeplink.message" = "Deeplink: \(%@))\nError: \(%@)"; + +"root.debug.title" = "Debug options"; +"root.debug.navigationTitle" = "Startup"; +"root.debug.option.gotoSandbox" = "Go To Sandbox (navigation proof)"; +"root.debug.option.gotoOnboarding" = "Go To Onboarding"; +"root.debug.option.gotoPhraseValidationDemo" = "Go To Phrase Validation Demo"; +"root.debug.option.restartApp" = "Restart the app"; +"root.debug.option.testCrashReporter" = "Test Crash Reporter"; +"root.debug.option.rescanBlockchain" = "Rescan Blockchain"; +"root.debug.option.nukeWallet" = "[Be careful] Nuke Wallet"; +"root.debug.option.exportLogs" = "Export logs"; +"root.debug.featureFlags" = "Feature flags"; +"root.debug.dialog.rescan.title" = "Rescan"; +"root.debug.dialog.rescan.message" = "Select the rescan you want"; +"root.debug.dialog.rescan.option.quick" = "Quick rescan"; +"root.debug.dialog.rescan.option.full" = "Full rescan"; +"root.debug.alert.rewind.failed.title" = "Rewind failed"; +"root.debug.alert.rewind.failed.message" = "Error: %@"; +"root.debug.alert.rewind.cantStartSync.title" = "Can't start sync process after rewind"; +"root.debug.alert.rewind.cantStartSync.message" = "Error: %@"; +"root.debug.error.rewind.sdkSynchronizerNotInitialized" = "SDKSynchronizer not initilized. rewindPublisher is nil"; + +// MARK: - Export logs +"exportLogs.alert.failed.title" = "Error when exporting logs"; +"exportLogs.alert.failed.message" = "Error: %@"; + +// MARK: - Text Fields +"field.multiline.charLimitExceeded" = "char limit exceeded"; + +"field.transactionAddress.validZcashAddress" = "Valid Zcash Address"; +"field.transactionAddress.to" = "To:"; + +"field.transactionAmount.zecAmount" = "ZEC Amount"; +"field.transactionAmount.amount" = "Amount:"; diff --git a/secant/UI Components/TextFields/MultiLineTextField/MultiLineTextFieldStore.swift b/secant/UI Components/TextFields/MultiLineTextField/MultiLineTextFieldStore.swift index d8d9537..2963da3 100644 --- a/secant/UI Components/TextFields/MultiLineTextField/MultiLineTextFieldStore.swift +++ b/secant/UI Components/TextFields/MultiLineTextField/MultiLineTextFieldStore.swift @@ -36,7 +36,7 @@ struct MultiLineTextFieldReducer: ReducerProtocol { charLimit > 0 ? isValid ? "\(textLength)/\(charLimit)" - : "char limit exceeded \(textLength)/\(charLimit)" + : "\(L10n.Field.Multiline.charLimitExceeded) \(textLength)/\(charLimit)" : "" } } diff --git a/secant/UI Components/TextFields/TransactionAddress/TransactionAddressTextField.swift b/secant/UI Components/TextFields/TransactionAddress/TransactionAddressTextField.swift index ae1f51d..9502c54 100644 --- a/secant/UI Components/TextFields/TransactionAddress/TransactionAddressTextField.swift +++ b/secant/UI Components/TextFields/TransactionAddress/TransactionAddressTextField.swift @@ -15,8 +15,8 @@ struct TransactionAddressTextField: View { WithViewStore(store) { viewStore in VStack { SingleLineTextField( - placeholderText: "Valid Zcash Address", - title: "To:", + placeholderText: L10n.Field.TransactionAddress.validZcashAddress, + title: L10n.Field.TransactionAddress.to, store: store.scope( state: \.textFieldState, action: TransactionAddressTextFieldReducer.Action.textField diff --git a/secant/UI Components/TextFields/TransactionAmount/TransactionAmountTextField.swift b/secant/UI Components/TextFields/TransactionAmount/TransactionAmountTextField.swift index ab920de..b150500 100644 --- a/secant/UI Components/TextFields/TransactionAmount/TransactionAmountTextField.swift +++ b/secant/UI Components/TextFields/TransactionAmount/TransactionAmountTextField.swift @@ -14,8 +14,8 @@ struct TransactionAmountTextField: View { var body: some View { VStack { SingleLineTextField( - placeholderText: "ZEC Amount", - title: "Amount:", + placeholderText: L10n.Field.TransactionAmount.zecAmount, + title: L10n.Field.TransactionAmount.amount, store: store.scope( state: \.textFieldState, action: TransactionAmountTextFieldReducer.Action.textField