From 12f27c0e5874b607ca88875b89a7c33c5805e82c Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Sat, 23 Dec 2023 13:15:01 +0200 Subject: [PATCH 01/27] [trello.com/c/iqPDxH1Y] fix: reaction positioning --- .../ChatBaseMessage/ChatMessageCell.swift | 19 ++++++++++++------- .../ChatReply/ChatMessageReplyCell.swift | 19 ++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/Adamant/Modules/Chat/View/Subviews/ChatBaseMessage/ChatMessageCell.swift b/Adamant/Modules/Chat/View/Subviews/ChatBaseMessage/ChatMessageCell.swift index 080cbad54..646ed4407 100644 --- a/Adamant/Modules/Chat/View/Subviews/ChatBaseMessage/ChatMessageCell.swift +++ b/Adamant/Modules/Chat/View/Subviews/ChatBaseMessage/ChatMessageCell.swift @@ -358,12 +358,16 @@ final class ChatMessageCell: TextMessageCell, ChatModelView { - reactionsContanerViewWidth / 2 let minSpace = model.isFromCurrentSender - ? minReactionsContanerHorizontalSpace + reactionsContanerViewWidth - : minReactionsContanerHorizontalSpace - - x = model.isFromCurrentSender - ? contentView.bounds.width - x > minSpace ? x : contentView.bounds.width - minSpace - : x > minSpace ? x : minSpace + ? minReactionsSpacingToOwnBoundary + reactionsContanerViewWidth + : minReactionsSpacingToOwnBoundary + + if model.isFromCurrentSender { + x = min(x, contentView.bounds.width - minSpace) + x = max(x, minReactionsSpacingToOppositeBoundary) + } else { + x = max(x, minSpace) + x = min(x, contentView.bounds.width - minReactionsSpacingToOppositeBoundary - reactionsContanerViewWidth) + } reactionsContanerView.frame = CGRect( origin: .init( @@ -525,4 +529,5 @@ extension ChatMessageCell { } private let reactionsContanerVerticalSpace: CGFloat = 10 -private let minReactionsContanerHorizontalSpace: CGFloat = 60 +private let minReactionsSpacingToOwnBoundary: CGFloat = 60 +private let minReactionsSpacingToOppositeBoundary: CGFloat = 15 diff --git a/Adamant/Modules/Chat/View/Subviews/ChatReply/ChatMessageReplyCell.swift b/Adamant/Modules/Chat/View/Subviews/ChatReply/ChatMessageReplyCell.swift index 4d4c4ec3b..f78ebce75 100644 --- a/Adamant/Modules/Chat/View/Subviews/ChatReply/ChatMessageReplyCell.swift +++ b/Adamant/Modules/Chat/View/Subviews/ChatReply/ChatMessageReplyCell.swift @@ -436,12 +436,16 @@ final class ChatMessageReplyCell: MessageContentCell, ChatModelView { - reactionsContanerViewWidth / 2 let minSpace = model.isFromCurrentSender - ? minReactionsContanerHorizontalSpace + reactionsContanerViewWidth - : minReactionsContanerHorizontalSpace - - x = model.isFromCurrentSender - ? contentView.bounds.width - x > minSpace ? x : contentView.bounds.width - minSpace - : x > minSpace ? x : minSpace + ? minReactionsSpacingToOwnBoundary + reactionsContanerViewWidth + : minReactionsSpacingToOwnBoundary + + if model.isFromCurrentSender { + x = min(x, contentView.bounds.width - minSpace) + x = max(x, minReactionsSpacingToOppositeBoundary) + } else { + x = max(x, minSpace) + x = min(x, contentView.bounds.width - minReactionsSpacingToOppositeBoundary - reactionsContanerViewWidth) + } reactionsContanerView.frame = CGRect( origin: .init( @@ -628,4 +632,5 @@ extension ChatMessageReplyCell { } private let reactionsContanerVerticalSpace: CGFloat = 10 -private let minReactionsContanerHorizontalSpace: CGFloat = 60 +private let minReactionsSpacingToOwnBoundary: CGFloat = 60 +private let minReactionsSpacingToOppositeBoundary: CGFloat = 15 From 883a7a5f8d849beef9808a5dc97f51c94fe85049 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Sat, 23 Dec 2023 14:17:06 +0200 Subject: [PATCH 02/27] [https://trello.com/c/z0aXp4FZ] feat: show fee estimate in fiat --- ...RC20TransactionDetailsViewController.swift | 4 + ...TransactionDetailsViewControllerBase.swift | 91 +++++++++++++------ .../CurrencyInfoService.swift | 5 + .../Services/AdamantCurrencyInfoService.swift | 18 ++++ 4 files changed, 89 insertions(+), 29 deletions(-) diff --git a/Adamant/Modules/Wallets/ERC20/ERC20TransactionDetailsViewController.swift b/Adamant/Modules/Wallets/ERC20/ERC20TransactionDetailsViewController.swift index a9361c81b..2e32f67df 100644 --- a/Adamant/Modules/Wallets/ERC20/ERC20TransactionDetailsViewController.swift +++ b/Adamant/Modules/Wallets/ERC20/ERC20TransactionDetailsViewController.swift @@ -22,6 +22,10 @@ final class ERC20TransactionDetailsViewController: TransactionDetailsViewControl return AdamantBalanceFormat.currencyFormatter(for: .full, currencySymbol: EthWalletService.currencySymbol) } + override var feeCurrencySymbol: String? { + EthWalletService.currencySymbol + } + private lazy var refreshControl: UIRefreshControl = { let control = UIRefreshControl() control.tintColor = .adamant.primary diff --git a/Adamant/Modules/Wallets/TransactionDetailsViewControllerBase.swift b/Adamant/Modules/Wallets/TransactionDetailsViewControllerBase.swift index 624649463..89d1ca1eb 100644 --- a/Adamant/Modules/Wallets/TransactionDetailsViewControllerBase.swift +++ b/Adamant/Modules/Wallets/TransactionDetailsViewControllerBase.swift @@ -192,6 +192,10 @@ class TransactionDetailsViewControllerBase: FormViewController { nil } + var feeCurrencySymbol: String? { + currencySymbol + } + var transactionStatus: TransactionStatus? { guard let richTransaction = richTransaction, let status = transaction?.transactionStatus @@ -247,6 +251,12 @@ class TransactionDetailsViewControllerBase: FormViewController { } } + var feeAtTimeTxn: String? { + didSet { + updateFeeAtTimeRowValue() + } + } + // MARK: - Lifecycle init( @@ -494,12 +504,7 @@ class TransactionDetailsViewControllerBase: FormViewController { $0.disabled = true $0.tag = Rows.fee.tag $0.title = Rows.fee.localized - - if let value = transaction?.feeValue { - $0.value = feeFormatter.string(from: value) - } else { - $0.value = TransactionDetailsViewControllerBase.awaitingValueString - } + $0.value = getFeeValue() }.cellSetup { (cell, _) in cell.selectionStyle = .gray cell.textLabel?.textColor = UIColor.adamant.textColor @@ -509,11 +514,7 @@ class TransactionDetailsViewControllerBase: FormViewController { } }.cellUpdate { [weak self] (cell, row) in cell.textLabel?.textColor = UIColor.adamant.textColor - if let value = self?.transaction?.feeValue, let formatter = self?.feeFormatter { - row.value = formatter.string(from: value) - } else { - row.value = TransactionDetailsViewControllerBase.awaitingValueString - } + row.value = self?.getFeeValue() } detailsSection.append(feeRow) @@ -776,31 +777,41 @@ class TransactionDetailsViewControllerBase: FormViewController { let amount = transaction?.amountValue else { return } - self.isFiatSet = true let currentFiat = currencyInfo.currentCurrency.rawValue - currencyInfo.getHistory( - for: currencySymbol, - timestamp: date - ) { result in - Task { @MainActor [weak self] in - guard case .success(let tickers) = result else { - self?.isFiatSet = false - return - } - - self?.isFiatSet = true + Task { + var tickers = try await currencyInfo.getHistory( + for: currencySymbol, + timestamp: date + ) + + isFiatSet = true + + guard var ticker = tickers["\(currencySymbol)/\(currentFiat)"] else { + return + } + + let totalFiat = amount * ticker + valueAtTimeTxn = fiatFormatter.string(from: totalFiat) + + guard let fee = transaction?.feeValue else { return } + + if let feeCurrencySymbol = feeCurrencySymbol, + feeCurrencySymbol != currencySymbol { + tickers = try await currencyInfo.getHistory( + for: feeCurrencySymbol, + timestamp: date + ) - guard let tickers = tickers, - let ticker = tickers["\(currencySymbol)/\(currentFiat)"] - else { + guard let feeTicker = tickers["\(feeCurrencySymbol)/\(currentFiat)"] else { return } - let totalFiat = amount * ticker - - self?.valueAtTimeTxn = self?.fiatFormatter.string(from: totalFiat) + ticker = feeTicker } + + let totalFeeFiat = fee * ticker + feeAtTimeTxn = fiatFormatter.string(from: totalFeeFiat) } } @@ -850,6 +861,28 @@ class TransactionDetailsViewControllerBase: FormViewController { row.updateCell() } + @MainActor + private func updateFeeAtTimeRowValue() { + guard let row: LabelRow = form.rowBy(tag: Rows.fee.tag) + else { return } + + row.value = getFeeValue() + row.updateCell() + } + + func getFeeValue() -> String { + guard let value = transaction?.feeValue else { + return TransactionDetailsViewControllerBase.awaitingValueString + } + + let feeValueRaw = feeFormatter.string(from: value) ?? "" + + if let feeAtTimeTxn = feeAtTimeTxn { + return "\(feeValueRaw) ~\(feeAtTimeTxn)" + } + + return feeValueRaw + } // MARK: - Actions @objc func share(_ sender: UIBarButtonItem) { diff --git a/Adamant/ServiceProtocols/CurrencyInfoService.swift b/Adamant/ServiceProtocols/CurrencyInfoService.swift index 1aa9c56e1..7a8547491 100644 --- a/Adamant/ServiceProtocols/CurrencyInfoService.swift +++ b/Adamant/ServiceProtocols/CurrencyInfoService.swift @@ -47,6 +47,11 @@ protocol CurrencyInfoService: AnyObject { func getRate(for coin: String) -> Decimal? func getHistory(for coin: String, timestamp: Date, completion: @escaping (ApiServiceResult<[String:Decimal]?>) -> Void) + + func getHistory( + for coin: String, + timestamp: Date + ) async throws -> [String: Decimal] } // MARK: - AdamantBalanceFormat fiat formatter diff --git a/Adamant/Services/AdamantCurrencyInfoService.swift b/Adamant/Services/AdamantCurrencyInfoService.swift index 957e01fad..23ec220e4 100644 --- a/Adamant/Services/AdamantCurrencyInfoService.swift +++ b/Adamant/Services/AdamantCurrencyInfoService.swift @@ -180,6 +180,24 @@ final class AdamantCurrencyInfoService: CurrencyInfoService { } } + func getHistory( + for coin: String, + timestamp: Date + ) async throws -> [String: Decimal] { + try await withUnsafeThrowingContinuation { continuation in + getHistory( + for: coin, + timestamp: timestamp) { completion in + switch completion { + case .success(let result): + continuation.resume(returning: result ?? [:]) + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } + private func setupSecuredStore() { if let id: String = securedStore.get(StoreKey.CoinInfo.selectedCurrency), From 4bc25cc660ed2f923a3c2613f7f9d0069d0ec3c8 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Thu, 28 Dec 2023 17:52:29 +0200 Subject: [PATCH 03/27] [trello.com/c/CwJgasMG] feat: move health check constants to wallets repository --- Adamant.xcodeproj/project.pbxproj | 4 + Adamant/Helpers/NodeGroup+Constants.swift | 87 +++++++++++++++++++ .../AdmWalletService+DynamicConstants.swift | 13 ++- .../BtcWalletService+DynamicConstants.swift | 11 ++- .../DashWalletService+DynamicConstants.swift | 11 ++- .../DogeWalletService+DynamicConstants.swift | 11 ++- .../EthWalletService+DynamicConstants.swift | 11 ++- .../LskWalletService+DynamicConstants.swift | 11 ++- CommonKit/Scripts/CoinsScript.rb | 61 ++++++++++++- .../Models/CoinHealthCheckParameters.swift | 36 ++++++++ .../Models/NodeGroup+Constants.swift | 39 --------- 11 files changed, 246 insertions(+), 49 deletions(-) create mode 100644 Adamant/Helpers/NodeGroup+Constants.swift create mode 100644 CommonKit/Sources/CommonKit/Models/CoinHealthCheckParameters.swift diff --git a/Adamant.xcodeproj/project.pbxproj b/Adamant.xcodeproj/project.pbxproj index 32cb3112a..f518263c8 100644 --- a/Adamant.xcodeproj/project.pbxproj +++ b/Adamant.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ 3AA50DF12AEBE66A00C58FC8 /* PartnerQRViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA50DF02AEBE66A00C58FC8 /* PartnerQRViewModel.swift */; }; 3AA50DF32AEBE67C00C58FC8 /* PartnerQRFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA50DF22AEBE67C00C58FC8 /* PartnerQRFactory.swift */; }; 3AC76E3D2AB09118008042C4 /* ElegantEmojiPicker in Frameworks */ = {isa = PBXBuildFile; productRef = 3AC76E3C2AB09118008042C4 /* ElegantEmojiPicker */; }; + 3AF53F8D2B3DCFA300B30312 /* NodeGroup+Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF53F8C2B3DCFA300B30312 /* NodeGroup+Constants.swift */; }; 3C06931576393125C61FB8F6 /* Pods_Adamant.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33975C0D891698AA7E74EBCC /* Pods_Adamant.framework */; }; 41047B70294B5EE10039E956 /* VisibleWalletsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41047B6F294B5EE10039E956 /* VisibleWalletsViewController.swift */; }; 41047B72294B5F210039E956 /* VisibleWalletsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41047B71294B5F210039E956 /* VisibleWalletsTableViewCell.swift */; }; @@ -668,6 +669,7 @@ 3AA50DEE2AEBE65D00C58FC8 /* PartnerQRView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PartnerQRView.swift; sourceTree = ""; }; 3AA50DF02AEBE66A00C58FC8 /* PartnerQRViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PartnerQRViewModel.swift; sourceTree = ""; }; 3AA50DF22AEBE67C00C58FC8 /* PartnerQRFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PartnerQRFactory.swift; sourceTree = ""; }; + 3AF53F8C2B3DCFA300B30312 /* NodeGroup+Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NodeGroup+Constants.swift"; sourceTree = ""; }; 41047B6F294B5EE10039E956 /* VisibleWalletsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleWalletsViewController.swift; sourceTree = ""; }; 41047B71294B5F210039E956 /* VisibleWalletsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleWalletsTableViewCell.swift; sourceTree = ""; }; 41047B73294C61D10039E956 /* VisibleWalletsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleWalletsService.swift; sourceTree = ""; }; @@ -2035,6 +2037,7 @@ 93CCAE7F2B06E2D100EA5B94 /* ApiServiceError+Extension.swift */, 939FA3412B0D6F0000710EC6 /* SelfRemovableHostingController.swift */, 936658942B0AC15300BDB2D3 /* Node+UI.swift */, + 3AF53F8C2B3DCFA300B30312 /* NodeGroup+Constants.swift */, ); path = Helpers; sourceTree = ""; @@ -3303,6 +3306,7 @@ E9B4E1A8210F079E007E77FC /* DoubleDetailsTableViewCell.swift in Sources */, E9502740202E257E002C1098 /* RepeaterService.swift in Sources */, E93D7AC02052CF63005D19DC /* AdamantNotificationService.swift in Sources */, + 3AF53F8D2B3DCFA300B30312 /* NodeGroup+Constants.swift in Sources */, 411743002A39B1D2008CD98A /* ContributeFactory.swift in Sources */, A5E04224282A830B0076CD13 /* BtcTransactionsViewController.swift in Sources */, 645938942378395E00A2BE7C /* EulaViewController.swift in Sources */, diff --git a/Adamant/Helpers/NodeGroup+Constants.swift b/Adamant/Helpers/NodeGroup+Constants.swift new file mode 100644 index 000000000..da7dce76a --- /dev/null +++ b/Adamant/Helpers/NodeGroup+Constants.swift @@ -0,0 +1,87 @@ +// +// NodeGroup+Constants.swift +// Adamant +// +// Created by Stanislav Jelezoglo on 27.12.2023. +// Copyright © 2023 Adamant. All rights reserved. +// +import Foundation +import CommonKit + +public extension NodeGroup { + var onScreenUpdateInterval: TimeInterval { + switch self { + case .adm: + return AdmWalletService.healthCheckParameters.onScreenUpdateInterval + case .btc: + return BtcWalletService.healthCheckParameters.onScreenUpdateInterval + case .eth: + return EthWalletService.healthCheckParameters.onScreenUpdateInterval + case .lskNode: + return LskWalletService.healthCheckParameters.onScreenUpdateInterval + case .lskService: + return LskWalletService.healthCheckParameters.onScreenServiceUpdateInterval + case .doge: + return DogeWalletService.healthCheckParameters.onScreenUpdateInterval + case .dash: + return DashWalletService.healthCheckParameters.onScreenUpdateInterval + } + } + + var crucialUpdateInterval: TimeInterval { + switch self { + case .adm: + return AdmWalletService.healthCheckParameters.crucialUpdateInterval + case .btc: + return BtcWalletService.healthCheckParameters.crucialUpdateInterval + case .eth: + return EthWalletService.healthCheckParameters.crucialUpdateInterval + case .lskNode: + return LskWalletService.healthCheckParameters.crucialUpdateInterval + case .lskService: + return LskWalletService.healthCheckParameters.crucialServiceUpdateInterval + case .doge: + return DogeWalletService.healthCheckParameters.crucialUpdateInterval + case .dash: + return DashWalletService.healthCheckParameters.crucialUpdateInterval + } + } + + var nodeHeightEpsilon: Int { + switch self { + case .adm: + return AdmWalletService.healthCheckParameters.threshold + case .btc: + return BtcWalletService.healthCheckParameters.threshold + case .eth: + return EthWalletService.healthCheckParameters.threshold + case .lskNode: + return LskWalletService.healthCheckParameters.threshold + case .lskService: + return LskWalletService.healthCheckParameters.threshold + case .doge: + return DogeWalletService.healthCheckParameters.threshold + case .dash: + return DashWalletService.healthCheckParameters.threshold + } + } + + var normalUpdateInterval: TimeInterval { + switch self { + case .adm: + return AdmWalletService.healthCheckParameters.normalUpdateInterval + case .btc: + return BtcWalletService.healthCheckParameters.normalUpdateInterval + case .eth: + return EthWalletService.healthCheckParameters.normalUpdateInterval + case .lskNode: + return LskWalletService.healthCheckParameters.normalUpdateInterval + case .lskService: + return LskWalletService.healthCheckParameters.normalServiceUpdateInterval + case .doge: + return DogeWalletService.healthCheckParameters.normalUpdateInterval + case .dash: + return DashWalletService.healthCheckParameters.normalUpdateInterval + } + } +} diff --git a/Adamant/Modules/Wallets/Adamant/AdmWalletService+DynamicConstants.swift b/Adamant/Modules/Wallets/Adamant/AdmWalletService+DynamicConstants.swift index 9f4a75576..2ed40b0ab 100644 --- a/Adamant/Modules/Wallets/Adamant/AdmWalletService+DynamicConstants.swift +++ b/Adamant/Modules/Wallets/Adamant/AdmWalletService+DynamicConstants.swift @@ -8,7 +8,16 @@ extension AdmWalletService { static let currencySymbol = "ADM" static let currencyExponent: Int = -8 static let qqPrefix: String = "adm" - + static let healthCheckParameters = CoinHealthCheckParameters( + normalUpdateInterval: 300, + crucialUpdateInterval: 30, + onScreenUpdateInterval: 10, + threshold: 10, + normalServiceUpdateInterval: 300, + crucialServiceUpdateInterval: 30, + onScreenServiceUpdateInterval: 10 + ) + static var newPendingInterval: Int { 4000 } @@ -70,7 +79,7 @@ Node(url: URL(string: "https://sunshine.adamant.im")!), static var serviceNodes: [Node] { [ - + Node(url: URL(string: "https://info.adamant.im")!), ] } } diff --git a/Adamant/Modules/Wallets/Bitcoin/BtcWalletService+DynamicConstants.swift b/Adamant/Modules/Wallets/Bitcoin/BtcWalletService+DynamicConstants.swift index 9425f8e2f..bf61ca7aa 100644 --- a/Adamant/Modules/Wallets/Bitcoin/BtcWalletService+DynamicConstants.swift +++ b/Adamant/Modules/Wallets/Bitcoin/BtcWalletService+DynamicConstants.swift @@ -8,7 +8,16 @@ extension BtcWalletService { static let currencySymbol = "BTC" static let currencyExponent: Int = -8 static let qqPrefix: String = "bitcoin" - + static let healthCheckParameters = CoinHealthCheckParameters( + normalUpdateInterval: 360, + crucialUpdateInterval: 30, + onScreenUpdateInterval: 10, + threshold: 2, + normalServiceUpdateInterval: 360, + crucialServiceUpdateInterval: 30, + onScreenServiceUpdateInterval: 10 + ) + static var newPendingInterval: Int { 10000 } diff --git a/Adamant/Modules/Wallets/Dash/DashWalletService+DynamicConstants.swift b/Adamant/Modules/Wallets/Dash/DashWalletService+DynamicConstants.swift index 6e3f810ea..6deec5297 100644 --- a/Adamant/Modules/Wallets/Dash/DashWalletService+DynamicConstants.swift +++ b/Adamant/Modules/Wallets/Dash/DashWalletService+DynamicConstants.swift @@ -8,7 +8,16 @@ extension DashWalletService { static let currencySymbol = "DASH" static let currencyExponent: Int = -8 static let qqPrefix: String = "dash" - + static let healthCheckParameters = CoinHealthCheckParameters( + normalUpdateInterval: 210, + crucialUpdateInterval: 30, + onScreenUpdateInterval: 10, + threshold: 3, + normalServiceUpdateInterval: 210, + crucialServiceUpdateInterval: 30, + onScreenServiceUpdateInterval: 10 + ) + static var newPendingInterval: Int { 5000 } diff --git a/Adamant/Modules/Wallets/Doge/DogeWalletService+DynamicConstants.swift b/Adamant/Modules/Wallets/Doge/DogeWalletService+DynamicConstants.swift index 82c7e1028..176cf3f17 100644 --- a/Adamant/Modules/Wallets/Doge/DogeWalletService+DynamicConstants.swift +++ b/Adamant/Modules/Wallets/Doge/DogeWalletService+DynamicConstants.swift @@ -8,7 +8,16 @@ extension DogeWalletService { static let currencySymbol = "DOGE" static let currencyExponent: Int = -8 static let qqPrefix: String = "doge" - + static let healthCheckParameters = CoinHealthCheckParameters( + normalUpdateInterval: 390, + crucialUpdateInterval: 30, + onScreenUpdateInterval: 10, + threshold: 3, + normalServiceUpdateInterval: 390, + crucialServiceUpdateInterval: 30, + onScreenServiceUpdateInterval: 10 + ) + static var newPendingInterval: Int { 5000 } diff --git a/Adamant/Modules/Wallets/Ethereum/EthWalletService+DynamicConstants.swift b/Adamant/Modules/Wallets/Ethereum/EthWalletService+DynamicConstants.swift index 184451ee2..9656b3973 100644 --- a/Adamant/Modules/Wallets/Ethereum/EthWalletService+DynamicConstants.swift +++ b/Adamant/Modules/Wallets/Ethereum/EthWalletService+DynamicConstants.swift @@ -8,7 +8,16 @@ extension EthWalletService { static let currencySymbol = "ETH" static let currencyExponent: Int = -18 static let qqPrefix: String = "ethereum" - + static let healthCheckParameters = CoinHealthCheckParameters( + normalUpdateInterval: 300, + crucialUpdateInterval: 30, + onScreenUpdateInterval: 10, + threshold: 5, + normalServiceUpdateInterval: 300, + crucialServiceUpdateInterval: 30, + onScreenServiceUpdateInterval: 10 + ) + static var newPendingInterval: Int { 4000 } diff --git a/Adamant/Modules/Wallets/Lisk/LskWalletService+DynamicConstants.swift b/Adamant/Modules/Wallets/Lisk/LskWalletService+DynamicConstants.swift index 036e8cd55..01f242cc0 100644 --- a/Adamant/Modules/Wallets/Lisk/LskWalletService+DynamicConstants.swift +++ b/Adamant/Modules/Wallets/Lisk/LskWalletService+DynamicConstants.swift @@ -8,7 +8,16 @@ extension LskWalletService { static let currencySymbol = "LSK" static let currencyExponent: Int = -8 static let qqPrefix: String = "lisk" - + static let healthCheckParameters = CoinHealthCheckParameters( + normalUpdateInterval: 270, + crucialUpdateInterval: 30, + onScreenUpdateInterval: 10, + threshold: 5, + normalServiceUpdateInterval: 330, + crucialServiceUpdateInterval: 30, + onScreenServiceUpdateInterval: 10 + ) + static var newPendingInterval: Int { 3000 } diff --git a/CommonKit/Scripts/CoinsScript.rb b/CommonKit/Scripts/CoinsScript.rb index c8ca7d70c..38432a22a 100755 --- a/CommonKit/Scripts/CoinsScript.rb +++ b/CommonKit/Scripts/CoinsScript.rb @@ -16,6 +16,55 @@ def createSwiftVariable(name, value, type, isStatic) return text end + # Get Health Check file + def get_health_check_params_from(json) + symbol = json["symbol"] + + # node_additional_info + node_additional_info = json["nodeAdditionalInfo"] + + normal_update_interval = nil + crucial_update_interval = nil + on_screen_update_interval = nil + threshold =nil + normal_service_update_interval = nil + crucial_service_update_interval = nil + on_screen_service_update_interval = nil + + if !node_additional_info.nil? + normal_update_interval = node_additional_info["normalUpdateInterval"] + crucial_update_interval = node_additional_info["crucialUpdateInterval"] + on_screen_update_interval = node_additional_info["onScreenUpdateInterval"] + threshold = node_additional_info["threshold"] + normal_service_update_interval = node_additional_info["normalServiceUpdateInterval"] + crucial_service_update_interval = node_additional_info["crucialServiceUpdateInterval"] + on_screen_service_update_interval = node_additional_info["onScreenServiceUpdateInterval"] + + if normal_service_update_interval.nil? + normal_service_update_interval = normal_update_interval + end + if crucial_service_update_interval.nil? + crucial_service_update_interval = crucial_update_interval + end + if on_screen_service_update_interval.nil? + on_screen_service_update_interval = on_screen_update_interval + end + + text = "static let healthCheckParameters = CoinHealthCheckParameters( + normalUpdateInterval: #{normal_update_interval / 1000}, + crucialUpdateInterval: #{crucial_update_interval / 1000}, + onScreenUpdateInterval: #{on_screen_update_interval / 1000}, + threshold: #{threshold}, + normalServiceUpdateInterval: #{normal_service_update_interval / 1000}, + crucialServiceUpdateInterval: #{crucial_service_update_interval / 1000}, + onScreenServiceUpdateInterval: #{on_screen_service_update_interval / 1000} + )" + return text + end + + return nil + end + # Update a swift file def writeToSwiftFile(name, json) @@ -43,7 +92,7 @@ def writeToSwiftFile(name, json) serviceNodes = "" services = json["services"] if services != nil - serviceNodesArray = services["#{symbol.downcase}Service"] + serviceNodesArray = (symbol == "ADM") ? services["infoService"] : services["#{symbol.downcase}Service"] if serviceNodesArray != nil serviceNodesArray.each do |node| url = node["url"] @@ -83,7 +132,7 @@ def writeToSwiftFile(name, json) defaultOrdinalLevel = json["defaultOrdinalLevel"] - minNodeVersion = json["minNodeVersion"] + minNodeVersion = json["nodeAdditionalInfo"]["minVersion"] if minNodeVersion == nil minNodeVersion = "nil" else @@ -114,6 +163,8 @@ def writeToSwiftFile(name, json) defaultGasLimit = json["defaultGasLimit"] warningGasPriceGwei = json["warningGasPriceGwei"] + health_check_params = get_health_check_params_from(json) + emptyText = "" # Create swift file @@ -128,7 +179,11 @@ def writeToSwiftFile(name, json) static let currencySymbol = \"#{symbol}\" static let currencyExponent: Int = -#{decimals} static let qqPrefix: String = \"#{qqPrefix}\" - + #{health_check_params ? + health_check_params : + emptyText + } + #{newPendingInterval ? createSwiftVariable("newPendingInterval", newPendingInterval, "Int", true) : emptyText diff --git a/CommonKit/Sources/CommonKit/Models/CoinHealthCheckParameters.swift b/CommonKit/Sources/CommonKit/Models/CoinHealthCheckParameters.swift new file mode 100644 index 000000000..931c1e099 --- /dev/null +++ b/CommonKit/Sources/CommonKit/Models/CoinHealthCheckParameters.swift @@ -0,0 +1,36 @@ +// +// CoinHealthCheckParameters.swift +// +// +// Created by Stanislav Jelezoglo on 28.12.2023. +// + +import Foundation + +public struct CoinHealthCheckParameters { + public let normalUpdateInterval: TimeInterval + public let crucialUpdateInterval: TimeInterval + public let onScreenUpdateInterval: TimeInterval + public let threshold: Int + public let normalServiceUpdateInterval: TimeInterval + public let crucialServiceUpdateInterval: TimeInterval + public let onScreenServiceUpdateInterval: TimeInterval + + public init( + normalUpdateInterval: TimeInterval, + crucialUpdateInterval: TimeInterval, + onScreenUpdateInterval: TimeInterval, + threshold: Int, + normalServiceUpdateInterval: TimeInterval, + crucialServiceUpdateInterval: TimeInterval, + onScreenServiceUpdateInterval: TimeInterval + ) { + self.normalUpdateInterval = normalUpdateInterval + self.crucialUpdateInterval = crucialUpdateInterval + self.onScreenUpdateInterval = onScreenUpdateInterval + self.threshold = threshold + self.normalServiceUpdateInterval = normalServiceUpdateInterval + self.crucialServiceUpdateInterval = crucialServiceUpdateInterval + self.onScreenServiceUpdateInterval = onScreenServiceUpdateInterval + } +} diff --git a/CommonKit/Sources/CommonKit/Models/NodeGroup+Constants.swift b/CommonKit/Sources/CommonKit/Models/NodeGroup+Constants.swift index 1fedf72cd..609311d0a 100644 --- a/CommonKit/Sources/CommonKit/Models/NodeGroup+Constants.swift +++ b/CommonKit/Sources/CommonKit/Models/NodeGroup+Constants.swift @@ -8,45 +8,6 @@ import Foundation public extension NodeGroup { - var crucialUpdateInterval: TimeInterval { 30 } - var onScreenUpdateInterval: TimeInterval { 10 } - - var nodeHeightEpsilon: Int { - switch self { - case .adm: - return 10 - case .btc: - return 2 - case .eth: - return 5 - case .lskService, .lskNode: - return 5 - case .doge: - return 3 - case .dash: - return 3 - } - } - - var normalUpdateInterval: TimeInterval { - switch self { - case .adm: - return 300000 - case .btc: - return 360000 - case .eth: - return 300000 - case .lskNode: - return 270000 - case .lskService: - return 330000 - case .doge: - return 390000 - case .dash: - return 210000 - } - } - var defaultFastestNodeMode: Bool { switch self { case .adm: From b5f97c4d135b867417a58d4334b2eb192b76714c Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Fri, 29 Dec 2023 10:48:02 +0200 Subject: [PATCH 04/27] [trello.com/c/CwJgasMG] feat: update script --- CommonKit/Scripts/CoinsScript.rb | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/CommonKit/Scripts/CoinsScript.rb b/CommonKit/Scripts/CoinsScript.rb index 38432a22a..5fcedfbb3 100755 --- a/CommonKit/Scripts/CoinsScript.rb +++ b/CommonKit/Scripts/CoinsScript.rb @@ -21,24 +21,32 @@ def get_health_check_params_from(json) symbol = json["symbol"] # node_additional_info - node_additional_info = json["nodeAdditionalInfo"] + node_additional_info = json["nodes"]["additionalInfo"] + services = json["services"] + + if !services.nil? + service_additional_info = services["additionalInfo"] + end normal_update_interval = nil crucial_update_interval = nil on_screen_update_interval = nil - threshold =nil + threshold = nil normal_service_update_interval = nil crucial_service_update_interval = nil on_screen_service_update_interval = nil + if !service_additional_info.nil? + normal_service_update_interval = service_additional_info["normalUpdateInterval"] + crucial_service_update_interval = service_additional_info["crucialUpdateInterval"] + on_screen_service_update_interval = service_additional_info["onScreenUpdateInterval"] + end + if !node_additional_info.nil? normal_update_interval = node_additional_info["normalUpdateInterval"] crucial_update_interval = node_additional_info["crucialUpdateInterval"] on_screen_update_interval = node_additional_info["onScreenUpdateInterval"] threshold = node_additional_info["threshold"] - normal_service_update_interval = node_additional_info["normalServiceUpdateInterval"] - crucial_service_update_interval = node_additional_info["crucialServiceUpdateInterval"] - on_screen_service_update_interval = node_additional_info["onScreenServiceUpdateInterval"] if normal_service_update_interval.nil? normal_service_update_interval = normal_update_interval @@ -76,7 +84,7 @@ def writeToSwiftFile(name, json) explorerTx = json["explorerTx"] nodes = "" - nodesArray = json["nodes"] + nodesArray = json["nodes"]["list"] if nodesArray != nil nodesArray.each do |node| url = node["url"] @@ -132,7 +140,7 @@ def writeToSwiftFile(name, json) defaultOrdinalLevel = json["defaultOrdinalLevel"] - minNodeVersion = json["nodeAdditionalInfo"]["minVersion"] + minNodeVersion = json["nodes"]["additionalInfo"]["minVersion"] if minNodeVersion == nil minNodeVersion = "nil" else From 43de876e4648d529cd4135cc72f943e27a7cbbc9 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Fri, 29 Dec 2023 17:40:10 +0200 Subject: [PATCH 05/27] [trello.com/c/CwJgasMG] feat: update script --- CommonKit/Scripts/CoinsScript.rb | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/CommonKit/Scripts/CoinsScript.rb b/CommonKit/Scripts/CoinsScript.rb index 5fcedfbb3..9ccca4b7f 100755 --- a/CommonKit/Scripts/CoinsScript.rb +++ b/CommonKit/Scripts/CoinsScript.rb @@ -21,11 +21,11 @@ def get_health_check_params_from(json) symbol = json["symbol"] # node_additional_info - node_additional_info = json["nodes"]["additionalInfo"] + node_additional_info = json["nodes"]["healthCheck"] services = json["services"] if !services.nil? - service_additional_info = services["additionalInfo"] + service_additional_info = services["healthCheck"] end normal_update_interval = nil @@ -98,13 +98,16 @@ def writeToSwiftFile(name, json) end serviceNodes = "" - services = json["services"] - if services != nil - serviceNodesArray = (symbol == "ADM") ? services["infoService"] : services["#{symbol.downcase}Service"] - if serviceNodesArray != nil - serviceNodesArray.each do |node| - url = node["url"] - serviceNodes += "Node(url: URL(string: \"#{url}\")!),\n" + servicesInfo = json["services"] + if servicesInfo != nil + services = servicesInfo["list"] + if services != nil + serviceNodesArray = (symbol == "ADM") ? services["infoService"] : services["#{symbol.downcase}Service"] + if serviceNodesArray != nil + serviceNodesArray.each do |node| + url = node["url"] + serviceNodes += "Node(url: URL(string: \"#{url}\")!),\n" + end end end end @@ -140,7 +143,13 @@ def writeToSwiftFile(name, json) defaultOrdinalLevel = json["defaultOrdinalLevel"] - minNodeVersion = json["nodes"]["additionalInfo"]["minVersion"] + nodesInfo = json["nodes"] + minNodeVersion = "nil" + + if nodesInfo != nil + minNodeVersion = nodesInfo["minVersion"] + end + if minNodeVersion == nil minNodeVersion = "nil" else From d2fa7ef4d1d008124de50c7fd88bc3493794641c Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Wed, 10 Jan 2024 11:30:25 +0200 Subject: [PATCH 06/27] [trello.com/c/yd3JjZ1f] feat: add chinese localization --- Adamant.xcodeproj/project.pbxproj | 7 + Adamant/Modules/Onboard/OnboardOverlay.swift | 11 +- Adamant/zh.lproj/InfoPlist.strings | 17 + .../Localization/de.lproj/Localizable.strings | 3 + .../Localization/en.lproj/Localizable.strings | 3 + .../Localization/ru.lproj/Localizable.strings | 3 + .../Localization/zh.lproj/Localizable.strings | 1145 +++++++++++++++++ .../zh.lproj/Localizable.stringsdict | 38 + .../Localization/zh.lproj/Localizable.strings | 26 + .../zh.lproj/Localizable.stringsdict | 38 + 10 files changed, 1289 insertions(+), 2 deletions(-) create mode 100644 Adamant/zh.lproj/InfoPlist.strings create mode 100644 CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings create mode 100644 CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.stringsdict create mode 100644 NotificationsShared/Localization/zh.lproj/Localizable.strings create mode 100644 NotificationsShared/Localization/zh.lproj/Localizable.stringsdict diff --git a/Adamant.xcodeproj/project.pbxproj b/Adamant.xcodeproj/project.pbxproj index 32cb3112a..c118ac053 100644 --- a/Adamant.xcodeproj/project.pbxproj +++ b/Adamant.xcodeproj/project.pbxproj @@ -668,6 +668,9 @@ 3AA50DEE2AEBE65D00C58FC8 /* PartnerQRView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PartnerQRView.swift; sourceTree = ""; }; 3AA50DF02AEBE66A00C58FC8 /* PartnerQRViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PartnerQRViewModel.swift; sourceTree = ""; }; 3AA50DF22AEBE67C00C58FC8 /* PartnerQRFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PartnerQRFactory.swift; sourceTree = ""; }; + 3AF08D5B2B4E7FFC00EB82B1 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/InfoPlist.strings; sourceTree = ""; }; + 3AF08D5C2B4E7FFC00EB82B1 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = zh; path = zh.lproj/Localizable.stringsdict; sourceTree = ""; }; + 3AF08D5D2B4E7FFC00EB82B1 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/Localizable.strings; sourceTree = ""; }; 41047B6F294B5EE10039E956 /* VisibleWalletsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleWalletsViewController.swift; sourceTree = ""; }; 41047B71294B5F210039E956 /* VisibleWalletsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleWalletsTableViewCell.swift; sourceTree = ""; }; 41047B73294C61D10039E956 /* VisibleWalletsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleWalletsService.swift; sourceTree = ""; }; @@ -2702,6 +2705,7 @@ ru, de, Base, + zh, ); mainGroup = E913C8E51FFFA51D001A83F7; packageReferences = ( @@ -3454,6 +3458,7 @@ 93E123302A6DF8EF004DF33B /* en */, 93E123322A6DF8F1004DF33B /* de */, 93E123332A6DF8F2004DF33B /* ru */, + 3AF08D5B2B4E7FFC00EB82B1 /* zh */, ); name = InfoPlist.strings; sourceTree = ""; @@ -3464,6 +3469,7 @@ 93E123392A6DFD15004DF33B /* de */, 93E1233B2A6DFD18004DF33B /* ru */, 93E1233C2A6DFD19004DF33B /* en */, + 3AF08D5D2B4E7FFC00EB82B1 /* zh */, ); name = Localizable.strings; sourceTree = ""; @@ -3474,6 +3480,7 @@ 93E123402A6DFE24004DF33B /* en */, 93E123422A6DFE27004DF33B /* de */, 93E123432A6DFE2E004DF33B /* ru */, + 3AF08D5C2B4E7FFC00EB82B1 /* zh */, ); name = Localizable.stringsdict; sourceTree = ""; diff --git a/Adamant/Modules/Onboard/OnboardOverlay.swift b/Adamant/Modules/Onboard/OnboardOverlay.swift index 434e95bb0..97eed9096 100644 --- a/Adamant/Modules/Onboard/OnboardOverlay.swift +++ b/Adamant/Modules/Onboard/OnboardOverlay.swift @@ -20,7 +20,7 @@ final class OnboardOverlay: SwiftyOnboardOverlay { lazy var agreeLabel: UILabel = { let view = UILabel() - view.text = " I accept" + view.text = " \(String.adamant.Onboard.agreeLabel)" view.font = UIFont.adamantPrimary(ofSize: 18)//UIFont(name: "Exo2-Regular", size: 18) view.textColor = UIColor.adamant.textColor return view @@ -30,7 +30,7 @@ final class OnboardOverlay: SwiftyOnboardOverlay { let button = UIButton(type: .system) button.contentHorizontalAlignment = .center - let attrs = NSAttributedString(string: "Terms of Service", + let attrs = NSAttributedString(string: String.adamant.Onboard.eulaTitle, attributes: [NSAttributedString.Key.foregroundColor: UIColor.adamant.textColor, NSAttributedString.Key.font: UIFont(name: "Exo2-Regular", size: 18) ?? UIFont.adamantPrimary(ofSize: 18), @@ -57,3 +57,10 @@ final class OnboardOverlay: SwiftyOnboardOverlay { } } + +private extension String.adamant { + enum Onboard { + static let agreeLabel = String.localized("WelcomeScene.Description.Accept", comment: "Welcome: Description accept") + static let eulaTitle = String.localized("EULA.Title", comment: "") + } +} diff --git a/Adamant/zh.lproj/InfoPlist.strings b/Adamant/zh.lproj/InfoPlist.strings new file mode 100644 index 000000000..270277be1 --- /dev/null +++ b/Adamant/zh.lproj/InfoPlist.strings @@ -0,0 +1,17 @@ +/* Bundle display name */ +"CFBundleDisplayName" = "ADAMANT"; + +/* Bundle name */ +"CFBundleName" = "ADAMANT信使"; + +/* Privacy - Camera Usage Description */ +"NSCameraUsageDescription" = "需要摄像头扫描二维码以查找地址和密码短语"; + +/* Privacy - Face ID Usage Description */ +"NSFaceIDUsageDescription" = "使用Face ID登录您的ADAMANT帐户"; + +/* Privacy - Photo Library Additions Usage Description */ +"NSPhotoLibraryAddUsageDescription" = "保存带有密码短语和地址的二维码"; + +/* Privacy - Photo Library Usage Description */ +"NSPhotoLibraryUsageDescription" = "读取带有密码短语和地址的二维码"; diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings index 7f7b85c0b..9a63eeec0 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings @@ -1138,6 +1138,9 @@ /* Welcome: Skip button */ "WelcomeScene.Description.SkipButton" = "Überspringen"; +/* Welcome: Description accept */ +"WelcomeScene.Description.Accept" = "Ik accepteer"; + /* EULA */ "EULA.Title" = "Geschäftsbedingungen"; "EULA.Accept" = "Akzeptieren"; diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings index e01391cfb..6acb2bd3a 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings @@ -1117,6 +1117,9 @@ /* Welcome: Skip button */ "WelcomeScene.Description.SkipButton" = "Skip"; +/* Welcome: Description accept */ +"WelcomeScene.Description.Accept" = "I accept"; + /* EULA */ "EULA.Title" = "Terms of Service"; "EULA.Accept" = "Accept"; diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings index 262f07c4d..d0123f5e7 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings @@ -1114,6 +1114,9 @@ /* Welcome: Skip button" */ "WelcomeScene.Description.SkipButton" = "Пропустить"; +/* Welcome: Description accept */ +"WelcomeScene.Description.Accept" = "Я принимаю"; + /* EULA */ "EULA.Title" = "Условия использования"; "EULA.Accept" = "Принять"; diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings new file mode 100644 index 000000000..8e02d64e4 --- /dev/null +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -0,0 +1,1145 @@ +/* 通知内容:处理事务时出错 */ +"content.error" = "出现问题!"; + +/* 通知内容:错误格式 */ +"content.error.format" = "出现问题:%@"; + +/* 新的转移通知标题 */ +"transfer.notificationTitle" = "新转让"; + +/* 转移通知正文格式 */ +"transfer.notificationBody.format" = "用户已将您%@"; + +/* 转账通知:"您的地址" */ +"transfer.notificationBody.yourAddress" = "您"; + +/* 关于页面:场景标题 */ +"About.Title" = "关于"; + +/* 关于场景:"阅读"部分标题 */ +"About.Section.About" = "关于ADAMANT"; + +/* 关于场景:"联系我们"部分标题 */ +"About.Section.ContactUs" = "联系我们"; + +/* 贡献场景:"Crashlytics"部分标题 */ +"Contribute.Section.Crashlytics" = "Crashlytics"; + +/* 贡献场景:"Crashlytics"部分描述 */ +"Contribute.Section.CrashlyticsDescription" = "发送匿名崩溃报告,使应用程序更加可靠。我们不收集使用统计信息。"; + +/* 贡献场景:"运行节点"部分标题 */ +"Contribute.Section.RunNodes" = "运行ADAMANT节点"; + +/* 贡献场景:"运行节点"部分描述 */ +"Contribute.Section.RunNodesDescription" = "支持去中心化,提高隐私级别"; + +/* 贡献场景:"网络代理"部分标题 */ +"Contribute.Section.NetworkDelegate" = "成为网络代表"; + +/* 贡献场景:"网络代理"部分描述 */ +"Contribute.Section.NetworkDelegateDescription" = "要成为代表,请支付注册费并获得选民的支持"; + +/* 贡献场景:"代码贡献"部分标题 */ +"Contribute.Section.CodeContribute" = "为代码贡献力量"; + +/* 贡献场景:"代码贡献"部分描述 */ +"Contribute.Section.CodeContributeDescription" = "如果您是开发人员,请加入我们的GitHub存储库"; + +/* 贡献场景:"捐赠"部分标题 */ +"Contribute.Section.Donate" = "捐赠"; + +/* 贡献场景:"捐赠"部分描述 */ +"Contribute.Section.DonateDescription" = "每一次捐赠都让ADAMANT变得更强大"; + +/* 贡献场景:"速率"部分标题 */ +"Contribute.Section.Rate" = "在app Store中对应用进行评分"; + +/* 贡献场景:"速率"部分描述 */ +"Contribute.Section.RateDescription" = "反馈越多,应用程序的可见性越好。突出显示您喜欢的功能"; + +/* 关于场景:网站行 */ +"About.Row.Website" = "网站"; + +/* 关于场景:白皮书行 */ +"About.Row.Whitepaper" = "白皮书"; + +/* 关于场景:Project的GitHub页面行 */ +"About.Row.GitHub" = "项目的GitHub页面"; + +/* 关于场景:给我们写一行 */ +"About.Row.WriteUs" = "电子邮件"; + +/* 关于场景:我们的博客行 */ +"About.Row.Blog" = "我们的博客"; + +/* 关于场景:推特排 */ +"About.Row.Twitter" = "推特"; + +/* "关于场景:网站本地化url" */ +"About.Row.Website.Url" = "https://adamant.im"; + +/* "关于场景:白皮书本地化url" */ +"About.Row.Whitepaper.Url" = "https://adamant.im/whitepaper/adamant-whitepaper-en.pdf"; + +/* "关于场景:Project的GitHub页面本地化url" */ +"About.Row.GitHub.Url" = "https://github.com/Adamant-im"; + +/* "关于场景:我们的博客本地化url" */ +"About.Row.Blog.Url" = "https://medium.com/adamant-im"; + +/* "关于场景:Twitter本地化url" */ +"About.Row.Twitter.Url" = "https://twitter.com/adamant_im"; + +/* 关于场景:写入Adamant行 */ +"About.Row.Adamant" = "Adamant"; + +/* 关于场景:显示欢迎屏幕 */ +"About.Row.Welcome" = "欢迎屏幕"; + +/* 帐户选项卡:"货币"行 */ +"AccountTab.Row.Currency" = "货币"; + +/* 系统帐户:ADAMANT令牌 */ +"Accounts.AdamantTokens" = "欢迎使用ADAMANT"; + +/* 系统帐户:PWA ADM Bounty机器人 */ +"Accounts.AdamantBountyBot" = "ADAMANT Bounty Bot"; + +/* 系统帐户:ADAMANT Bounty */ +"Accounts.AdamantBounty" = "ADAMANT Bounty钱包"; + +/* 系统帐户:ADAMANT支持 */ +"Accounts.Support" = "ADAMANT Support"; + +/* 系统帐户:ADAMANT Exchange */ +"Accounts.AdamantExchange" = "ADAMANT Exchange"; + +/* 系统账户:押注比特币价格 */ +"Accounts.BetOnBitcoin" = "押注比特币价格"; + +/* 系统帐户:Adeline */ +"Accounts.Adelina" = "Adelina AI"; + +/* 系统账户:捐赠ADAMANT基金会 */ +"Accounts.DonateADMFoundation" = "向ADAMANT基金会捐款"; + +/* AccountsProvider:地址无效错误,%@代表地址 */ +"AccountsProvider.Error.AddressNotValidFormat" = "无效地址:%@"; + +/* AccountService:警报标题。1.2版中的更改 */ +"AccountService.update.v12.title" = "版本1.2更新:加密钱包"; + +/* AccountService:警报消息。1.2版本中的更改,通知用户需要重新登录才能启动eth&lsk钱包 */ +"AccountService.update.v12.message" = "您需要重新登录才能启动以太坊钱包"; + +/* AccountService:用户必须重新登录应用程序才能启动钱包 */ +"AccountService.reloginToInitializeWallets" = "重新登录以启动钱包"; + +/* 登录:用户键入了无效的密码短语 */ +"AccountServiceError.InvalidPassphrase" = "错误的密码短语"; + +/* 登录:用户键入了错误的密码短语 */ +"AccountServiceError.FrowngPassphrase" = "错误的密码短语"; + +/* 帐户选项卡:确认注销警报:注销(确定)按钮 */ +"AccountTab.ConfirmLogout.Logout" = "注销"; + +/* 帐户选项卡:确认注销警报 */ +"AccountTab.ConfirmLogout.MessageFormat" = "从%@注销?"; + +/* 帐户选项卡:完整的"获取免费代币"链接,地址为%@ */ +"AccountTab.FreeTokens.UrlFormat" = "https://adamant.im/free-adm-tokens/?wallet=%@"; + +/* 帐户选项卡:完整的"购买代币"链接,地址为%@ */ +"AccountTab.BuyTokens.UrlFormat" = "https://adamant.im/buy-tokens/?wallet=%@"; + +/* "帐户"选项卡:余额行标题 */ +"AccountTab.Row.Balance" = "余额"; + +/* 帐户选项卡:"购买代币"按钮 */ +"AccountTab.Row.BuyTokens" = "交换代币"; + +/* 帐户选项卡:"注销"按钮 */ +"AccountTab.Row.Logout" = "注销"; + +/* 帐户选项卡:"安全"行 */ +"AccountTab.Row.Security" = "安全性"; + +/* 账户选项卡:"发送代币"按钮 */ +"AccountTab.Row.SendTokens" = "发送令牌"; + +/* 帐户选项卡:"发送ADM令牌"按钮 */ +"AccountTab.Row.SendAdm" = "发送ADM"; + +/* 账户选项卡:"发送ETH代币"按钮 */ +"AccountTab.Row.SendEth" = "发送ETH"; + +/* 账户选项卡:"发送LSK代币"按钮 */ +"AccountTab.Row.SendLsk" = "发送LSK"; + +/* 账户选项卡:"发送BTC代币"按钮 */ +"AccountTab.Row.SendBtc" = "发送BTC"; + +/* 账户选项卡:"发送DOGE代币"按钮 */ +"AccountTab.Row.SendDoge" = "发送DOGE"; + +/* 帐户选项卡:"发送DASH令牌"按钮 */ +"AccountTab.Row.SendDash" = "发送DASH"; + +/* 账户选项卡:"发送ERC20代币"按钮 */ +"AccountTab.Row.SendToken" = "发送%@"; + +/* 账户选项卡:匿名购买ADM代币 */ +"AccountTab.Row.AnonymouslyBuyADM" = "匿名更改ADM"; + +/* 帐户选项卡:在聊天中交换ADM令牌 */ +"AccountTab.Row.ExchangeADMInChat" = "聊天内交换器"; + +/* 帐户选项卡:"地址"行 */ +"AccountTab.Row.Address" = "地址"; + +/* 帐户选项卡:"获取免费代币"按钮 */ +"AccountTab.Row.FreeTokens" = "免费ADM令牌"; + +/* 帐户选项卡:"主题"行 */ +"AccountTab.Row.Theme" = "主题"; + +/* 帐户选项卡:"主题"行值"浅色" */ +"AccountTab.Row.Theme.Light" = "灯光"; + +/* 帐户选项卡:"主题"行值"深色" */ +"AccountTab.Row.Theme.Dark" = "黑暗"; + +/* 帐户选项卡:"关于"行 */ +"AccountTab.Row.About" = "关于"; + +/* 帐户选项卡:"贡献"行 */ +"AccountTab.Row.Contribute" = "投稿"; + +/* 帐户选项卡:"为代表投票"按钮 */ +"AccountTab.Row.VoteForDelegates" = "为代表投票"; + +/* "帐户"选项卡:"操作"部分标题 */ +"AccountTab.Section.Actions" = "行动"; + +/* "帐户"选项卡:"应用程序"部分标题 */ +"AccountTab.Section.Application" = "应用"; + +/* 账户选项卡:阿达曼钱包 */ +"AccountTab.Wallets.adamant_wallet" = "adamant钱包"; + +/* 账户选项卡:以太坊钱包 */ +"AccountTab.Wallets.ethereum_wallet" = "以太坊钱包"; + +/* 账户选项卡:Lisk钱包 */ +"AccountTab.Wallets.lisk_vallet" = "lisk钱包"; + +/* 账户选项卡:比特币钱包 */ +"AccountTab.Wallets.bitcoin_wallet" = "比特币钱包"; + +/* 账户选项卡:狗狗钱包 */ +"AccountTab.Wallets.doge_ewallet" = "狗狗钱包"; + +/* 账户选项卡:达世币钱包 */ +"AccountTab.Wallets.dash_wallet" = "达世币钱包"; + +/* 账户选项卡:ERC20钱包 */ +"AccountTab.Wallets.erc20_wallet" = "%@钱包"; + +/* 帐号页面:场景标题 */ +"AccountTab.Title" = "帐户"; + +/* "帐户"选项卡:"代理人"部分标题 */ +"AccountTab.Section.Delegates" = "代理人"; + +/* 产品名称 */ +"ADAMANT" = "坚定不移"; + +/* AddressBookService:没有足够的钱将地址保存到区块链中 */ +"AddressBookService.Error.notEnoughMoney" = "没有足够的令牌在区块链中存储数据"; + +/* 应用程序:无法将deviceToken发送到ANS错误格式。%@用于错误描述 */ +"Application.deviceTokenErrorFormat" = "无法在ANS:%@中注册"; + +/* 严重内部错误:无法生成终结点url */ +"ApiService.InternalError.EndpointBuildFailed" = "端点构建失败。报告错误"; + +/* 严重内部错误:无法签署交易 */ +"ApiService.InternalError.FailedTransactionSigning" = "事务失败"; + +/* 严重内部错误:分析响应时出错 */ +"ApiService.InternalError.PassingFailed" = "分析失败。报告错误"; + +/* 严重的内部错误:没有可用的节点 */ +"ApiService.InternalError.NoNodesAvailable" = "没有活动的%@节点。查看节点列表"; + +/* 尤里卡表格取消按钮 */ +"Cancel" = "取消"; + +/* 聊天列表:传出消息前缀 */ +"ChatListPage.SentMessagePrefix" = "您:"; + +/* 聊天列表:SearchBar占位符文本 */ +"ChatListPage.SearchBar.Placeholder" = "搜索联系人或消息"; + +/* 搜索页面:联系人标题 */ +"SearchPage.Contacts" = "联系人"; + +/* 搜索页面:联系人标题 */ +"SearchPage.Contact.New" = "新联系人"; + +/* 搜索页面:联系人新标题 */ +"SearchPage.Contact.Add.New" = "[添加新联系人]"; + +/* SearchPage:消息标题 */ +"SearchPage.Messages" = "信息"; + +/* 聊天列表:第一次同步正在进行中 */ +"ChatListPage.SyncingChats" = "正在同步聊天…"; + +/* 聊天列表:已反应 */ +"ChatListPage.Rreached" = "达到"; + +/* 聊天列表:删除的反应 */ +"ChatListPage.RemotedReaction" = "已删除反应"; + +/* 聊天列表:场景标题 */ +"ChatListPage.Title" = "聊天"; + +/* 聊天提供商:通知用户他没有钱支付消息费 */ +"ChatsProvider.Error.notEnoughMoney" = "零余额。获得免费ADM代币"; + +/* ChatsProvider:未找到事务错误。%@用于事务的ID */ +"ChatsProvider.Error.TransactionNotFoundFormat" = "找不到id为%@的消息"; + +/* ChatsProvider:验证错误:消息为空 */ +"ChatsProvider.Validation.MessageIsEmpty" = "消息为空"; + +/* ChatsProvider:验证错误:消息太长 */ +"ChatsProvider.Validation.MessageTooLong" = "消息太长"; + +/* 已知联系人:Adamant ICO消息。支持降价 */ +"Chats.IcoMessage" = "Null"; + +/* 已知联系人:Adamant预ICO消息 */ +"Chats.PreIcoMessage" = "Null"; + +/* 已知联系人:Adamant欢迎信息。支持降价 */ +"Chats.WelcomeMessage" = "ADAMANT是一个真正的区块链信使,独立于政府、企业甚至开发商。这是由于去中心化的网络基础设施,完全开源,由用户运行。这就是为什么每一个动作,包括发送消息或保存联系人姓名,都有0.001 ADM的网络费用。\n\nBlockchain提供了卓越的安全性和隐私,这是典型的P2P和c集中的信使。此外,区块链提供了新的可能性。您可以在聊天中存储和传输密码,并完全控制您的私钥,使用ADAMANT作为2FA等。\\n\nADAMANT中,没有人可以控制、阻止、停用、限制或审查帐户。用户对内容、消息、媒体以及使用Messenger的目标和意图承担全部责任。\\n\n请注意,您的安全性和匿名性取决于您。不要关注你收到的链接,否则你的IP可能会被泄露。在设备上设置密码。了解有关安全性和匿名性的更多信息,请访问https://adamant.im/staysecured/.\\n\n请确保已保存此帐户的密码短语--注销并再次登录。把你的通行证短语也写在纸上。只有**您对通行证短语的安全负责**。它无法恢复。如果其他人得到了它,你的代币就会被盗,信件也会被读取。把这个问题看得最重要,就好像你钱包里的代币在一段时间内会花费10亿美元一样。\\n\n若要立即开始发送消息,请在\"帐户\"选项卡上**获得免费欢迎令牌**。然后创建新聊天并输入您朋友的ADM地址。建议您亲自分享ADM地址,不要使用其他信使。"; + +/* 已知联系人:Adamant Exchenge消息。支持降价 */ +"Chats.Exchange.WellomeMessage" = "嗨!😊 我是你的交换机器人。我即时匿名操作。键入* */help**看看我能做些什么。我要求的费用比我的机器人同伴高,所以我建议你以有竞争力的费用建立自己的机器人。ℹ️ 你可以在ADAMANT博客上了解更多信息。我非常可靠,但如果您有任何问题,请在这里留言U6386412615727665758。"; + +/* 已知联系人:Adamant押注比特币消息。支持降价 */ +"Chats.BetOnBitcoin.WelcomeMessage" = "嗨!😊 我是匿名的,区块链验证的投注机器人。我接受BTC费率的投注,并向中奖者支付奖励。ℹ️ 在ADAMANT的博客上了解更多信息,或键入* */help**开始下注。通过U63864126157276665758提供支持。"; + +/* 已知联系人:Adamant Adelina消息。支持降价 */ +"Chats.Adelina.WelcomeMessage" = "你好,我是Adelina。让我们愉快地交谈一下!我可以做很多事情,比如:\n\n-起草电子邮件或其他文章\n-编写Python代码\n-回答关于一组文档的问题\n-支持对话\n-一系列主题的导师\n-翻译语言\n-写诗\n-模拟电子游戏中的角色等等"; + +/* 已知联系人:阿达曼捐赠欢迎信息。支持降价 */ +"Chats.Donate.WellomeMessage" = "感谢您的支持,我们开发了去中心化的ADAMANT Messenger——在此聊天中转移ADM、ETH和其他代币。有关其他捐赠钱包,请参阅consided.im。"; + +/* 警报"重试或删除"标题。在caht中用于再次发送或删除失败的消息 */ +"Chats.RetryOrDelete.Title" = "重试还是删除?"; + +/* 警报"重试或删除"正文消息。用于聊天,用于再次发送或删除失败的消息 */ +"Chats.RetryOrDelete.Body" = "尝试再次发送消息,还是删除它?"; + +/* 按钮"阻止" */ +"Chats.Block" = "区块链 区块"; + +/* 警报"是否阻止此用户?" */ +"Chats.BlockUser" = "是否阻止此用户?"; + +/* "删除"按钮 */ +"Chats.Remove" = "删除"; + +/* 警报"是否删除此消息?" */ +"Chats.RemoveMessage" = "是否删除此消息?"; + +/* Button "Report" */ +"Chats.Report" = "报告"; + +/* "回复"按钮 */ +"Chats.Reply" = "回复"; + +/* "复制"按钮 */ +"Chats.Copy" = "复制"; + +/* 警报"报告为不合适?" */ +"Chats.ReportMessage" = "是否报告为不合适?"; + +/* 警报"报告已发送" */ +"Chats.ReportSent" = "报告已发送"; + +/* 聊天:通知用户他不能取消已发送的交易 */ +"ChatScene.Error.cancelError" = "消息已发送"; + +/* 聊天:消息输入占位符 */ +"ChatScene.NewMessage.Placeholder" = "新消息"; + +/* 聊天:发送信息按钮 */ +"ChatScene.Send" = "发送"; + +/* 聊天:"已发送资金"泡沫标题 */ +"ChatScene.Sent" = "已发送"; + +/* 聊天:"收到的资金"泡沫标题 */ +"ChatScene.Received" = "已接收"; + +/* 聊天:"已发送资金"buble"点击了解详细信息"提示 */ +"ChatScene.tapForDetails" = "点击获取详细信息"; + +/* 聊天:发送聊天事务失败的状态消息 */ +"ChatScene.MessageStatus.FailToSend" = "发送失败"; + +/* 聊天:挂起聊天事务的状态消息 */ +"ChatScene.MessageStatus.Pending" = "待定"; + +/* 聊天:警告聊天事务的状态消息 */ +"ChatScene.MessageStatus.Warning" = "警告"; + +/* 聊天:动作正文菜单 */ +"ChatScene.Actions.Body" = "%@的新名称"; + +/* 聊天:操作菜单中的"重命名"操作 */ +"ChatScene.Actions.Rename" = "重命名"; + +/* 聊天:操作菜单中的"姓名"字段 */ +"ChatScene.Actions.NamePlaceholder" = "名称"; + +/* 聊天:"免费代币"按钮 */ +"ChatScene.FreeTokensAlert.FreeTokens" = "🎁 免费代币"; + +/* 聊天:"免费代币"消息 */ +"ChatScene.FreeTokensAlert.Message" = "ADAMANT是一个独特的区块链信使,独立于政府、企业甚至其开发者。这是可能的,因为它是一个去中心化的网络,完全开源,由用户运行。这就是为什么每一个动作,包括发消息或保存新联系人,都要收取0.001 ADM.的网络费。要立即开始发消息,请获得免费的欢迎令牌。"; + +/* 聊天:在设备上未配置邮件应用程序的情况下打开电子邮件链接的警告消息 */ +"ChatScene.Warning.NoMailApp" = "无法发送电子邮件。请检查邮件应用程序配置。"; + +/* 聊天:打开不支持的url方案的警告消息 */ +"ChatScene.Warning.UnsupportedUrl" = "不支持的url协议"; + +/* 聊天:滚动到消息时出错,此消息已被删除,无法再访问 */ +"ChatScene.Error.messageWasDeleted" = "很抱歉,此消息已被删除,无法再访问"; + +/* 聊天:错误消息太大 */ +"ChatScene.Error.messageIsTooBig" = "消息太大。分部分发送。"; + +/* 代理人页面:场景标题 */ +"Delegates.Title" = "Delegates"; + +/* 可见钱包页面:场景标题 */ +"VisibleWallets.Title" = "钱包列表"; + +/* VisibleWallets:重置钱包警报标题 */ +"VisibleWallets.ResetListAlert" = "是否将钱包列表重置为默认值?"; + +/* 代理人选项卡:关于50 ADM投票费的信息 */ +"Delegates.NotEnoughtTokensForVote" = "没有足够的代币可以投票。您需要50个ADM"; + +/* 代理人选项卡:关于新投票超时的消息 */ +"Delegates.timeOutBeforeNewVote" = "请等待上一次投票处理完毕"; + +/* 代理详细信息:场景标题 */ +"DelegateDetails.Title" = "详细信息"; + +/* 代理人详细信息屏幕:"用户名"的行标题 */ +"DelegateDetails.Row.Username" = "用户名"; + +/* 代理人详细信息屏幕:"地址"的行标题 */ +"DelegateDetails.Row.Address" = "地址"; + +/* 代理人详细信息屏幕:"公钥"的行标题 */ +"DelegateDetails.Row.PublicKey" = "公钥"; + +/* 代表详细信息屏幕:"投票权重"的行标题" */ +"DelegateDetails.Row.VoteWeight" = "投票权重"; + +/* 代理详细信息屏幕:"生成的块"的行标题 */ +"DelegateDetails.Row.ProductedBlocks" = "生产的块"; + +/* 代理详细信息屏幕:"错过的块"的行标题" */ +"DelegateDetails.Row.MissedBlocks" = "错过的块"; + +/* 代理人详细信息屏幕:"费率"的行标题 */ +"DelegateDetails.Row.Rate" = "Rate"; + +/* 代理人详细信息屏幕:"排名"的行标题 */ +"DelegateDetails.Row.Rank" = "等级"; + +/* 代理人详细信息屏幕:"批准"的行标题" */ +"DelegateDetails.Row.Approval" = "审批"; + +/* 代理人详细信息屏幕:"生产力"的行标题" */ +"DelegateDetails.Row.Productivity" = "生产率"; + +/* 代表详细信息屏幕:"锻造时间"的行标题" */ +"DelegateDetails.Row.ForgingTime" = "锻造时间"; + +/* 代表详细信息屏幕:"伪造"的行标题 */ +"DelegateDetails.Row.Forged" = "伪造"; + +/* 代表:成功投票的消息 */ +"Delegates.Vote.Success" = "您的投票已发送"; + +/* Storybard-代表投票面板:"支持票"标签 */ +"Delegates.VotePanel.Upvotes" = "向上投票:"; + +/* Storybard-代表投票面板:"否决票"标签 */ +"Delegates.VotePanel.Downvotes" = "反对票:"; + +/* Storybard-代表投票面板:"新"标签 */ +"Delegates.VotePanel.New" = "新:"; + +/* Storybard-代表投票面板:"总计"标签 */ +"Delegates.VotePanel.Total" = "总计:"; + +/* 共享错误:找不到帐户错误。使用%@作为地址 */ +"Error.AccountNotFoundFormat" = "找不到帐户:%@"; + +/* 共享错误:帐户未启动 */ +"Error.AccountNotInitiated" = "帐户未启动"; + +/* 共享错误:消息的内部错误格式为%@ */ +"Error.InteralErrorFormat" = "内部错误:%@"; + +/* 共享错误:消息的基本格式为%@ */ +"Error.BaseErrorFormat" = "错误:%@"; + +/* 支持电子邮件的错误消息标题 */ +"Error.Mail.Title" = "iOS应用程序中的错误"; + +/* 支持电子邮件的错误消息正文 */ +"Error.Mail.Body" = "你好,\n\n我有这个错误:\n\n%@\n\n我的设备信息:\n\n%@"; + +/*支持电子邮件的错误消息正文,以及详细的错误描述。其中,第一个%@-错误的短消息,第二个%@–详细描述,第三个%@-设备信息 */ +"Error.Mail.Body.Detailed" = "你好,\n\n我有这个错误:\n\n%@\n\n%@\n\n设备:\n\n%@"; + +/* 共享错误:网络问题。在大多数情况下-无连接 */ +"Error.NoNetwork" = "无连接"; + +/* 共享错误:请求已取消 */ +"Error.RequestCancelled" = "请求已取消"; + +/* 共享错误:消息的远程错误格式为%@ */ +"Error.RemoteServerErrorFormat" = "区块链节点错误:%@"; + +/* 共享错误:用户未登录 */ +"Error.UserNotLogged" = "用户未登录"; + +/* 共享未知错误 */ +"Error.UnnowError" = "未知错误。报告错误"; + +/* 登录:通知用户,他在设置中禁用了摄像头,需要授权应用程序 */ +"LoginScene.Error.AuthorizeCamera" = "您需要授权ADAMANT才能使用设备的摄像头"; + +/* 登录:用户禁用了对光库的访问,他可以在设置中授权应用程序 */ +"LoginScene.Error.AuthorizePhotolibrary" = "您需要授权ADAMANT才能使用您的照片库"; + +/* 登录:没有网络错误 */ +"LoginScene.Error.NoInternet" = "没有连接到Internet"; + +/* 登录:通知用户他正尝试在没有密码的情况下登录 */ +"LoginScene.Error.NoPassphrase" = "输入密码短语"; + +/* 登录:通知用户所选照片不包含带密码的有效二维码 */ +"LoginScene.Error.NoQrOnPhoto" = "所选图像不包含有效的二维码"; + +/* 登录:通知用户QR阅读器不支持该设备 */ +"LoginScene.Error.QrNotSupported" = "设备不支持读取二维码"; + +/* 登录:通知用户扫描的QR不包含密码短语 */ +"LoginScene.Error.WrongQr" = "二维码不包含有效的密码短语"; + +/* 登录:通知用户我们正在尝试登录 */ +"LoginScene.LoggingInProgress" = "正在登录…"; + +/* 登录:使用biometry或pincode登录到以前的帐户 */ +"LoginScene.LoginIntoAdamant" = "登录到ADAMANT"; + +/* 登录:生成新密码短语按钮 */ +"LoginScene.Row.Generate" = "生成新密码短语"; + +/* 登录:登录按钮 */ +"LoginScene.Row.Login" = "登录"; + +/* 登录:密码短语占位符 */ +"LoginScene.Row.Passphrase.Placeholder" = "密码短语"; + +/* 登录:使用密码按钮登录 */ +"LoginScene.Row.Pincode" = "使用PIN码登录"; + +/* 登录:使用二维码按钮登录 */ +"LoginScene.Row.Qr" = "使用二维码登录"; + +/* 登录:安全警报,通知用户必须保存新密码。支持向下标记,居中对齐 */ +"LoginScene.Row.SavePassphraseAlert" = "**保存新钱包和Messenger帐户的密码短语**。没有登录信息可以进入钱包,只需要密码短语。**如果丢失,无法恢复**。"; + +/* 登录:对用户的一个小提示,他可以点击密码短语来保存它 */ +"LoginScene.Row.TapToSave" = "点击保存"; + +/* 登录:使用现有密码段登录 */ +"LoginScene.Section.Login" = "登录"; + +/* 登录:创建新帐户部分 */ +"LoginScene.Section.NewAccount" = "新帐户"; + +/* 新聊天:收件人地址占位符。请注意,地址文本字段总是显示U字母,所以您可以将这一行留空 */ +"NewChatScene.Address.Placeholder" = ""; + +/* 新聊天:通知用户找不到指定的地址(%@)。使用%@作为地址 */ +"NewChatScene.Error.AddressNotFoundFormat" = "未找到地址:%@"; + +/* 新聊天:通知用户他输入了无效地址 */ +"NewChatScene.Error.InvalidAddress" = "输入有效地址"; + +/* 新聊天:通知用户他无法开始与自己聊天 */ +"NewChatScene.Error.OwnAddress" = "你不需要加密的匿名聊天来与自己交谈"; + +/* 新聊天:通知用户扫描的二维码不包含地址 */ +"NewChatScene.Error.WrongQr" = "二维码不包含有效地址"; + +/* 新聊天:使用地址按钮扫描二维码 */ +"NewChatScene.ScanQr" = "扫描二维码"; + +/* 新聊天:场景标题 */ +"NewChatScene.Title" = "新聊天"; + +/* 新聊天:显示我的地址按钮的二维码 */ +"NewChatScene.MyQr" = "显示我的二维码"; + +/* 新聊天:"这是什么意思?",有关未初始化帐户的信息的帮助按钮 */ +"NewChatScene.NotInitialized.HelpButton" = "这是什么意思?"; + +/* NodesList:按钮标签 */ +"NodesList.NodesList" = "ADM节点列表"; + +/* 节点列表:场景标题 */ +"NodesList.Title" = "ADM节点列表"; + +/* NodesList:"添加新节点"按钮标签 */ +"NodesList.AddNewNode" = "添加新节点"; + +/* NodesList:重置节点警报标题 */ +"NodesList.ResetNodeListAlert" = "是否将节点列表重置为默认值?"; + +/* NodesList:"重置"按钮 */ +"NodesList.ResetButton" = "重置"; + +/* NodesList:"首选最快的节点"开关 */ +"NodesList.PreferTheFastestNode" = "首选最快的节点"; + +/* NodesList:"首选最快的节点"开关 */ +"NodesList.PreferTheFastestNode.Footer" = "处理请求更快,但可能会减少隐私"; + +/* 节点列表。NodeCell:节点ping */ +"NodesList.NodeCell.Ping" = "Ping"; + +/* 节点列表。NodeCell:毫秒 */ +"NodesList.NodeCell.Milliseconds" = "ms"; + +/* 节点列表。NodeCell:节点正在同步 */ +"NodesList.NodeCell.Synchronizing" = "正在同步"; + +/* 节点列表。NodeCell:节点处于脱机状态 */ +"NodesList.NodeCell.Online" = "脱机"; + +/* 节点列表。NodeCell:节点已禁用 */ +"NodesList.NodeCell.Disabled" = "已禁用"; + +/* 节点列表。NodeCell:节点版本 */ +"NodesList.NodeCell.Version" = "版本"; + +/* NodeList:如果用户删除了所有节点,则通知默认节点已加载 */ +"NodeList.DefaultNodesLoaded" = "已加载默认节点列表"; + +/* 硬币节点列表:标题 */ +"CoinsNodesList.Title" = "Coin和服务节点列表"; + +/* CoinsNodesList:ServiceNode */ +"CoinsNodesList.ServiceNode" = "服务"; + +/* NodesEditor:新节点场景标题 */ +"NodesEditor.NewNodeTitle" = "新节点"; + +/* NodesEditor:删除节点确认消息 */ +"NodesEditor.DeleteNodeAlert" = "是否删除此节点?"; + +/* NodesEditor:测试正在进行中 */ +"NodesEditor.TestingInProgressMessage" = "正在检查连接…"; + +/* NodesEditor:Scheme行 */ +"NodesEditor.SchemeRow" = "Scheme"; + +/* NodesEditor:端口行 */ +"NodesEditor.PortRow" = "端口"; + +/* NodesEditor:主机行 */ +"NodesEditor.HostRow" = "主机"; + +/* NodesEditor:Web套接字 */ +"NodesEditor.Webockets" = "Web套接字"; + +/* NodesEditor:支持Web套接字 */ +"NodesEditor.WebocketsSupported" = "支持"; + +/* NodesEditor:不支持Web套接字 */ +"NodesEditor.WebocketsNotSupported" = "不支持"; + +/* NodesEditor:删除节点按钮 */ +"NodesEditor.DeleteNodeButton" = "删除"; + +/* NodesEditor:主机行占位符 */ +"NodesEditor.HostRow.Placeholder" = "IP或主机名"; + +/* NodesEditor:无法生成URL警报 */ +"NodesEditor.FailedToBuildURL" = "无效主机"; + +/* 安全性:通知模式说明。支持降价 */ +"SecurityPage.Row.Notifications.ModesDescription" = "####通知模式\n\n####禁用\n无通知。\n\n####后台提取\n您的设备会自动提取新消息。没有外部调用。提取由iOS启动,实际时间由操作系统根据电池电量、蜂窝网络、应用程序使用模式等许多因素确定,无法预测。可以是20分钟、6小时,甚至可能是一天。不过,您仍然可以打开应用程序并查看新消息。\n\n####推送\n ADAMANT通知服务发送到您的设备的通知。在消息发送并获得区块链批准后,您几乎会立即收到通知——延迟几秒钟。但此模式要求您的设备在服务的数据库中注册其设备令牌。设备令牌是安全的,在大多数情况下建议使用此选项。\\n\n您可以在ADAMANT的Github页面上阅读更多关于设备注册的信息。\n \n"; + +/* 安全性:选定的通知类型 */ +"SecurityPage.Section.NotificationsType" = "Notifications"; + +/* 安全性:关于通知类型 */ +"SecurityPage.Section.AboutNotificationTypes" = "关于ANS"; + +/* 安全:消息通知声音 */ +"SecurityPage.Section.Messages" = "Messages"; + +/* 安全:设置通知 */ +"SecurityPage.Section.Settings" = "Settings"; + +/* 通知:禁用通知 */ +"Notifications.Mode.NotificationsDisabled" = "已禁用"; + +/* 通知:使用后台提取通知 */ +"Notifications.Mode.BackgroundFetch" = "后台获取"; + +/* 通知:使用Apple推送通知 */ +"Notifications.Mode.ApplePush" = "推送"; + +/* 安全:访问Github */ +"SecurityPage.Row.VisitGithub" = "访问Github"; + +/* 通知:打开系统设置 */ +"Notifications.Settings.System" = "系统设置"; + +/* 通知:选择声音 */ +"Notifications.Sound.Name" = "声音"; + +/* 通知:选择声音 */ +"Notifications.Sounds.Name" = "Sounds"; + +/* 通知:选择提醒音调 */ +"Notifications.Alert.Tones" = "Alert Tones"; + +/* 通知:选择警报保存 */ +"Notifications.Alert.Save" = "保存"; + +/* 通知:警报取消 */ +"Notifications.Alert.Cancel" = "取消"; + +/* Pinpad:要求用户创建新引脚 */ +"Pinpad.EnterNewPin" = "输入新的PIN码"; + +/* Pinpad:要求用户重复新引脚 */ +"Pinpad.RenerPin" = "重新输入您的PIN码"; + +/* QRGenerator:错误的内部生成器错误消息格式。使用%@作为错误描述 */ +"QrGeneratorScene.Error.InteralErrorFormat" = "内部错误:%@。报告错误"; + +/* QRGenerator:用户键入了无效的密码短语 */ +"QrGeneratorScene.Error.InvalidPassphrase" = "输入有效的密码短语"; + +/* QRGenerator:密码短语文本视图占位符 */ +"QrGeneratorScene.Passphrase.Placeholder" = "密码短语"; + +/* QRGenerator:生成的QR下的小"点击保存"工具提示 */ +"QrGeneratorScene.TapToSave" = "点击保存"; + +/* QRGenerator:场景标题 */ +"QrGeneratorScene.Title" = "QR生成器"; + +/* PrivateKeyGenerator:场景标题 */ +"PkGeneratorScene.Title" = "私钥生成器"; + +/* PrivateKeyGenerator:安全警报。确保密码的安全 */ +"PkGeneratorScene.Alert" = "ADAMANT帐户包括加密钱包。所有这些钱包都与您的密码连接,只有您可以访问这些钱包。您可以导出私钥以在其他应用程序中使用它们。将密钥存储在安全的地方。"; + +/* PrivateKeyGenerator:"生成"按钮 */ +"PkGeneratorScene.GenerateButton" = "生成密钥"; + +/* 安全:场景标题 */ +"SecurityPage.Title" = "安全性"; + +/* 安全:关闭"保持登录"确认 */ +"SecurityPage.DoNotStayLoggedIn" = "不保持登录状态"; + +/* 配置:关闭生物测量的授权原因 */ +"SecurityPage.DoNotUseBiometry" = "不使用biometry登录"; + +/* 安全性:生成带有密码短语行的QR */ +"SecurityPage.Row.GenerateQr" = "生成带有密码短语的QR"; + +/* 安全性:使用密码短语行生成PrivateKey */ +"SecurityPage.Row.GeneratePk" = "导出私钥"; + +/* 安全性:显示通知 */ +"SecurityPage.Row.Notifications" = "通知"; + +/* 安全:保持记录行 */ +"SecurityPage.Row.StayLoggedIn" = "保持登录状态"; + +/* 安全:安全部分 */ +"SecurityPage.Section.Security" = "安全性"; + +/* 配置:场景标题 */ +"SettingsPage.Title" = "设置"; + +/* 安全:开启生物测量的授权原因 */ +"SecurityPage.UseBiometry" = "使用生物测量"; + +/* 共享警报"取消"按钮。在任何地方使用 */ +"Shared.Cancel" = "取消"; + +/* 共享警报通知:关于项目复制到粘贴板的消息 */ +"Shared.CopiedToPasteboard" = "已复制到粘贴板"; + +/* 共享警报"复制"按钮。在任何地方使用。用于复制粘贴信息 */ +"Shared.CopyToPasteboard" = "复制到粘贴板"; + +/* 共享警报"聊天"按钮。用于与收件人聊天 */ +"Shared.ChatWith" = "与聊天"; + +/* 共享警报"发送ADM到"按钮。用于将ADM发送到收件人 */ +"Shared.SendAdmTo" = "将ADM发送到"; + +/* 共享警报完成消息。在任何地方使用 */ +"Shared.Done" = "完成"; + +/* 共享警报"错误"标题。在任何地方使用 */ +"Shared.Error" = "错误"; + +/* 共享警报"生成QR"按钮。用于生成带有地址和密码短语的二维码。用于随时随地共享和保存 */ +"Shared.GenerateQRCode" = "生成二维码"; + +/* 共享警报通知:无internet连接消息的标题 */ +"Shared.NoInternet.Title" = "无互联网连接"; + +/* 共享警报通知:没有互联网连接的正文消息 */ +"Shared.NoInternet.Body" = "请检查您的互联网连接,然后重试"; + +/* 共享警报"确定"按钮。在任何地方使用 */ +"Shared.Ok" = "Ok"; + +/* 共享警报"保存"按钮。在任何地方使用 */ +"Shared.Save" = "保存"; + +/* 共享警报"保存到照片"。用于将图像保存到光库 */ +"Shared.SaveToPhotolibrary" = "保存到照片"; + +/* 共享警报"设置"按钮。用于转到应用程序设置页面上的系统设置应用程序。应与"设置"应用程序标题相同 */ +"Shared.Settings" = "设置"; + +/* 共享警报"共享"按钮。用于任何地方展示标准的iOS"共享"菜单 */ +"Shared.Share" = "共享"; + +/* 共享警报"重试"按钮。在任何地方使用 */ +"Shared.Retry" = "重试"; + +/* 共享警报"删除"按钮。在任何地方使用 */ +"Shared.Delete" = "删除"; + +/* ShareQR场景:用户未经授权将图像写入照片库 */ +"ShareQR.protorilibraryNotAuthorized" = "您需要授权ADAMANT才能使用您的照片库"; + +/* 主选项卡栏:帐户页面 */ +"Tabs.Account" = "帐户"; + +/* 主选项卡栏:聊天页面 */ +"Tabs.Chats" = "聊天"; + +/* 主选项卡栏:设置页面 */ +"Tabs.Settings" = "设置"; + +/* TransactionList:场景标题 */ +"TransactionListScene.Title" = "事务"; + +/* TransactionList:To Chat按钮 */ +"TransactionListScene.ToChat" = "聊天"; + +/* 事务列表:开始聊天按钮 */ +"TransactionListScene.StartChat" = "开始聊天"; + +/* TransactionList:"未找到事务"消息 */ +"TransactionListScene.Error.NotFound" = "未找到事务"; + +/* TransactionList:"尚未进行交易"消息 */ +"TransactionListScene.NoTransactionYet" = "还没有事务"; + +/* TransactionList:"找不到事务"本地化来自API的错误消息 */ +"No transactions found" = "未找到交易"; + +/* 交易发送:收件人最低剩余余额要求 */ +"TransactionSend.Minimum.Balance" = "收件人必须至少具有0.05 LSK--发送更多令牌"; + +/* 事务状态:正在更新 */ +"TransactionStatus.Updateing" = "正在更新…"; + +/* 交易状态:交易处于挂起状态 */ +"TransactionStatus.Pending" = "待定"; + +/* 交易状态:成功 */ +"TransactionStatus.Success" = "成功"; + +/* 交易状态:交易失败 */ +"TransactionStatus.Failed" = "失败"; + +/* 交易状态:不一致 */ +"TransactionStatus.Inconsistent" = "不一致"; + +/* 事务状态:时间戳不一致错误 */ +"TransactionStatus.Inconsistent.WrongTimestamp" = "消息和Tx有不同的时间戳。这是可能的,但要检查两次"; + +/* 交易状态:原因标题不一致 */ +"TransactionStatus.Inconsistent.Reason.Title" = "不一致的原因"; + +/* 事务细节:场景标题 */ +"TransactionDetailsScene.Title" = "详细信息"; + +/* 交易明细:金额行 */ +"TransactionDetailsScene.Row.Amount" = "金额"; + +/* 事务详细信息:块id行 */ +"TransactionDetailsScene.Row.Block" = "区块链 区块"; + +/* 交易明细:交易交付状态 */ +"TransactionDetailsScene.Row.Status" = "事务状态"; + +/* 交易明细:确认行 */ +"TransactionDetailsScene.Row.Confirmations" = "确认"; + +/* 交易明细:日期行 */ +"TransactionDetailsScene.Row.Date" = "日期"; + +/* 事务详细信息:"在资源管理器中打开事务"行 */ +"TransactionDetailsScene.Row.Explorer" = "在资源管理器中打开"; + +/* 交易明细:费用行 */ +"TransactionDetailsScene.Row.Fee" = "费用"; + +/* 交易详细信息:发件人行 */ +"TransactionDetailsScene.Row.From" = "来自"; + +/* 交易明细:当时的法定价值 */ +"TransactionDetailsScene.Row.HistoryFiat" = "Txn时的值"; + +/* 交易明细:当时的法定价值 */ +"TransactionDetailsScene.Row.CurrentFiat" = "当前值"; + +/* 事务详细信息:Id行 */ +"TransactionDetailsScene.Row.Id" = "同上"; + +/* 交易明细:收单行 */ +"TransactionDetailsScene.Row.To" = "至"; + +/* 导出交易:"共享交易摘要"按钮 */ +"TransactionDetailsScene.Share.Summary" = "摘要"; + +/* 导出交易:"共享交易URL"按钮 */ +"TransactionDetailsScene.Share.URL" = "网址"; + +/* "交易详细信息:‘评论’部分" */ +"TransactionDetailsScene.Section.Comment" = "评论"; + +/* "事务详细信息:"操作"部分" */ +"TransactionDetailsScene.Section.Actions" = "行动"; + +/* 事务详细信息:"请求数据"进度消息 */ +"TransactionDetailsScene.RequestingData" = "正在请求数据…"; + +/* 交易详细信息:"您的地址"标志 */ +"TransactionDetailsScene.YourAddress" = "您"; + +/* TransfersProvider:找不到交易错误。%@信息%s(%s)用于事务的ID */ +"TransfersProvider.Error.TransactionNotFoundFormat" = "找不到ID为%@的事务"; + +/* 转账:最低交易金额为0.00001 */ +"TransferScene.Error.MinAmount" = "最低交易金额为0.00001"; + +/* 转账:转账金额占位符 */ +"TransferScene.Amount.Placeholder" = "发送"; + +/* 传输:找不到地址错误 */ +"TransferScene.Error.AddressNotFound" = "找不到地址"; + +/* 传输:地址验证错误 */ +"TransferScene.Error.InvalidAddress" = "输入有效地址"; + +/* 转账:金额高于用户的总金额通知 */ +"TransferScene.Error.notEnoughMoney" = "你没有那个标志"; + +/* 转账:金额为零,甚至是负面通知 */ +"TransferScene.Error.TooLittleMoney" = "你应该发送更多的标志"; + +/* 转账:发送交易的费用不足 */ +"TransferScene.Error.TooLittleFee" = "费用不足"; + +/* 转账:费用比平时高 */ +"TransferScene.Error.FeeIsTooHigh" = "注意:tx费用高于常规费用"; + +/* 转账:警报标题:未找到帐户或未启动帐户。提醒用户他仍然可以汇款,但需要加倍确认地址 */ +"TransferScene.unsafeTransferAlert.title" = "无法验证%@"; + +/* 转账:预警主体:未找到账户或未启动账户。提醒用户他仍然可以汇款,但需要加倍确认地址 */ +"TransferScene.unsafeTransferAlert.body" = "找不到帐户,或未启动帐户。请仔细检查收件人地址并确认交易"; + +/* 转账:预警主体:未发起账户。无法启动聊天,因为区块链不存储帐户的公钥来加密消息 */ +"TransferScene.unsafeChatAlert.body" = "帐户未启动。由于区块链不存储帐户的公钥来加密消息,因此无法启动聊天。"; + +/* 转移:收件人地址占位符 */ +"TransferScene.Receiver.Placeholder" = "收件人的"; + +/* 转让:坚持转让的金额 */ +"TransferScene.Row.Amount" = "金额"; + +/* 转账:加密货币的法定价值 */ +"TransferScene.Row.Fiat" = "价值"; + +/* 转移:记录的用户余额 */ +"TransferScene.Row.Balance" = "余额"; + +/* 转账:最高转账金额:可用账户资金减去转账费用 */ +"TransferScene.Row.MaxToTransfer" = "要传输的最大值"; + +/* 转移:收件人地址 */ +"TransferScene.Row.ReceipientAddress" = "地址"; + +/* 转移:收件人姓名 */ +"TransferScene.Row.ReceipientName" = "名称"; + +/* 传输:发送按钮 */ +"TransferScene.Row.Send" = "发送"; + +/* 转账:交易总金额:转账附加费 */ +"TransferScene.Row.Total" = "总计"; + +/* 转让:转让费 */ +"TransferScene.Row.TransactionFee" = "费用"; + +/* 转让:在聊天中转让的评论 */ +"TransferScene.Row.Comments" = "评论"; + +/* 转让:转让增加费 */ +"TransferScene.Row.IncreaseFee" = "增加费用"; + +/* 转移:"转移信息"部分 */ +"TransferScene.Section.TransferInfo" = "传输信息"; + +/* 转账:"您的钱包"部分 */ +"TransferScene.Section.YourWallet" = "您的钱包"; + +/* 传输:"收件人信息"部分 */ +"TransferScene.Section.Recipient" = "收件人"; + +/* 转移:确认转移警报:发送令牌按钮 */ +"TransferScene.Send" = "发送"; + +/* 传输:确认传输警报:"无法撤消"消息 */ +"TransferScene.CantUndo" = "您将无法撤消此操作"; + +/* Tranfser:确认使用可用于转移代币的最大金额作为转移金额 */ +"TransferScene.UseMaxToTransfer" = "使用所有可用代币作为转账金额?"; + +/* Tranfser:灰尘错误 */ +"TransferScene.Dust.Error" = "灰尘数量--发送更多代币"; + +/*传输:确认将%1$@令牌传输到%2$@消息。注意两个变量:在运行时%1$@将是金额(带ADM后缀),%2$@将是收件人地址。您可以使用这个所谓的"仓位代币"在金额之前使用地址 */ +"TransferScene.SendConfirmFormat" = "将%1$@发送到%2$@?"; + +/* 传输:正在处理消息 */ +"TransferScene.SendingFundsProgress" = "正在发送令牌…"; + +/* 传输:令牌传输成功消息 */ +"TransferScene.TransferSuccessMessage" = "完成!"; + +/* 钱包服务:共享错误,用户没有足够的钱 */ +"WalletServices.SharedErrors.notEnoughMoney" = "代币不足"; + +/* 钱包服务:共享错误,用户尚未启动特定的钱包 */ +"WalletServices.SharedErrors.WalletNotInitiated" = "收款人的钱包尚未启动"; + +/* 钱包服务:共享错误,金额格式无效。%@金额 */ +"WalletServices.SharedErrors.InvalidAmountFormat" = "要发送的金额无效:%@"; + +/* 钱包服务:共享错误,找不到交易 */ +"WalletServices.SharedErrors.TransactionNotFound" = "未找到交易"; + +/* 钱包服务:共享错误,BTC Taproot不工作 */ +"WalletServices.SharedErrors.BtcTaproot" = "ADAMANT不支持Taproot比特币地址"; + +/* 钱包服务:等待其他交易获得批准 */ +"WalletServices.SharedErrors.walletFrezzed" = "等待其他交易获得批准"; + +/* 钱包服务:交易不可用 */ +"WalletServices.SharedErrors.transactionUnavailable" = "交易不可用"; + +/* 钱包服务:无法验证交易 */ +"WalletServices.SharedErrors.consistentTransaction" = "无法验证交易"; + +/* 欢迎:跳过按钮 */ +"WelcomeScene.Skip" = "跳过"; + +/* 欢迎:幻灯片1说明 */ +"WelcomeScene.Description.Slide1" = "欢迎来到ADAMANT,真正的**区块链**信使。"; + +/* 欢迎:幻灯片2说明 */ +"WelcomeScene.Description.Slide2" = "ADAMANT是您的消息以及聊天加密货币传输工具的**匿名性**和**安全性**。\n\n[为什么其他消息不安全?](https://medium.com/adamant-im/adamant-security-features-e7cc836ff52c)"; + +/* 欢迎:幻灯片3说明 */ +"WelcomeScene.Description.Slide3" = "ADAMANT基础设施不属于任何人,是**去中心化的**。\n\n它由ADM代币支付的消息维护。新帐户可能会收到免费代币用于测试。"; + +/* 欢迎:幻灯片4说明 */ +"WelcomeScene.Description.Slide4" = "无需任何要求即可单击**创建帐户**(无需电子邮件/电话/任何内容)并邀请您的朋友。\n\n为了真正的安全起见,请亲自**共享您的ADAMANT地址。"; + +/* 欢迎:幻灯片5说明 */ +"WelcomeScene.Description.Slide5" = "项目的源代码[完全开放](https://github.com/Adamant-im/).该应用程序正在开发中,我们不断添加新功能。\\n\n如果您是开发人员,请加入我们的团队。"; + +/* 欢迎场景。描述开始按钮 */ +"WelcomeScene.Description.BeginButton" = "启动安全消息"; + +/* 欢迎:下一屏幕按钮 */ +"WelcomeScene.Description.ContinueButton" = "继续"; + +/* 欢迎:跳过按钮 */ +"WelcomeScene.Description.SkipButton" = "跳过"; + +/* Welcome: Description accept */ +"WelcomeScene.Description.Accept" = "我接受"; + +/* 欧拉 */ +"EULA.Title" = "服务条款"; +"EULA.Accept" = "接受"; +"EULA.Decline" = "拒绝"; +"EULA.Text" = "ADAMANT Messenger基于去中心化的区块链技术,因此:\n\n✓ ADAMANT Messenger不容忍令人反感的内容或辱骂用户\n✓ ADAMANT Messenger最初专注于通信的安全性和用户的隐私。\n✓ ADAMANT Messenger始终显示完全开源的代码,许可证为GPL-3.0。源代码可在GitHub:GitHub.com/stend-im上获得。\n✓ ADAMANT Messenger按\"原样\"提供,不提供任何担保。\n✓ 开发人员只是ADAMANT Messenger的贡献者和用户。\n✓ 开发人员不控制用户的任何操作。\n✓ 开发人员在ADAMANT Messenger中没有权限。\n✓ 开发人员不可能禁用或阻止ADAMANT Messenger中的任何帐户。\n✓ 开发人员不可能获得加密密钥或读取任何ADAMANT Messenger用户的通信或其他信息。\n✓ 如果丢失,开发人员不可能恢复对任何用户帐户的访问。用户有责任保护自己的帐户的安全。\n✓ 开发人员不对用户内容、消息、媒体以及使用ADAMANT Messenger的目标和意图负责。\n✓ 开发者不存储用户之间传输的任何信息(消息、多媒体),也不对其在区块链上/中的存储负责。\n✓ 开发者不可能访问,也不对连接到ADAMANT Messenger或通过ADAMANT信使发送的任何资产(包括但不限于:加密货币)负责。\n✓ ADAMANT Messenger利用元数据作为账户之间通信的事实,在其区块链中公开提供。\n✓ 开发者不与任何第三方或外部服务合作提供任何使用数据。\n✓ ADAMANT信使基础设施(区块链节点)属于其用户,由用户运行。\n✓ 开发人员不可能停用、停止或暂停ADAMANT Messenger。开发人员对ADAMANT Messenger的运行不提供任何保证。\n✓ 开发人员不承担与ADAMANT Messenger相关的可能风险、成本和故障。\n✓ ADAMANT Messenger的用户从此对其使用承担全部责任,包括但不限于:区块链和Messenger内应用的其他技术的合法性,使用匿名消息服务,以及其他管辖法律。\\n\n通过使用ADAMANT Messenger,您从此接受这些服务条款。"; + +/* 回复:未知短信错误 */ +"Reply.ShortUnknownMessageError" = "未知消息"; + +/* 回复:长未知消息错误 */ +"Reply.LongUnknownMessageError" = "我们没有找到此邮件"; + +/* 回复:失败的消息回复错误 */ +"Reply.failedMessageError" = "无法回复失败的消息"; + +/* 挂起的消息回复错误 */ +"Reply.pendingMessageError" = "您无法回复挂起的消息。请等待确认(估计1-2秒)"; + +/* 包括合作伙伴名称 */ +"PartnerQR.includePartnerName" = "包括联系人姓名"; + +/* 包括合作伙伴url */ +"PartnerQR.includePartnerURL" = "包括Web应用程序链接"; diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.stringsdict b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.stringsdict new file mode 100644 index 000000000..e51f70eb7 --- /dev/null +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.stringsdict @@ -0,0 +1,38 @@ + + + + + Doge.TransactionDetails.SendersFormat + + NSStringLocalizedFormatKey + %#@senders@ + senders + + NSStringFormatValueTypeKey + d + NSStringFormatSpecTypeKey + NSStringPluralRuleType + other + %d senders + one + %d sender + + + Doge.TransactionDetails.RecipientsFormat + + NSStringLocalizedFormatKey + %#@recipients@ + recipients + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + other + %d recipients + one + %d recipient + + + + diff --git a/NotificationsShared/Localization/zh.lproj/Localizable.strings b/NotificationsShared/Localization/zh.lproj/Localizable.strings new file mode 100644 index 000000000..ab217d9d6 --- /dev/null +++ b/NotificationsShared/Localization/zh.lproj/Localizable.strings @@ -0,0 +1,26 @@ +/* Notifications: Something went wrong while registering remote notifications. %@ for description */ +"NotificationsService.Error.RegistrationRemotesFormat" = "在ANS中注册失败。请稍后再试。原因%@"; + +/* Notifications: New message notification title */ +"NotificationsService.NewMessage.Title" = "新消息"; + +/* Notifications: New single message notification body */ +"NotificationsService.NewMessage.BodySingle" = "您有一条新消息"; + +/* Notifications: New transfer transaction title */ +"NotificationsService.NewTransfer.Title" = "新转移"; + +/* Notifications: New single transfer transaction body */ +"NotificationsService.NewTransfer.BodySingle" = "您有新的转账"; + +/* Notifications: User has disabled notifications. Head him into settings */ +"NotificationsService.NotificationsDisabled" = "通知已禁用。您可以在“设置”中启用通知"; + +/* Notifications: Not stayed logged in */ +"NotificationsService.NotStayedLoggedIn" = "不保持登录状态就无法打开通知"; + +/* Notifications: Reacted */ +"NotificationsService.Reacted" = "有反应"; + +/* Notifications: Modified Reaction */ +"NotificationsService.ModifiedReaction" = "修改的反应"; diff --git a/NotificationsShared/Localization/zh.lproj/Localizable.stringsdict b/NotificationsShared/Localization/zh.lproj/Localizable.stringsdict new file mode 100644 index 000000000..058b16be1 --- /dev/null +++ b/NotificationsShared/Localization/zh.lproj/Localizable.stringsdict @@ -0,0 +1,38 @@ + + + + + NotificationsService.NewTransfer.BodyFormat + + NSStringLocalizedFormatKey + 您有 %#@transfers@ + transfers + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + %d new transaction + other + %d new transactions + + + NotificationsService.NewMessage.BodyFormat + + NSStringLocalizedFormatKey + 您有 %#@messages@ + messages + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + %d new message + other + %d new messages + + + + From e32a66f6bf9e6e5cd351aa8b4bc501503c913f68 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Wed, 10 Jan 2024 17:23:48 +0200 Subject: [PATCH 07/27] [trello.com/c/AT07OnsL] feat: add language switcher --- Adamant.xcodeproj/project.pbxproj | 12 +++ Adamant/App/DI/AppAssembly.swift | 5 + Adamant/Models/Language.swift | 29 ++++++ Adamant/Modules/Account/AccountFactory.swift | 23 +++-- .../Account/AccountViewController.swift | 94 ++++++++++++++---- .../LanguageStorageProtocol.swift | 14 +++ Adamant/Services/LanguageService.swift | 22 ++++ .../Localization/de.lproj/Localizable.strings | 6 ++ .../Localization/en.lproj/Localizable.strings | 6 ++ .../Localization/ru.lproj/Localizable.strings | 6 ++ .../Localization/zh.lproj/Localizable.strings | 6 ++ .../Row/row_language.imageset/Contents.json | 23 +++++ .../Row/row_language.imageset/lang_switch.png | Bin 0 -> 402 bytes .../row_language.imageset/lang_switch@2x.png | Bin 0 -> 774 bytes .../row_language.imageset/lang_switch@3x.png | Bin 0 -> 1128 bytes .../Sources/CommonKit/Core/SecuredStore.swift | 4 + .../Localization/AdamantLocalized.swift | 10 +- 17 files changed, 227 insertions(+), 33 deletions(-) create mode 100644 Adamant/Models/Language.swift create mode 100644 Adamant/ServiceProtocols/LanguageStorageProtocol.swift create mode 100644 Adamant/Services/LanguageService.swift create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/Contents.json create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/lang_switch.png create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/lang_switch@2x.png create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/lang_switch@3x.png diff --git a/Adamant.xcodeproj/project.pbxproj b/Adamant.xcodeproj/project.pbxproj index c118ac053..8dfeaf3ed 100644 --- a/Adamant.xcodeproj/project.pbxproj +++ b/Adamant.xcodeproj/project.pbxproj @@ -33,6 +33,9 @@ 3AA50DF12AEBE66A00C58FC8 /* PartnerQRViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA50DF02AEBE66A00C58FC8 /* PartnerQRViewModel.swift */; }; 3AA50DF32AEBE67C00C58FC8 /* PartnerQRFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA50DF22AEBE67C00C58FC8 /* PartnerQRFactory.swift */; }; 3AC76E3D2AB09118008042C4 /* ElegantEmojiPicker in Frameworks */ = {isa = PBXBuildFile; productRef = 3AC76E3C2AB09118008042C4 /* ElegantEmojiPicker */; }; + 3AF08D5F2B4EB3A200EB82B1 /* LanguageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF08D5E2B4EB3A200EB82B1 /* LanguageService.swift */; }; + 3AF08D612B4EB3C400EB82B1 /* LanguageStorageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF08D602B4EB3C400EB82B1 /* LanguageStorageProtocol.swift */; }; + 3AF08D632B4EEAFF00EB82B1 /* Language.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF08D622B4EEAFF00EB82B1 /* Language.swift */; }; 3C06931576393125C61FB8F6 /* Pods_Adamant.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33975C0D891698AA7E74EBCC /* Pods_Adamant.framework */; }; 41047B70294B5EE10039E956 /* VisibleWalletsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41047B6F294B5EE10039E956 /* VisibleWalletsViewController.swift */; }; 41047B72294B5F210039E956 /* VisibleWalletsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41047B71294B5F210039E956 /* VisibleWalletsTableViewCell.swift */; }; @@ -671,6 +674,9 @@ 3AF08D5B2B4E7FFC00EB82B1 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/InfoPlist.strings; sourceTree = ""; }; 3AF08D5C2B4E7FFC00EB82B1 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = zh; path = zh.lproj/Localizable.stringsdict; sourceTree = ""; }; 3AF08D5D2B4E7FFC00EB82B1 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/Localizable.strings; sourceTree = ""; }; + 3AF08D5E2B4EB3A200EB82B1 /* LanguageService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageService.swift; sourceTree = ""; }; + 3AF08D602B4EB3C400EB82B1 /* LanguageStorageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageStorageProtocol.swift; sourceTree = ""; }; + 3AF08D622B4EEAFF00EB82B1 /* Language.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Language.swift; sourceTree = ""; }; 41047B6F294B5EE10039E956 /* VisibleWalletsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleWalletsViewController.swift; sourceTree = ""; }; 41047B71294B5F210039E956 /* VisibleWalletsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleWalletsTableViewCell.swift; sourceTree = ""; }; 41047B73294C61D10039E956 /* VisibleWalletsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleWalletsService.swift; sourceTree = ""; }; @@ -1927,6 +1933,7 @@ 93ADC17C2B083C3B00F2DF77 /* NodesAdditionalParamsStorageProtocol.swift */, 3A2F55FB2AC6F885000A3F26 /* CoinStorage.swift */, 3A96E37B2AED27F8001F5A52 /* PartnerQRService.swift */, + 3AF08D602B4EB3C400EB82B1 /* LanguageStorageProtocol.swift */, ); path = ServiceProtocols; sourceTree = ""; @@ -1963,6 +1970,7 @@ 93ADC17E2B083D7A00F2DF77 /* NodesAdditionalParamsStorage.swift */, 3A2F55FD2AC6F90E000A3F26 /* AdamantCoinStorageService.swift */, 3A96E3792AED27D7001F5A52 /* AdamantPartnerQRService.swift */, + 3AF08D5E2B4EB3A200EB82B1 /* LanguageService.swift */, ); path = Services; sourceTree = ""; @@ -2002,6 +2010,7 @@ 93E8EDCE2AF1CD9F003E163C /* NodeStatusInfo.swift */, 93B28EBF2B076667007F268B /* APIResponseModel.swift */, 936658902B0AB9DC00BDB2D3 /* NodeWithGroup.swift */, + 3AF08D622B4EEAFF00EB82B1 /* Language.swift */, ); path = Models; sourceTree = ""; @@ -3143,6 +3152,7 @@ E9E7CDB32002B9FB00DFC4DB /* LoginFactory.swift in Sources */, E941CCDE20E7B70200C96220 /* WalletCollectionViewCell.swift in Sources */, 4186B33A294200F4006594A3 /* DashWalletService+DynamicConstants.swift in Sources */, + 3AF08D5F2B4EB3A200EB82B1 /* LanguageService.swift in Sources */, E9AA8BFA212C166600F9249F /* EthWalletService+Send.swift in Sources */, 411743042A39B257008CD98A /* ContributeViewModel.swift in Sources */, 93E5D4DB293000BE00439298 /* UnregisteredTransaction.swift in Sources */, @@ -3284,6 +3294,7 @@ 93ADE0722ACA66AF008ED641 /* VibrationSelectionView.swift in Sources */, 648C696F22915A12006645F5 /* DashTransaction.swift in Sources */, 3A41939A2A5D554A006A6B22 /* Reaction.swift in Sources */, + 3AF08D632B4EEAFF00EB82B1 /* Language.swift in Sources */, 93CCAE752B06CC3600EA5B94 /* LskNodeApiService.swift in Sources */, 6416B1A321AD7EA1006089AC /* LskTransactionDetailsViewController.swift in Sources */, 6449BA6F235CA0930033B936 /* ERC20WalletService+Send.swift in Sources */, @@ -3364,6 +3375,7 @@ 93ADC17B2B08283500F2DF77 /* ForceQueryItemsEncoding.swift in Sources */, 41BCB310295C6082004B12AB /* VisibleWalletsResetTableViewCell.swift in Sources */, 93CCAE7B2B06D9B500EA5B94 /* DogeBlocksDTO.swift in Sources */, + 3AF08D612B4EB3C400EB82B1 /* LanguageStorageProtocol.swift in Sources */, E9E7CDB12002B97B00DFC4DB /* AccountFactory.swift in Sources */, E9AA8BF82129F13000F9249F /* ComplexTransferViewController.swift in Sources */, E9A174B52057EDCE003667CD /* AdamantTransfersProvider+backgroundFetch.swift in Sources */, diff --git a/Adamant/App/DI/AppAssembly.swift b/Adamant/App/DI/AppAssembly.swift index e47b09bac..b3ae8568c 100644 --- a/Adamant/App/DI/AppAssembly.swift +++ b/Adamant/App/DI/AppAssembly.swift @@ -231,6 +231,11 @@ struct AppAssembly: Assembly { service.accountService = r.resolve(AccountService.self) } + // MARK: LanguageStorageProtocol + container.register(LanguageStorageProtocol.self) { r in + LanguageStorageService() + }.inObjectScope(.container) + // MARK: - Data Providers // MARK: CoreData Stack container.register(CoreDataStack.self) { _ in diff --git a/Adamant/Models/Language.swift b/Adamant/Models/Language.swift new file mode 100644 index 000000000..ad327160b --- /dev/null +++ b/Adamant/Models/Language.swift @@ -0,0 +1,29 @@ +// +// Language.swift +// Adamant +// +// Created by Stanislav Jelezoglo on 10.01.2024. +// Copyright © 2024 Adamant. All rights reserved. +// + +import Foundation + +enum Language: String { + case ru + case en + case de + case zh + case auto = "" + + var name: String { + switch self { + case .ru: return "Русский" + case .en: return "English" + case .de: return "Deutschland" + case .zh: return "中文" + case .auto: return .localized("Language.Auto", comment: "Account tab: Language auto") + } + } + + static let all: [Language] = [.auto, .en, .ru, .de, .zh] +} diff --git a/Adamant/Modules/Account/AccountFactory.swift b/Adamant/Modules/Account/AccountFactory.swift index dbc7a18a1..009fed0b2 100644 --- a/Adamant/Modules/Account/AccountFactory.swift +++ b/Adamant/Modules/Account/AccountFactory.swift @@ -13,16 +13,17 @@ struct AccountFactory { let assembler: Assembler func makeViewController(screensFactory: ScreensFactory) -> UIViewController { - let c = AccountViewController() - c.accountService = assembler.resolve(AccountService.self) - c.dialogService = assembler.resolve(DialogService.self) - c.notificationsService = assembler.resolve(NotificationsService.self) - c.transfersProvider = assembler.resolve(TransfersProvider.self) - c.localAuth = assembler.resolve(LocalAuthentication.self) - c.avatarService = assembler.resolve(AvatarService.self) - c.currencyInfoService = assembler.resolve(CurrencyInfoService.self) - c.visibleWalletsService = assembler.resolve(VisibleWalletsService.self) - c.screensFactory = screensFactory - return c + AccountViewController( + visibleWalletsService: assembler.resolve(VisibleWalletsService.self)!, + accountService: assembler.resolve(AccountService.self)!, + dialogService: assembler.resolve(DialogService.self)!, + screensFactory: screensFactory, + notificationsService: assembler.resolve(NotificationsService.self)!, + transfersProvider: assembler.resolve(TransfersProvider.self)!, + localAuth: assembler.resolve(LocalAuthentication.self)!, + avatarService: assembler.resolve(AvatarService.self)!, + currencyInfoService: assembler.resolve(CurrencyInfoService.self)!, + languageService: assembler.resolve(LanguageStorageProtocol.self)! + ) } } diff --git a/Adamant/Modules/Account/AccountViewController.swift b/Adamant/Modules/Account/AccountViewController.swift index 30f23240d..02a266893 100644 --- a/Adamant/Modules/Account/AccountViewController.swift +++ b/Adamant/Modules/Account/AccountViewController.swift @@ -60,7 +60,7 @@ final class AccountViewController: FormViewController { enum Rows { case balance, sendTokens // Wallet - case security, nodes, coinsNodes, theme, currency, about, visibleWallets, contribute, vibration // Application + case security, nodes, coinsNodes, theme, currency, language, about, visibleWallets, contribute, vibration // Application case voteForDelegates, generateQr, generatePk, logout // Actions case stayIn, biometry, notifications // Security @@ -84,6 +84,7 @@ final class AccountViewController: FormViewController { case .contribute: return "contribute" case .vibration: return "vibration" case .coinsNodes: return "coinsNodes" + case .language: return "language" } } @@ -107,6 +108,7 @@ final class AccountViewController: FormViewController { case .contribute: return .localized("AccountTab.Row.Contribute", comment: "Account tab: 'Contribute' row") case .vibration: return "Vibrations" case .coinsNodes: return .adamant.coinsNodesList.title + case .language: return .localized("AccountTab.Row.Language", comment: "Account tab: 'Language' row") } } @@ -131,6 +133,7 @@ final class AccountViewController: FormViewController { case .visibleWallets: image = .asset(named: "row_balance") case .contribute: image = .asset(named: "row_contribute") case .vibration: image = .asset(named: "row_contribute") + case .language: image = .asset(named: "row_language") } return image? @@ -140,17 +143,17 @@ final class AccountViewController: FormViewController { } // MARK: - Dependencies - var visibleWalletsService: VisibleWalletsService! - var accountService: AccountService! - var dialogService: DialogService! - var screensFactory: ScreensFactory! - var notificationsService: NotificationsService! - var transfersProvider: TransfersProvider! - var localAuth: LocalAuthentication! - var avatarService: AvatarService! - - var currencyInfoService: CurrencyInfoService! + let visibleWalletsService: VisibleWalletsService + let accountService: AccountService + let dialogService: DialogService + let screensFactory: ScreensFactory + let notificationsService: NotificationsService + let transfersProvider: TransfersProvider + let localAuth: LocalAuthentication + let avatarService: AvatarService + let currencyInfoService: CurrencyInfoService + let languageService: LanguageStorageProtocol // MARK: - Properties @@ -190,6 +193,38 @@ final class AccountViewController: FormViewController { return refreshControl }() + // MARK: - Init + + init( + visibleWalletsService: VisibleWalletsService, + accountService: AccountService, + dialogService: DialogService, + screensFactory: ScreensFactory, + notificationsService: NotificationsService, + transfersProvider: TransfersProvider, + localAuth: LocalAuthentication, + avatarService: AvatarService, + currencyInfoService: CurrencyInfoService, + languageService: LanguageStorageProtocol + ) { + self.visibleWalletsService = visibleWalletsService + self.accountService = accountService + self.dialogService = dialogService + self.screensFactory = screensFactory + self.notificationsService = notificationsService + self.transfersProvider = transfersProvider + self.localAuth = localAuth + self.avatarService = avatarService + self.currencyInfoService = currencyInfoService + self.languageService = languageService + + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + // MARK: - Lifecycle override func viewDidLoad() { @@ -375,14 +410,33 @@ final class AccountViewController: FormViewController { } }.cellUpdate { (cell, _) in cell.accessoryType = .disclosureIndicator - }.onChange { row in - if let value = row.value { - self.currencyInfoService.currentCurrency = value - } + }.onChange { [weak self] row in + guard let value = row.value else { return } + self?.currencyInfoService.currentCurrency = value } appSection.append(currencyRow) + // Language select + let languageRow = ActionSheetRow { + $0.title = Rows.language.localized + $0.tag = Rows.language.tag + $0.cell.imageView?.image = Rows.language.image + $0.options = Language.all + $0.value = languageService.getLanguage() + + $0.displayValueFor = { language in + return language?.name + } + }.cellUpdate { (cell, _) in + cell.accessoryType = .disclosureIndicator + }.onChange { [weak self] row in + guard let value = row.value else { return } + self?.languageService.setLanguage(value) + } + + appSection.append(languageRow) + // Contribute let contributeRow = LabelRow { $0.title = Rows.contribute.localized @@ -596,12 +650,10 @@ final class AccountViewController: FormViewController { $0.title = localAuth.biometryType.localized $0.value = accountService.useBiometry - if let auth = localAuth { - switch auth.biometryType { - case .none: $0.cell.imageView?.image = nil - case .touchID: $0.cell.imageView?.image = .asset(named: "row_touchid.png") - case .faceID: $0.cell.imageView?.image = .asset(named: "row_faceid.png") - } + switch localAuth.biometryType { + case .none: $0.cell.imageView?.image = nil + case .touchID: $0.cell.imageView?.image = .asset(named: "row_touchid.png") + case .faceID: $0.cell.imageView?.image = .asset(named: "row_faceid.png") } $0.hidden = Condition.function([], { [weak self] _ -> Bool in guard let showBiometry = self?.showBiometryOptions else { diff --git a/Adamant/ServiceProtocols/LanguageStorageProtocol.swift b/Adamant/ServiceProtocols/LanguageStorageProtocol.swift new file mode 100644 index 000000000..c922c7e98 --- /dev/null +++ b/Adamant/ServiceProtocols/LanguageStorageProtocol.swift @@ -0,0 +1,14 @@ +// +// LanguageStorageProtocol.swift +// Adamant +// +// Created by Stanislav Jelezoglo on 10.01.2024. +// Copyright © 2024 Adamant. All rights reserved. +// + +import Foundation + +protocol LanguageStorageProtocol { + func getLanguage() -> Language + func setLanguage(_ language: Language) +} diff --git a/Adamant/Services/LanguageService.swift b/Adamant/Services/LanguageService.swift new file mode 100644 index 000000000..572f8e24a --- /dev/null +++ b/Adamant/Services/LanguageService.swift @@ -0,0 +1,22 @@ +// +// LanguageService.swift +// Adamant +// +// Created by Stanislav Jelezoglo on 10.01.2024. +// Copyright © 2024 Adamant. All rights reserved. +// + +import Foundation +import CommonKit + +final class LanguageStorageService: LanguageStorageProtocol { + func getLanguage() -> Language { + let raw = UserDefaults.standard.string(forKey: StoreKey.language.language) ?? "" + let language: Language = .init(rawValue: raw) ?? .auto + return language + } + + func setLanguage(_ language: Language) { + UserDefaults.standard.set(language.rawValue, forKey: StoreKey.language.language) + } +} diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings index 9a63eeec0..0aafd7a0b 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings @@ -100,6 +100,12 @@ /* Account tab: 'Currency' row */ "AccountTab.Row.Currency" = "Währung"; +/* Account tab: 'Language' row */ +"AccountTab.Row.Language" = "Sprache"; + +/* Account tab: Language auto */ +"Language.Auto" = "Automatisch"; + /* System accounts: ADAMANT Tokens */ "Accounts.AdamantTokens" = "Willkommen in ADAMANT"; diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings index 6acb2bd3a..f48c46bb4 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings @@ -100,6 +100,12 @@ /* Account tab: 'Currency' row */ "AccountTab.Row.Currency" = "Currency"; +/* Account tab: 'Language' row */ +"AccountTab.Row.Language" = "Language"; + +/* Account tab: Language auto */ +"Language.Auto" = "Automatically"; + /* System accounts: ADAMANT Tokens */ "Accounts.AdamantTokens" = "Welcome to ADAMANT"; diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings index d0123f5e7..8f9e9cbb5 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings @@ -220,6 +220,12 @@ /* Account tab: 'Vote for delegates' button */ "AccountTab.Row.VoteForDelegates" = "Голосовать за делегатов"; +/* Account tab: 'Language' row */ +"AccountTab.Row.Language" = "Язык"; + +/* Account tab: Language auto */ +"Language.Auto" = "Автоматически"; + /* Account tab: Actions section title */ "AccountTab.Section.Actions" = "Действия"; diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index 8e02d64e4..ebffe446e 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -100,6 +100,12 @@ /* 帐户选项卡:"货币"行 */ "AccountTab.Row.Currency" = "货币"; +/* Account tab: 'Language' row */ +"AccountTab.Row.Language" = "语言"; + +/* Account tab: Language auto */ +"Language.Auto" = "自动"; + /* 系统帐户:ADAMANT令牌 */ "Accounts.AdamantTokens" = "欢迎使用ADAMANT"; diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/Contents.json b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/Contents.json new file mode 100644 index 000000000..912b283c8 --- /dev/null +++ b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "lang_switch.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "lang_switch@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "lang_switch@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/lang_switch.png b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/lang_switch.png new file mode 100644 index 0000000000000000000000000000000000000000..0d983e5f656f4278ec65c3bf0a667edebcb53979 GIT binary patch literal 402 zcmV;D0d4+?P)7OWFeg-?NFm{1ApQu%u0X5-m3Ku`^PiDGz+=m8 zpw!_3#K)lFj-KP5GBJ=2>Y=U$8Qe!oHpK-%2AzcFsvSVw2n}nZvMDYg19d4Zw>9D_ wr3i&7$%&tkp`cVDN@_MGWHVXy7eIgk01^XaYA#)o&Hw-a07*qoM6N<$g2{@To&W#< literal 0 HcmV?d00001 diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/lang_switch@2x.png b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/lang_switch@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2f8b5a51465c0a24fcac573c9aae20f04bd52929 GIT binary patch literal 774 zcmV+h1Nr=kP)0Fc76(&5F7etyQ2~ z3NIb2ZdqK90orD6gZx0!4>0@zNyaV)x*HkX&0Du9-LeQBJEWQI_y^KE;1N9tvLuS6 ztOFh>Qxx@lyn8xPO8vKp@SU(CJUYS(b4JS2dT8Geeu@b$r<57#BA)FXwbl$?8!SJISI~9M0n&abDA0>ZkJ2R$+oxU+}DD>^D3eXi0jm$ z%xE2~Qz~k^E^`zUJ;f7X2q|zO+$rYSD;e`1_e=#Um;L}75SnaNM%Rh88Kmt58ayu` zs>dzsCetl82QJ~=$WcK&z&wd~XlNZCiX}IyN7=Jq@ZR040aeqhnjAafC>Nv4x;YWF zAW5fak3cpNgl9fq?wXRF3&NUY+BKqaK>`|WdiW+9Lfmgeag!Cq>`sZs*iAVTayJ5G zf{k~bOnNuv4l$Z;NwC4LiDsyhHYEvmkt-j!TF-(=Ticaf8iqD8y2jG_+|o&KkF^ca z1=^|dv;7!~3T$Ds^sRoR=vhwK`OiLi&wBrm_D_HT08wSwFljU3fB*mh07*qoM6N<$ Ef+4+Ml>h($ literal 0 HcmV?d00001 diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/lang_switch@3x.png b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Row/row_language.imageset/lang_switch@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f13056ce8c5205aec4fd401b88774ac8b86d8371 GIT binary patch literal 1128 zcmV-u1eg1XP)j{0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$3Q0skRCwCtTfI&jK@c8Wt`GWP3ChG( zDr73BA?}h$#4T7d4{+uIFb`mOfJAXm&vnNf`_KS%Qb!@coUyVz%FV%3zFLJ zqa{ch3*Is@P*Lz(0^H9Sc(By=a4vvzJ1_-)pWJsc22KTVO77p7GW&Zn;B&Bxekq)@ zHq8fg3--~-kqDeI` z*YLNP6Y+6rcqwaK*%U2m(E1`I9oTLLz=Nb~7yfP5^q!*mpTwM9m^B*%suO4EaYVug{n&1y9I;sX4bD9-+Ua+JUrvnH2N9Xv<(6?VxTx$hi zffb_?Ci*q9wz3FKM-kQD2I~t{BhqI#F8FhpZ2@Ux_)0S=sp7bc))eK4_jqx_YY{7) zF?o4EjWqu}107tqiMjJCcH$nh)whW(?>XyJxatUzS zK-poy{XBvX6F{BS String { - NSLocalizedString(key, bundle: .module, comment: comment) + guard let language = UserDefaults.standard.string(forKey: StoreKey.language.language), + !language.isEmpty, + let path = Bundle.module.path(forResource: language, ofType: "lproj") + else { + return NSLocalizedString(key, bundle: .module, comment: comment) + } + + let bundle: Bundle = Bundle(path: path) ?? .module + return NSLocalizedString(key, bundle: bundle, comment: comment) } } From eef5594a0f23160b629e4cf662c9a9e29a12e175 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Thu, 11 Jan 2024 16:30:16 +0200 Subject: [PATCH 08/27] [trello.com/c/AT07OnsL] feat: apply the language change immediately --- Adamant/App/AppDelegate.swift | 16 +- Adamant/Helpers/MyLittlePinpad+adamant.swift | 10 +- Adamant/Helpers/Node+UI.swift | 60 ++++--- Adamant/Helpers/String+localized.swift | 150 +++++++++++++----- Adamant/Models/Language.swift | 16 ++ .../Account/AccountViewController.swift | 119 +++++++++----- Adamant/Modules/Chat/ChatLocalization.swift | 102 ++++++++---- .../ChatsList/ChatListViewController.swift | 48 ++++-- .../ChatsList/NewChatViewController.swift | 32 ++-- .../SearchResultsViewController.swift | 16 +- .../ViewModel/CoinsNodesListStrings.swift | 36 +++-- .../DelegateDetailsViewController.swift | 4 +- .../DelegatesListViewController.swift | 23 +-- .../Modules/Login/LoginViewController.swift | 45 ++++-- .../NodeEditorViewController.swift | 12 +- .../NodesEditor/NodesListViewController.swift | 26 ++- Adamant/Modules/Onboard/OnboardOverlay.swift | 8 +- .../Onboard/OnboardViewController.swift | 16 +- .../Settings/AboutViewController.swift | 4 +- .../Settings/PKGeneratorViewController.swift | 16 +- .../Settings/QRGeneratorViewController.swift | 26 +-- .../Settings/SecurityViewController.swift | 20 ++- .../VisibleWalletsViewController.swift | 12 +- .../AdmTransactionDetailsViewController.swift | 6 +- .../Adamant/AdmTransferViewController.swift | 6 +- .../Wallets/Adamant/AdmWalletFactory.swift | 3 +- .../Adamant/AdmWalletViewController.swift | 32 ++-- .../Wallets/Bitcoin/BtcWalletFactory.swift | 3 +- .../Wallets/Bitcoin/BtcWalletService.swift | 4 +- .../Bitcoin/BtcWalletViewController.swift | 19 +-- .../Wallets/Dash/DashWalletFactory.swift | 3 +- .../Dash/DashWalletViewController.swift | 20 +-- .../Wallets/Doge/DogeWalletFactory.swift | 3 +- .../Doge/DogeWalletViewController.swift | 20 +-- .../Wallets/ERC20/ERC20WalletFactory.swift | 3 +- .../ERC20/ERC20WalletViewController.swift | 12 +- .../Wallets/Ethereum/EthWalletFactory.swift | 3 +- .../Ethereum/EthWalletViewController.swift | 12 +- .../Wallets/Lisk/LskWalletFactory.swift | 3 +- .../Lisk/LskWalletViewController.swift | 20 +-- ...TransactionDetailsViewControllerBase.swift | 20 ++- .../TransactionsListViewControllerBase.swift | 23 ++- .../Wallets/TransferViewControllerBase.swift | 61 ++++--- .../Wallets/WalletViewControllerBase.swift | 29 +++- Adamant/ServiceProtocols/AccountService.swift | 15 +- Adamant/ServiceProtocols/DialogService.swift | 16 +- Adamant/Services/LanguageService.swift | 2 + .../Localization/de.lproj/Localizable.strings | 12 ++ .../Localization/en.lproj/Localizable.strings | 12 ++ .../Localization/ru.lproj/Localizable.strings | 12 ++ .../Localization/zh.lproj/Localizable.strings | 32 ++-- .../Sources/CommonKit/Core/SecuredStore.swift | 1 + .../CommonKit/Helpers/Date+adamant.swift | 50 ++++-- .../AdamantLocalized+Notifications.swift | 30 ++-- 54 files changed, 891 insertions(+), 413 deletions(-) diff --git a/Adamant/App/AppDelegate.swift b/Adamant/App/AppDelegate.swift index 5f47035aa..e17971c03 100644 --- a/Adamant/App/AppDelegate.swift +++ b/Adamant/App/AppDelegate.swift @@ -14,10 +14,18 @@ import CommonKit // MARK: - Constants extension String.adamant { - struct tabItems { - static let account = String.localized("Tabs.Account", comment: "Main tab bar: Account page") - static let chats = String.localized("Tabs.Chats", comment: "Main tab bar: Chats page") - static let settings = String.localized("Tabs.Settings", comment: "Main tab bar: Settings page") + enum tabItems { + static var account: String { + String.localized("Tabs.Account", comment: "Main tab bar: Account page") + } + + static var chats: String { + String.localized("Tabs.Chats", comment: "Main tab bar: Chats page") + } + + static var settings: String { + String.localized("Tabs.Settings", comment: "Main tab bar: Settings page") + } } struct application { diff --git a/Adamant/Helpers/MyLittlePinpad+adamant.swift b/Adamant/Helpers/MyLittlePinpad+adamant.swift index 2523fd0a4..34c06bda6 100644 --- a/Adamant/Helpers/MyLittlePinpad+adamant.swift +++ b/Adamant/Helpers/MyLittlePinpad+adamant.swift @@ -10,9 +10,13 @@ import Foundation import MyLittlePinpad extension String.adamant { - struct pinpad { - static let createPin = String.localized("Pinpad.EnterNewPin", comment: "Pinpad: Ask user to create new pin") - static let reenterPin = String.localized("Pinpad.ReenterPin", comment: "Pinpad: Ask user to repeat new pin") + enum pinpad { + static var createPin: String { + String.localized("Pinpad.EnterNewPin", comment: "Pinpad: Ask user to create new pin") + } + static var reenterPin: String { + String.localized("Pinpad.ReenterPin", comment: "Pinpad: Ask user to repeat new pin") + } } } diff --git a/Adamant/Helpers/Node+UI.swift b/Adamant/Helpers/Node+UI.swift index f51c55c62..3a2fcb55e 100644 --- a/Adamant/Helpers/Node+UI.swift +++ b/Adamant/Helpers/Node+UI.swift @@ -71,35 +71,47 @@ extension Node { private extension Node { enum Strings { - static let ping = String.localized( - "NodesList.NodeCell.Ping", - comment: "NodesList.NodeCell: Node ping" - ) + static var ping: String { + String.localized( + "NodesList.NodeCell.Ping", + comment: "NodesList.NodeCell: Node ping" + ) + } - static let milliseconds = String.localized( - "NodesList.NodeCell.Milliseconds", - comment: "NodesList.NodeCell: Milliseconds" - ) + static var milliseconds: String { + String.localized( + "NodesList.NodeCell.Milliseconds", + comment: "NodesList.NodeCell: Milliseconds" + ) + } - static let synchronizing = String.localized( - "NodesList.NodeCell.Synchronizing", - comment: "NodesList.NodeCell: Node is synchronizing" - ) + static var synchronizing: String { + String.localized( + "NodesList.NodeCell.Synchronizing", + comment: "NodesList.NodeCell: Node is synchronizing" + ) + } - static let offline = String.localized( - "NodesList.NodeCell.Offline", - comment: "NodesList.NodeCell: Node is offline" - ) + static var offline: String { + String.localized( + "NodesList.NodeCell.Offline", + comment: "NodesList.NodeCell: Node is offline" + ) + } - static let version = String.localized( - "NodesList.NodeCell.Version", - comment: "NodesList.NodeCell: Node version" - ) + static var version: String { + String.localized( + "NodesList.NodeCell.Version", + comment: "NodesList.NodeCell: Node version" + ) + } - static let disabled = String.localized( - "NodesList.NodeCell.Disabled", - comment: "NodesList.NodeCell: Node is disabled" - ) + static var disabled: String { + String.localized( + "NodesList.NodeCell.Disabled", + comment: "NodesList.NodeCell: Node is disabled" + ) + } } var versionString: String? { diff --git a/Adamant/Helpers/String+localized.swift b/Adamant/Helpers/String+localized.swift index d3b940264..3afb579dc 100644 --- a/Adamant/Helpers/String+localized.swift +++ b/Adamant/Helpers/String+localized.swift @@ -10,45 +10,81 @@ import Foundation import CommonKit extension String.adamant { - struct shared { - static let productName = String.localized("ADAMANT", comment: "Product name") - - private init() {} + enum shared { + static var productName: String { + String.localized("ADAMANT", comment: "Product name") + } } - struct alert { + enum alert { // MARK: Buttons - static let cancel = String.localized("Shared.Cancel", comment: "Shared alert 'Cancel' button. Used anywhere") - static let ok = String.localized("Shared.Ok", comment: "Shared alert 'Ok' button. Used anywhere") - static let save = String.localized("Shared.Save", comment: "Shared alert 'Save' button. Used anywhere") - static let settings = String.localized("Shared.Settings", comment: "Shared alert 'Settings' button. Used to go to system Settings app, on application settings page. Should be same as Settings application title.") - static let retry = String.localized("Shared.Retry", comment: "Shared alert 'Retry' button. Used anywhere") - static let delete = String.localized("Shared.Delete", comment: "Shared alert 'Delete' button. Used anywhere") + static var cancel: String { + String.localized("Shared.Cancel", comment: "Shared alert 'Cancel' button. Used anywhere") + } + static var ok: String { + String.localized("Shared.Ok", comment: "Shared alert 'Ok' button. Used anywhere") + } + static var save: String { + String.localized("Shared.Save", comment: "Shared alert 'Save' button. Used anywhere") + } + static var settings: String { + String.localized("Shared.Settings", comment: "Shared alert 'Settings' button. Used to go to system Settings app, on application settings page. Should be same as Settings application title.") + } + static var retry: String { + String.localized("Shared.Retry", comment: "Shared alert 'Retry' button. Used anywhere") + } + static var delete: String { + String.localized("Shared.Delete", comment: "Shared alert 'Delete' button. Used anywhere") + } // MARK: Titles and messages - static let error = String.localized("Shared.Error", comment: "Shared alert 'Error' title. Used anywhere") - static let done = String.localized("Shared.Done", comment: "Shared alert Done message. Used anywhere") - static let retryOrDeleteTitle = String.localized("Chats.RetryOrDelete.Title", comment: "Alert 'Retry Or Delete' title. Used in caht for sending failed messages again or delete them") - static let retryOrDeleteBody = String.localized("Chats.RetryOrDelete.Body", comment: "Alert 'Retry Or Delete' body message. Used in caht for sending failed messages again or delete them") + static var error: String { + String.localized("Shared.Error", comment: "Shared alert 'Error' title. Used anywhere") + } + static var done: String { + String.localized("Shared.Done", comment: "Shared alert Done message. Used anywhere") + } + static var retryOrDeleteTitle: String { + String.localized("Chats.RetryOrDelete.Title", comment: "Alert 'Retry Or Delete' title. Used in caht for sending failed messages again or delete them") + } + static var retryOrDeleteBody: String { + String.localized("Chats.RetryOrDelete.Body", comment: "Alert 'Retry Or Delete' body message. Used in caht for sending failed messages again or delete them") + } // MARK: Notifications - static let copiedToPasteboardNotification = String.localized("Shared.CopiedToPasteboard", comment: "Shared alert notification: message about item copied to pasteboard.") - - static let noInternetNotificationTitle = String.localized("Shared.NoInternet.Title", comment: "Shared alert notification: title for no internet connection message.") - static let noInternetNotificationBoby = String.localized("Shared.NoInternet.Body", comment: "Shared alert notification: body message for no internet connection.") + static var copiedToPasteboardNotification: String { + String.localized("Shared.CopiedToPasteboard", comment: "Shared alert notification: message about item copied to pasteboard.") + } + static var noInternetNotificationTitle: String { + String.localized("Shared.NoInternet.Title", comment: "Shared alert notification: title for no internet connection message.") + } + static var noInternetNotificationBoby: String { + String.localized("Shared.NoInternet.Body", comment: "Shared alert notification: body message for no internet connection.") + } - static let emailErrorMessageTitle = String.localized("Error.Mail.Title", comment: "Error messge title for support email") - static let emailErrorMessageBody = String.localized("Error.Mail.Body", comment: "Error messge body for support email") - static let emailErrorMessageBodyWithDescription = String.localized("Error.Mail.Body.Detailed", comment: "Error messge body for support email, with detailed error description. Where first %@ - error's short message, second %@ - detailed description, third %@ - deviceInfo") + static var emailErrorMessageTitle: String { + String.localized("Error.Mail.Title", comment: "Error messge title for support email") + } + static var emailErrorMessageBody: String { + String.localized("Error.Mail.Body", comment: "Error messge body for support email") + } + static var emailErrorMessageBodyWithDescription: String { + String.localized("Error.Mail.Body.Detailed", comment: "Error messge body for support email, with detailed error description. Where first %@ - error's short message, second %@ - detailed description, third %@ - deviceInfo") + } } - struct sharedErrors { - static let userNotLogged = String.localized("Error.UserNotLogged", comment: "Shared error: User not logged") - static let networkError = String.localized("Error.NoNetwork", comment: "Shared error: Network problems. In most cases - no connection") - static let requestCancelled = String.localized("Error.RequestCancelled", comment: "Shared error: Request cancelled") - + enum sharedErrors { + static var userNotLogged: String { + String.localized("Error.UserNotLogged", comment: "Shared error: User not logged") + } + static var networkError: String { + String.localized("Error.NoNetwork", comment: "Shared error: Network problems. In most cases - no connection") + } + static var requestCancelled: String { + String.localized("Error.RequestCancelled", comment: "Shared error: Request cancelled") + } static func commonError(_ text: String) -> String { - return String.localizedStringWithFormat( + String.localizedStringWithFormat( .localized( "Error.BaseErrorFormat", comment: "Shared error: Base format, %@" @@ -58,41 +94,67 @@ extension String.adamant { } static func accountNotFound(_ account: String) -> String { - return String.localizedStringWithFormat(.localized("Error.AccountNotFoundFormat", comment: "Shared error: Account not found error. Using %@ for address."), account) + String.localizedStringWithFormat(.localized("Error.AccountNotFoundFormat", comment: "Shared error: Account not found error. Using %@ for address."), account) } - static let accountNotInitiated = String.localized("Error.AccountNotInitiated", comment: "Shared error: Account not initiated") + static var accountNotInitiated: String { + String.localized("Error.AccountNotInitiated", comment: "Shared error: Account not initiated") + } - static let unknownError = String.localized("Error.UnknownError", comment: "Shared unknown error") + static var unknownError: String { + String.localized("Error.UnknownError", comment: "Shared unknown error") + } - static let notEnoughMoney = String.localized("WalletServices.SharedErrors.notEnoughMoney", comment: "Wallet Services: Shared error, user do not have enought money.") + static var notEnoughMoney: String { + String.localized("WalletServices.SharedErrors.notEnoughMoney", comment: "Wallet Services: Shared error, user do not have enought money.") + } - static let dustError = String.localized("TransferScene.Dust.Error", comment: "Tranfser: Dust error.") + static var dustError: String { + String.localized("TransferScene.Dust.Error", comment: "Tranfser: Dust error.") + } - static let transactionUnavailable = String.localized("WalletServices.SharedErrors.transactionUnavailable", comment: "Wallet Services: Transaction unavailable") + static var transactionUnavailable: String { + String.localized("WalletServices.SharedErrors.transactionUnavailable", comment: "Wallet Services: Transaction unavailable") + } - static let inconsistentTransaction = String.localized("WalletServices.SharedErrors.inconsistentTransaction", comment: "Wallet Services: Cannot verify transaction") + static var inconsistentTransaction: String { + String.localized("WalletServices.SharedErrors.inconsistentTransaction", comment: "Wallet Services: Cannot verify transaction") + } - static let walletFrezzed = String.localized("WalletServices.SharedErrors.walletFrezzed", comment: "Wallet Services: Wait until other transactions approved") + static var walletFrezzed: String { + String.localized("WalletServices.SharedErrors.walletFrezzed", comment: "Wallet Services: Wait until other transactions approved") + } static func internalError(message: String) -> String { - return String.localizedStringWithFormat(.localized("Error.InternalErrorFormat", comment: "Shared error: Internal error format, %@ for message"), message) + String.localizedStringWithFormat(.localized("Error.InternalErrorFormat", comment: "Shared error: Internal error format, %@ for message"), message) } static func remoteServerError(message: String) -> String { - return String.localizedStringWithFormat(.localized("Error.RemoteServerErrorFormat", comment: "Shared error: Remote error format, %@ for message"), message) + String.localizedStringWithFormat(.localized("Error.RemoteServerErrorFormat", comment: "Shared error: Remote error format, %@ for message"), message) } } enum reply { - static let shortUnknownMessageError = String.localized("Reply.ShortUnknownMessageError", comment: "Short unknown message error") - static let longUnknownMessageError = String.localized("Reply.LongUnknownMessageError", comment: "Long unknown message error") - static let failedMessageError = String.localized("Reply.failedMessageError", comment: "Failed message reply error") - static let pendingMessageError = String.localized("Reply.pendingMessageError", comment: "Pending message reply error") + static var shortUnknownMessageError: String { + String.localized("Reply.ShortUnknownMessageError", comment: "Short unknown message error") + } + static var longUnknownMessageError: String { + String.localized("Reply.LongUnknownMessageError", comment: "Long unknown message error") + } + static var failedMessageError: String { + String.localized("Reply.failedMessageError", comment: "Failed message reply error") + } + static var pendingMessageError: String { + String.localized("Reply.pendingMessageError", comment: "Pending message reply error") + } } enum partnerQR { - static let includePartnerName = String.localized("PartnerQR.includePartnerName", comment: "Include partner name") - static let includePartnerURL = String.localized("PartnerQR.includePartnerURL", comment: "Include partner url") + static var includePartnerName: String { + String.localized("PartnerQR.includePartnerName", comment: "Include partner name") + } + static var includePartnerURL: String { + String.localized("PartnerQR.includePartnerURL", comment: "Include partner url") + } } } diff --git a/Adamant/Models/Language.swift b/Adamant/Models/Language.swift index ad327160b..caf354c46 100644 --- a/Adamant/Models/Language.swift +++ b/Adamant/Models/Language.swift @@ -8,6 +8,12 @@ import Foundation +extension Notification.Name { + struct LanguageStorageService { + static let languageUpdated = Notification.Name("adamant.language.languageUpdated") + } +} + enum Language: String { case ru case en @@ -25,5 +31,15 @@ enum Language: String { } } + var locale: String { + switch self { + case .ru: return "ru_RU" + case .en: return "en_EN" + case .de: return "de_DE" + case .zh: return "zh_CN" + case .auto: return "en_EN" + } + } + static let all: [Language] = [.auto, .en, .ru, .de, .zh] } diff --git a/Adamant/Modules/Account/AccountViewController.swift b/Adamant/Modules/Account/AccountViewController.swift index 02a266893..5274c9b95 100644 --- a/Adamant/Modules/Account/AccountViewController.swift +++ b/Adamant/Modules/Account/AccountViewController.swift @@ -17,12 +17,12 @@ import Combine // MARK: - Localization extension String.adamant { - struct account { - static let title = String.localized("AccountTab.Title", comment: "Account page: scene title") + enum account { + static var title: String { + String.localized("AccountTab.Title", comment: "Account page: scene title") + } static let updatingBalance = "…" - - private init() { } } } @@ -317,8 +317,9 @@ final class AccountViewController: FormViewController { $0.title = Rows.visibleWallets.localized $0.cell.imageView?.image = Rows.visibleWallets.image $0.cell.selectionStyle = .gray - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = Rows.visibleWallets.localized }.onCellSelection { [weak self] (_, _) in guard let self = self else { return } let vc = screensFactory.makeVisibleWallets() @@ -345,8 +346,9 @@ final class AccountViewController: FormViewController { $0.tag = Rows.nodes.tag $0.cell.imageView?.image = Rows.nodes.image $0.cell.selectionStyle = .gray - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = Rows.nodes.localized }.onCellSelection { [weak self] (_, _) in guard let self = self else { return } let vc = screensFactory.makeNodesList() @@ -372,8 +374,9 @@ final class AccountViewController: FormViewController { $0.tag = Rows.coinsNodes.tag $0.cell.imageView?.image = Rows.coinsNodes.image $0.cell.selectionStyle = .gray - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = Rows.coinsNodes.localized }.onCellSelection { [weak self] (_, _) in guard let self = self else { return } let vc = screensFactory.makeCoinsNodesList(context: .menu) @@ -393,6 +396,28 @@ final class AccountViewController: FormViewController { appSection.append(coinsNodesRow) + // Language select + let languageRow = ActionSheetRow { + $0.title = Rows.language.localized + $0.tag = Rows.language.tag + $0.cell.imageView?.image = Rows.language.image + $0.options = Language.all + $0.value = languageService.getLanguage() + + $0.displayValueFor = { language in + return language?.name + } + }.cellUpdate { (cell, row) in + cell.accessoryType = .disclosureIndicator + row.title = Rows.language.localized + }.onChange { [weak self] row in + guard let value = row.value else { return } + self?.languageService.setLanguage(value) + self?.updateUI() + } + + appSection.append(languageRow) + // Currency select let currencyRow = ActionSheetRow { $0.title = Rows.currency.localized @@ -408,8 +433,9 @@ final class AccountViewController: FormViewController { return "\(currency.rawValue) (\(currency.symbol))" } - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = Rows.currency.localized }.onChange { [weak self] row in guard let value = row.value else { return } self?.currencyInfoService.currentCurrency = value @@ -417,34 +443,15 @@ final class AccountViewController: FormViewController { appSection.append(currencyRow) - // Language select - let languageRow = ActionSheetRow { - $0.title = Rows.language.localized - $0.tag = Rows.language.tag - $0.cell.imageView?.image = Rows.language.image - $0.options = Language.all - $0.value = languageService.getLanguage() - - $0.displayValueFor = { language in - return language?.name - } - }.cellUpdate { (cell, _) in - cell.accessoryType = .disclosureIndicator - }.onChange { [weak self] row in - guard let value = row.value else { return } - self?.languageService.setLanguage(value) - } - - appSection.append(languageRow) - // Contribute let contributeRow = LabelRow { $0.title = Rows.contribute.localized $0.tag = Rows.contribute.tag $0.cell.imageView?.image = Rows.contribute.image $0.cell.selectionStyle = .gray - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = Rows.contribute.localized }.onCellSelection { [weak self] (_, _) in guard let self = self else { return } let vc = screensFactory.makeContribute() @@ -470,8 +477,9 @@ final class AccountViewController: FormViewController { $0.tag = Rows.about.tag $0.cell.imageView?.image = Rows.about.image $0.cell.selectionStyle = .gray - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = Rows.about.localized }.onCellSelection { [weak self] (_, _) in guard let self = self else { return } let vc = screensFactory.makeAbout() @@ -502,8 +510,9 @@ final class AccountViewController: FormViewController { $0.title = Rows.voteForDelegates.localized $0.cell.imageView?.image = Rows.voteForDelegates.image $0.cell.selectionStyle = .gray - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = Rows.voteForDelegates.localized }.onCellSelection { [weak self] (_, _) in guard let self = self else { return } let vc = screensFactory.makeDelegatesList() @@ -530,8 +539,9 @@ final class AccountViewController: FormViewController { $0.tag = Rows.generateQr.tag $0.cell.imageView?.image = Rows.generateQr.image $0.cell.selectionStyle = .gray - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = Rows.generateQr.localized }.onCellSelection { [weak self] (_, _) in guard let self = self else { return } let vc = screensFactory.makeQRGenerator() @@ -557,8 +567,9 @@ final class AccountViewController: FormViewController { $0.tag = Rows.generatePk.tag $0.cell.imageView?.image = Rows.generatePk.image $0.cell.selectionStyle = .gray - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = Rows.generatePk.localized }.onCellSelection { [weak self] (_, _) in guard let self = self else { return } let vc = screensFactory.makePKGenerator() @@ -584,8 +595,9 @@ final class AccountViewController: FormViewController { $0.tag = Rows.logout.tag $0.cell.imageView?.image = Rows.logout.image $0.cell.selectionStyle = .gray - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = Rows.logout.localized }.onCellSelection { [weak self] (_, row) in guard let address = self?.accountService.account?.address else { return @@ -631,8 +643,9 @@ final class AccountViewController: FormViewController { $0.title = Rows.stayIn.localized $0.cell.imageView?.image = Rows.stayIn.image $0.value = accountService.hasStayInAccount - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.switchControl.onTintColor = UIColor.adamant.active + row.title = Rows.stayIn.localized }.onChange { [weak self] row in guard let enabled = row.value else { return @@ -662,8 +675,9 @@ final class AccountViewController: FormViewController { return !showBiometry }) - }.cellUpdate { (cell, _) in + }.cellUpdate { [weak self] (cell, row) in cell.switchControl.onTintColor = UIColor.adamant.active + row.title = self?.localAuth.biometryType.localized }.onChange { [weak self] row in let value = row.value ?? false self?.setBiometry(enabled: value) @@ -686,8 +700,10 @@ final class AccountViewController: FormViewController { return !showNotifications }) - }.cellUpdate { (cell, _) in + }.cellUpdate { [weak self] (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = Rows.notifications.localized + row.value = self?.notificationsService.notificationsMode.localized }.onCellSelection { [weak self] (_, _) in guard let self = self else { return } let vc = screensFactory.makeNotifications() @@ -889,6 +905,35 @@ final class AccountViewController: FormViewController { .store(in: ¬ificationsSet) } + private func updateUI() { + let appSection = form.sectionBy(tag: Sections.application.tag) + appSection?.header?.title = Sections.application.localized + + let walletSection = form.sectionBy(tag: Sections.wallet.tag) + walletSection?.header?.title = Sections.wallet.localized + + let securitySection = form.sectionBy(tag: Sections.security.tag) + securitySection?.header?.title = Sections.security.localized + + let actionsSection = form.sectionBy(tag: Sections.actions.tag) + actionsSection?.header?.title = Sections.actions.localized + + tableView.reloadData() + + tabBarController?.viewControllers?.first?.tabBarItem.title = .adamant.tabItems.chats + tabBarController?.viewControllers?.last?.tabBarItem.title = .adamant.tabItems.account + + if let splitVC = tabBarController?.viewControllers?.first as? UISplitViewController, + !splitVC.isCollapsed { + splitVC.showDetailViewController(WelcomeViewController(), sender: nil) + } + + if let splitVC = tabBarController?.viewControllers?.last as? UISplitViewController, + !splitVC.isCollapsed { + splitVC.showDetailViewController(WelcomeViewController(), sender: nil) + } + } + private func setupWalletsVC() { walletViewControllers.removeAll() let availableServices: [WalletService] = visibleWalletsService.sorted(includeInvisible: false) diff --git a/Adamant/Modules/Chat/ChatLocalization.swift b/Adamant/Modules/Chat/ChatLocalization.swift index 441fad9c3..f255748bf 100644 --- a/Adamant/Modules/Chat/ChatLocalization.swift +++ b/Adamant/Modules/Chat/ChatLocalization.swift @@ -12,35 +12,77 @@ import CommonKit // MARK: - Localization extension String.adamant { enum chat { - static let sendButton = String.localized("ChatScene.Send", comment: "Chat: Send message button") - static let messageInputPlaceholder = String.localized("ChatScene.NewMessage.Placeholder", comment: "Chat: message input placeholder") - static let cancelError = String.localized("ChatScene.Error.cancelError", comment: "Chat: inform user that he can't cancel transaction, that was sent") - static let failToSend = String.localized("ChatScene.MessageStatus.FailToSend", comment: "Chat: status message for failed to send chat transaction") - static let pending = String.localized("ChatScene.MessageStatus.Pending", comment: "Chat: status message for pending chat transaction") - - static let actionsBody = String.localized("ChatScene.Actions.Body", comment: "Chat: Body for actions menu") - static let rename = String.localized("ChatScene.Actions.Rename", comment: "Chat: 'Rename' action in actions menu") - static let name = String.localized("ChatScene.Actions.NamePlaceholder", comment: "Chat: 'Name' field in actions menu") - - static let noMailAppWarning = String.localized("ChatScene.Warning.NoMailApp", comment: "Chat: warning message for opening email link without mail app configurated on device") - static let unsupportedUrlWarning = String.localized("ChatScene.Warning.UnsupportedUrl", comment: "Chat: warning message for opening unsupported url schemes") - - static let block = String.localized("Chats.Block", comment: "Block") - - static let remove = String.localized("Chats.Remove", comment: "Remove") - static let removeMessage = String.localized("Chats.RemoveMessage", comment: "Delete this message?") - static let report = String.localized("Chats.Report", comment: "Report") - static let reply = String.localized("Chats.Reply", comment: "Reply") - static let copy = String.localized("Chats.Copy", comment: "Copy") - static let reportMessage = String.localized("Chats.ReportMessage", comment: "Report as inappropriate?") - static let reportSent = String.localized("Chats.ReportSent", comment: "Report has been sent") - - static let freeTokens = String.localized("ChatScene.FreeTokensAlert.FreeTokens", comment: "Chat: 'Free Tokens' button") - static let freeTokensMessage = String.localized("ChatScene.FreeTokensAlert.Message", comment: "Chat: 'Free Tokens' message") - - static let transactionSent = String.localized("ChatScene.Sent", comment: "Chat: 'Sent funds' bubble title") - static let transactionReceived = String.localized("ChatScene.Received", comment: "Chat: 'Received funds' bubble title") - static let messageWasDeleted = String.localized("ChatScene.Error.messageWasDeleted", comment: "Chat: Error scrolling to message, this message has been deleted and is no longer accessible") - static let messageIsTooBig = String.localized("ChatScene.Error.messageIsTooBig", comment: "Chat: Error message is too big") + static var sendButton: String { + String.localized("ChatScene.Send", comment: "Chat: Send message button") + } + static var messageInputPlaceholder: String { + String.localized("ChatScene.NewMessage.Placeholder", comment: "Chat: message input placeholder") + } + static var cancelError: String { + String.localized("ChatScene.Error.cancelError", comment: "Chat: inform user that he can't cancel transaction, that was sent") + } + static var failToSend: String { + String.localized("ChatScene.MessageStatus.FailToSend", comment: "Chat: status message for failed to send chat transaction") + } + static var pending: String { + String.localized("ChatScene.MessageStatus.Pending", comment: "Chat: status message for pending chat transaction") + } + static var actionsBody: String { + String.localized("ChatScene.Actions.Body", comment: "Chat: Body for actions menu") + } + static var rename: String { + String.localized("ChatScene.Actions.Rename", comment: "Chat: 'Rename' action in actions menu") + } + static var name: String { + String.localized("ChatScene.Actions.NamePlaceholder", comment: "Chat: 'Name' field in actions menu") + } + static var noMailAppWarning: String { + String.localized("ChatScene.Warning.NoMailApp", comment: "Chat: warning message for opening email link without mail app configurated on device") + } + static var unsupportedUrlWarning: String { + String.localized("ChatScene.Warning.UnsupportedUrl", comment: "Chat: warning message for opening unsupported url schemes") + } + static var block: String { + String.localized("Chats.Block", comment: "Block") + } + static var remove: String { + String.localized("Chats.Remove", comment: "Remove") + } + static var removeMessage: String { + String.localized("Chats.RemoveMessage", comment: "Delete this message?") + } + static var report: String { + String.localized("Chats.Report", comment: "Report") + } + static var reply: String { + String.localized("Chats.Reply", comment: "Reply") + } + static var copy: String { + String.localized("Chats.Copy", comment: "Copy") + } + static var reportMessage: String { + String.localized("Chats.ReportMessage", comment: "Report as inappropriate?") + } + static var reportSent: String { + String.localized("Chats.ReportSent", comment: "Report has been sent") + } + static var freeTokens: String { + String.localized("ChatScene.FreeTokensAlert.FreeTokens", comment: "Chat: 'Free Tokens' button") + } + static var freeTokensMessage: String { + String.localized("ChatScene.FreeTokensAlert.Message", comment: "Chat: 'Free Tokens' message") + } + static var transactionSent: String { + String.localized("ChatScene.Sent", comment: "Chat: 'Sent funds' bubble title") + } + static var transactionReceived: String { + String.localized("ChatScene.Received", comment: "Chat: 'Received funds' bubble title") + } + static var messageWasDeleted: String { + String.localized("ChatScene.Error.messageWasDeleted", comment: "Chat: Error scrolling to message, this message has been deleted and is no longer accessible") + } + static var messageIsTooBig: String { + String.localized("ChatScene.Error.messageIsTooBig", comment: "Chat: Error message is too big") + } } } diff --git a/Adamant/Modules/ChatsList/ChatListViewController.swift b/Adamant/Modules/ChatsList/ChatListViewController.swift index f92838381..d5d3fda70 100644 --- a/Adamant/Modules/ChatsList/ChatListViewController.swift +++ b/Adamant/Modules/ChatsList/ChatListViewController.swift @@ -14,19 +14,28 @@ import Combine import CommonKit extension String.adamant { - struct chatList { - static let title = String.localized("ChatListPage.Title", comment: "ChatList: scene title") - static let sentMessagePrefix = String.localized("ChatListPage.SentMessagePrefix", comment: "ChatList: outgoing message prefix") - static let syncingChats = String.localized("ChatListPage.SyncingChats", comment: "ChatList: First syncronization is in progress") - static let searchPlaceholder = String.localized("ChatListPage.SearchBar.Placeholder", comment: "ChatList: SearchBar placeholder text") - - static let blockUser = String.localized("Chats.BlockUser", comment: "Block this user?") - - static let removedReaction = String.localized("ChatListPage.RemovedReaction", comment: "ChatList: Removed Reaction?") - - static let reacted = String.localized("ChatListPage.Reacted", comment: "ChatList: Reacted") - - private init() {} + enum chatList { + static var title: String { + String.localized("ChatListPage.Title", comment: "ChatList: scene title") + } + static var sentMessagePrefix: String { + String.localized("ChatListPage.SentMessagePrefix", comment: "ChatList: outgoing message prefix") + } + static var syncingChats: String { + String.localized("ChatListPage.SyncingChats", comment: "ChatList: First syncronization is in progress") + } + static var searchPlaceholder: String { + String.localized("ChatListPage.SearchBar.Placeholder", comment: "ChatList: SearchBar placeholder text") + } + static var blockUser: String { + String.localized("Chats.BlockUser", comment: "Block this user?") + } + static var removedReaction: String { + String.localized("ChatListPage.RemovedReaction", comment: "ChatList: Removed Reaction?") + } + static var reacted: String { + String.localized("ChatListPage.Reacted", comment: "ChatList: Reacted") + } } } @@ -254,6 +263,19 @@ final class ChatListViewController: KeyboardObservingViewController { .sink { [weak self] notification in self?.animateUpdateIfNeeded(notification) } .store(in: &subscriptions) + NotificationCenter.default + .publisher(for: .LanguageStorageService.languageUpdated) + .receive(on: OperationQueue.main) + .sink { [weak self] _ in + self?.updateUITitles() + } + .store(in: &subscriptions) + } + + private func updateUITitles() { + updatingIndicatorView.updateTitle(title: String.adamant.chatList.title) + tableView.reloadData() + searchController?.searchBar.placeholder = String.adamant.chatList.searchPlaceholder } private func animateUpdateIfNeeded(_ notification: Notification) { diff --git a/Adamant/Modules/ChatsList/NewChatViewController.swift b/Adamant/Modules/ChatsList/NewChatViewController.swift index 5e41c6e96..f77c4be7c 100644 --- a/Adamant/Modules/ChatsList/NewChatViewController.swift +++ b/Adamant/Modules/ChatsList/NewChatViewController.swift @@ -17,19 +17,25 @@ import CommonKit // MARK: - Localization extension String.adamant { - struct newChat { - static let title = String.localized("NewChatScene.Title", comment: "New chat: scene title") - - static let addressPlaceholder = String.localized("NewChatScene.Address.Placeholder", comment: "New chat: Recipient address placeholder. Note that address text field always shows U letter, so you can left this line blank.") - - static let specifyValidAddressMessage = String.localized("NewChatScene.Error.InvalidAddress", comment: "New chat: Notify user that he did enter invalid address") - static let loggedUserAddressMessage = String.localized("NewChatScene.Error.OwnAddress", comment: "New chat: Notify user that he can't start chat with himself") - - static let wrongQrError = String.localized("NewChatScene.Error.WrongQr", comment: "New Chat: Notify user that scanned QR doesn't contains an address") - - static let whatDoesItMean = String.localized("NewChatScene.NotInitialized.HelpButton", comment: "New Chat: 'What does it mean?', a help button for info about uninitialized accounts.") - - private init() { } + enum newChat { + static var title: String { + String.localized("NewChatScene.Title", comment: "New chat: scene title") + } + static var addressPlaceholder: String { + String.localized("NewChatScene.Address.Placeholder", comment: "New chat: Recipient address placeholder. Note that address text field always shows U letter, so you can left this line blank.") + } + static var specifyValidAddressMessage: String { + String.localized("NewChatScene.Error.InvalidAddress", comment: "New chat: Notify user that he did enter invalid address") + } + static var loggedUserAddressMessage: String { + String.localized("NewChatScene.Error.OwnAddress", comment: "New chat: Notify user that he can't start chat with himself") + } + static var wrongQrError: String { + String.localized("NewChatScene.Error.WrongQr", comment: "New Chat: Notify user that scanned QR doesn't contains an address") + } + static var whatDoesItMean: String { + String.localized("NewChatScene.NotInitialized.HelpButton", comment: "New Chat: 'What does it mean?', a help button for info about uninitialized accounts.") + } } } diff --git a/Adamant/Modules/ChatsList/SearchResultsViewController.swift b/Adamant/Modules/ChatsList/SearchResultsViewController.swift index 76635c830..ebd2f7ffb 100644 --- a/Adamant/Modules/ChatsList/SearchResultsViewController.swift +++ b/Adamant/Modules/ChatsList/SearchResultsViewController.swift @@ -13,10 +13,18 @@ import CommonKit extension String.adamant { enum search { - static let contacts = String.localized("SearchPage.Contacts", comment: "SearchPage: Contacts header") - static let messages = String.localized("SearchPage.Messages", comment: "SearchPage: Messages header") - static let newContactHeader = String.localized("SearchPage.Contact.New", comment: "SearchPage: Contacts header") - static let newContact = String.localized("SearchPage.Contact.Add.New", comment: "SearchPage: Contact new header") + static var contacts: String { + String.localized("SearchPage.Contacts", comment: "SearchPage: Contacts header") + } + static var messages: String { + String.localized("SearchPage.Messages", comment: "SearchPage: Messages header") + } + static var newContactHeader: String { + String.localized("SearchPage.Contact.New", comment: "SearchPage: Contacts header") + } + static var newContact: String { + String.localized("SearchPage.Contact.Add.New", comment: "SearchPage: Contact new header") + } } } diff --git a/Adamant/Modules/CoinsNodesList/ViewModel/CoinsNodesListStrings.swift b/Adamant/Modules/CoinsNodesList/ViewModel/CoinsNodesListStrings.swift index d65bb3fa0..e2283320f 100644 --- a/Adamant/Modules/CoinsNodesList/ViewModel/CoinsNodesListStrings.swift +++ b/Adamant/Modules/CoinsNodesList/ViewModel/CoinsNodesListStrings.swift @@ -10,19 +10,31 @@ import CommonKit extension String.adamant { enum coinsNodesList { - static let title = String.localized("CoinsNodesList.Title", comment: .empty) - static let serviceNode = String.localized("CoinsNodesList.ServiceNode", comment: .empty) - static let reset = String.localized("NodesList.ResetButton", comment: .empty) - static let resetAlert = String.localized("NodesList.ResetNodeListAlert", comment: .empty) + static var title: String { + String.localized("CoinsNodesList.Title", comment: .empty) + } + static var serviceNode: String { + String.localized("CoinsNodesList.ServiceNode", comment: .empty) + } + static var reset: String { + String.localized("NodesList.ResetButton", comment: .empty) + } + static var resetAlert: String { + String.localized("NodesList.ResetNodeListAlert", comment: .empty) + } - static let preferTheFastestNode = String.localized( - "NodesList.PreferTheFastestNode", - comment: .empty - ) + static var preferTheFastestNode: String { + String.localized( + "NodesList.PreferTheFastestNode", + comment: .empty + ) + } - static let fastestNodeTip = String.localized( - "NodesList.PreferTheFastestNode.Footer", - comment: .empty - ) + static var fastestNodeTip: String { + String.localized( + "NodesList.PreferTheFastestNode.Footer", + comment: .empty + ) + } } } diff --git a/Adamant/Modules/Delegates/DelegateDetailsViewController.swift b/Adamant/Modules/Delegates/DelegateDetailsViewController.swift index 58d85dc2a..d35f4e9cf 100644 --- a/Adamant/Modules/Delegates/DelegateDetailsViewController.swift +++ b/Adamant/Modules/Delegates/DelegateDetailsViewController.swift @@ -14,7 +14,9 @@ import CommonKit // MARK: - Localization extension String.adamant { struct delegateDetails { - static let title = String.localized("DelegateDetails.Title", comment: "Delegate details: scene title") + static var title: String { + String.localized("DelegateDetails.Title", comment: "Delegate details: scene title") + } } } diff --git a/Adamant/Modules/Delegates/DelegatesListViewController.swift b/Adamant/Modules/Delegates/DelegatesListViewController.swift index c6b1eb46d..1387ea5f3 100644 --- a/Adamant/Modules/Delegates/DelegatesListViewController.swift +++ b/Adamant/Modules/Delegates/DelegatesListViewController.swift @@ -12,16 +12,19 @@ import CommonKit // MARK: - Localization extension String.adamant { - struct delegates { - static let title = String.localized("Delegates.Title", comment: "Delegates page: scene title") - - static let notEnoughtTokensForVote = String.localized("Delegates.NotEnoughtTokensForVote", comment: "Delegates tab: Message about 50 ADM fee for vote") - - static let timeOutBeforeNewVote = String.localized("Delegates.timeOutBeforeNewVote", comment: "Delegates tab: Message about time out for new vote") - - static let success = String.localized("Delegates.Vote.Success", comment: "Delegates: Message for Successfull voting") - - private init() { } + enum delegates { + static var title: String { + String.localized("Delegates.Title", comment: "Delegates page: scene title") + } + static var notEnoughtTokensForVote: String { + String.localized("Delegates.NotEnoughtTokensForVote", comment: "Delegates tab: Message about 50 ADM fee for vote") + } + static var timeOutBeforeNewVote: String { + String.localized("Delegates.timeOutBeforeNewVote", comment: "Delegates tab: Message about time out for new vote") + } + static var success: String { + String.localized("Delegates.Vote.Success", comment: "Delegates: Message for Successfull voting") + } } } diff --git a/Adamant/Modules/Login/LoginViewController.swift b/Adamant/Modules/Login/LoginViewController.swift index 8453cdcdd..0392fa815 100644 --- a/Adamant/Modules/Login/LoginViewController.swift +++ b/Adamant/Modules/Login/LoginViewController.swift @@ -13,23 +13,34 @@ import CommonKit // MARK: - Localization extension String.adamant { - struct login { - static let loggingInProgressMessage = String.localized("LoginScene.LoggingInProgress", comment: "Login: notify user that we are trying to log in") - - static let loginIntoPrevAccount = String.localized("LoginScene.LoginIntoAdamant", comment: "Login: Login into previous account with biometry or pincode") - - static let wrongQrError = String.localized("LoginScene.Error.WrongQr", comment: "Login: Notify user that scanned QR doesn't contains a passphrase.") - static let noQrError = String.localized("LoginScene.Error.NoQrOnPhoto", comment: "Login: Notify user that picked photo doesn't contains a valid qr code with passphrase") - static let noNetworkError = String.localized("LoginScene.Error.NoInternet", comment: "Login: No network error.") - - static let cameraNotAuthorized = String.localized("LoginScene.Error.AuthorizeCamera", comment: "Login: Notify user, that he disabled camera in settings, and need to authorize application.") - static let cameraNotSupported = String.localized("LoginScene.Error.QrNotSupported", comment: "Login: Notify user that device not supported by QR reader") - - static let photolibraryNotAuthorized = String.localized("LoginScene.Error.AuthorizePhotolibrary", comment: "Login: User disabled access to photolibrary, he can authorize application in settings") - - static let emptyPassphraseAlert = String.localized("LoginScene.Error.NoPassphrase", comment: "Login: notify user that he is trying to login without a passphrase") - - private init() {} + enum login { + static var loggingInProgressMessage: String { + String.localized("LoginScene.LoggingInProgress", comment: "Login: notify user that we are trying to log in") + } + static var loginIntoPrevAccount: String { + String.localized("LoginScene.LoginIntoAdamant", comment: "Login: Login into previous account with biometry or pincode") + } + static var wrongQrError: String { + String.localized("LoginScene.Error.WrongQr", comment: "Login: Notify user that scanned QR doesn't contains a passphrase.") + } + static var noQrError: String { + String.localized("LoginScene.Error.NoQrOnPhoto", comment: "Login: Notify user that picked photo doesn't contains a valid qr code with passphrase") + } + static var noNetworkError: String { + String.localized("LoginScene.Error.NoInternet", comment: "Login: No network error.") + } + static var cameraNotAuthorized: String { + String.localized("LoginScene.Error.AuthorizeCamera", comment: "Login: Notify user, that he disabled camera in settings, and need to authorize application.") + } + static var cameraNotSupported: String { + String.localized("LoginScene.Error.QrNotSupported", comment: "Login: Notify user that device not supported by QR reader") + } + static var photolibraryNotAuthorized: String { + String.localized("LoginScene.Error.AuthorizePhotolibrary", comment: "Login: User disabled access to photolibrary, he can authorize application in settings") + } + static var emptyPassphraseAlert: String { + String.localized("LoginScene.Error.NoPassphrase", comment: "Login: notify user that he is trying to login without a passphrase") + } } } diff --git a/Adamant/Modules/NodesEditor/NodeEditorViewController.swift b/Adamant/Modules/NodesEditor/NodeEditorViewController.swift index 5c0e8216f..e4c4422be 100644 --- a/Adamant/Modules/NodesEditor/NodeEditorViewController.swift +++ b/Adamant/Modules/NodesEditor/NodeEditorViewController.swift @@ -13,9 +13,15 @@ import CommonKit // MARK: - Localization extension String.adamant { enum nodesEditor { - static let newNodeTitle = String.localized("NodesEditor.NewNodeTitle", comment: "NodesEditor: New node scene title") - static let deleteNodeAlert = String.localized("NodesEditor.DeleteNodeAlert", comment: "NodesEditor: Delete node confirmation message") - static let failedToBuildURL = String.localized("NodesEditor.FailedToBuildURL", comment: "NodesEditor: Failed to build URL alert") + static var newNodeTitle: String { + String.localized("NodesEditor.NewNodeTitle", comment: "NodesEditor: New node scene title") + } + static var deleteNodeAlert: String { + String.localized("NodesEditor.DeleteNodeAlert", comment: "NodesEditor: Delete node confirmation message") + } + static var failedToBuildURL: String { + String.localized("NodesEditor.FailedToBuildURL", comment: "NodesEditor: Failed to build URL alert") + } } } diff --git a/Adamant/Modules/NodesEditor/NodesListViewController.swift b/Adamant/Modules/NodesEditor/NodesListViewController.swift index 358859a83..69a7cf3a6 100644 --- a/Adamant/Modules/NodesEditor/NodesListViewController.swift +++ b/Adamant/Modules/NodesEditor/NodesListViewController.swift @@ -14,17 +14,27 @@ import Combine // MARK: - Localization extension String.adamant { enum nodesList { - static let title = String.localized("NodesList.Title", comment: "NodesList: scene title") - static let nodesListButton = String.localized("NodesList.NodesList", comment: "NodesList: Button label") + static var title: String { + String.localized("NodesList.Title", comment: "NodesList: scene title") + } + static var nodesListButton: String { + String.localized("NodesList.NodesList", comment: "NodesList: Button label") + } - static let defaultNodesWasLoaded = String.localized("NodeList.DefaultNodesLoaded", comment: "NodeList: Inform that default nodes was loaded, if user deleted all nodes") + static var defaultNodesWasLoaded: String { + String.localized("NodeList.DefaultNodesLoaded", comment: "NodeList: Inform that default nodes was loaded, if user deleted all nodes") + } - static let resetAlertTitle = String.localized("NodesList.ResetNodeListAlert", comment: "NodesList: Reset nodes alert title") + static var resetAlertTitle: String { + String.localized("NodesList.ResetNodeListAlert", comment: "NodesList: Reset nodes alert title") + } - static let fastestNodeModeTip = String.localized( - "NodesList.PreferTheFastestNode.Footer", - comment: .empty - ) + static var fastestNodeModeTip: String { + String.localized( + "NodesList.PreferTheFastestNode.Footer", + comment: .empty + ) + } } } diff --git a/Adamant/Modules/Onboard/OnboardOverlay.swift b/Adamant/Modules/Onboard/OnboardOverlay.swift index 97eed9096..c983971f1 100644 --- a/Adamant/Modules/Onboard/OnboardOverlay.swift +++ b/Adamant/Modules/Onboard/OnboardOverlay.swift @@ -60,7 +60,11 @@ final class OnboardOverlay: SwiftyOnboardOverlay { private extension String.adamant { enum Onboard { - static let agreeLabel = String.localized("WelcomeScene.Description.Accept", comment: "Welcome: Description accept") - static let eulaTitle = String.localized("EULA.Title", comment: "") + static var agreeLabel: String { + String.localized("WelcomeScene.Description.Accept", comment: "Welcome: Description accept") + } + static var eulaTitle: String { + String.localized("EULA.Title", comment: "") + } } } diff --git a/Adamant/Modules/Onboard/OnboardViewController.swift b/Adamant/Modules/Onboard/OnboardViewController.swift index e9347e293..6ca5ce540 100644 --- a/Adamant/Modules/Onboard/OnboardViewController.swift +++ b/Adamant/Modules/Onboard/OnboardViewController.swift @@ -21,12 +21,16 @@ private class OnboardingPageItem { } fileprivate extension String.adamant { - struct Onboard { - static let beginButton = String.localized("WelcomeScene.Description.BeginButton", comment: "Welcome: Last slide Begin button") - static let continueButton = String.localized("WelcomeScene.Description.ContinueButton", comment: "Welcome: Next screen button") - static let skipButton = String.localized("WelcomeScene.Description.SkipButton", comment: "Welcome: Skip button") - - private init() {} + enum Onboard { + static var beginButton: String { + String.localized("WelcomeScene.Description.BeginButton", comment: "Welcome: Last slide Begin button") + } + static var continueButton: String { + String.localized("WelcomeScene.Description.ContinueButton", comment: "Welcome: Next screen button") + } + static var skipButton: String { + String.localized("WelcomeScene.Description.SkipButton", comment: "Welcome: Skip button") + } } } diff --git a/Adamant/Modules/Settings/AboutViewController.swift b/Adamant/Modules/Settings/AboutViewController.swift index 79b6796b0..48f34bad3 100644 --- a/Adamant/Modules/Settings/AboutViewController.swift +++ b/Adamant/Modules/Settings/AboutViewController.swift @@ -15,7 +15,9 @@ import CommonKit // MARK: - Localization extension String.adamant { struct about { - static let title = String.localized("About.Title", comment: "About page: scene title") + static var title: String { + String.localized("About.Title", comment: "About page: scene title") + } private init() { } } diff --git a/Adamant/Modules/Settings/PKGeneratorViewController.swift b/Adamant/Modules/Settings/PKGeneratorViewController.swift index 34476f29a..35ba5e7b1 100644 --- a/Adamant/Modules/Settings/PKGeneratorViewController.swift +++ b/Adamant/Modules/Settings/PKGeneratorViewController.swift @@ -15,12 +15,16 @@ import CommonKit // MARK: - Localization extension String.adamant { - struct pkGenerator { - static let title = String.localized("PkGeneratorScene.Title", comment: "PrivateKeyGenerator: scene title") - static let alert = String.localized("PkGeneratorScene.Alert", comment: "PrivateKeyGenerator: Security alert. Keep your passphrase safe") - static let generateButton = String.localized("PkGeneratorScene.GenerateButton", comment: "PrivateKeyGenerator: Generate button") - - private init() {} + enum pkGenerator { + static var title: String { + String.localized("PkGeneratorScene.Title", comment: "PrivateKeyGenerator: scene title") + } + static var alert: String { + String.localized("PkGeneratorScene.Alert", comment: "PrivateKeyGenerator: Security alert. Keep your passphrase safe") + } + static var generateButton: String { + String.localized("PkGeneratorScene.GenerateButton", comment: "PrivateKeyGenerator: Generate button") + } } } diff --git a/Adamant/Modules/Settings/QRGeneratorViewController.swift b/Adamant/Modules/Settings/QRGeneratorViewController.swift index 4a5438b00..7a5d4192e 100644 --- a/Adamant/Modules/Settings/QRGeneratorViewController.swift +++ b/Adamant/Modules/Settings/QRGeneratorViewController.swift @@ -14,16 +14,22 @@ import CommonKit // MARK: - Localization extension String.adamant { - struct qrGenerator { - static let title = String.localized("QrGeneratorScene.Title", comment: "QRGenerator: scene title") - - static let tapToSaveTip = String.localized("QrGeneratorScene.TapToSave", comment: "QRGenerator: small 'Tap to save' tooltip under generated QR") - static let passphrasePlaceholder = String.localized("QrGeneratorScene.Passphrase.Placeholder", comment: "QRGenerator: Passphrase textview placeholder") - - static let wrongPassphraseError = String.localized("QrGeneratorScene.Error.InvalidPassphrase", comment: "QRGenerator: user typed in invalid passphrase") - static let internalError = String.localized("QrGeneratorScene.Error.InternalErrorFormat", comment: "QRGenerator: Bad Internal generator error message format. Using %@ for error description") - - private init() {} + enum qrGenerator { + static var title: String { + String.localized("QrGeneratorScene.Title", comment: "QRGenerator: scene title") + } + static var tapToSaveTip: String { + String.localized("QrGeneratorScene.TapToSave", comment: "QRGenerator: small 'Tap to save' tooltip under generated QR") + } + static var passphrasePlaceholder: String { + String.localized("QrGeneratorScene.Passphrase.Placeholder", comment: "QRGenerator: Passphrase textview placeholder") + } + static var wrongPassphraseError: String { + String.localized("QrGeneratorScene.Error.InvalidPassphrase", comment: "QRGenerator: user typed in invalid passphrase") + } + static var internalError: String { + String.localized("QrGeneratorScene.Error.InternalErrorFormat", comment: "QRGenerator: Bad Internal generator error message format. Using %@ for error description") + } } } diff --git a/Adamant/Modules/Settings/SecurityViewController.swift b/Adamant/Modules/Settings/SecurityViewController.swift index 914aeb37b..fd1bd954e 100644 --- a/Adamant/Modules/Settings/SecurityViewController.swift +++ b/Adamant/Modules/Settings/SecurityViewController.swift @@ -14,14 +14,20 @@ import CommonKit // MARK: - Localization extension String.adamant { - struct security { - static let title = String.localized("SecurityPage.Title", comment: "Security: scene title") - - static let stayInTurnOff = String.localized("SecurityPage.DoNotStayLoggedIn", comment: "Security: turn off 'Stay Logged In' confirmation") - static let biometryOnReason = String.localized("SecurityPage.UseBiometry", comment: "Security: Authorization reason for turning biometry on") - static let biometryOffReason = String.localized("SecurityPage.DoNotUseBiometry", comment: "Security: Authorization reason for turning biometry off") + enum security { + static var title: String { + String.localized("SecurityPage.Title", comment: "Security: scene title") + } - private init() {} + static var stayInTurnOff: String { + String.localized("SecurityPage.DoNotStayLoggedIn", comment: "Security: turn off 'Stay Logged In' confirmation") + } + static var biometryOnReason: String { + String.localized("SecurityPage.UseBiometry", comment: "Security: Authorization reason for turning biometry on") + } + static var biometryOffReason: String { + String.localized("SecurityPage.DoNotUseBiometry", comment: "Security: Authorization reason for turning biometry off") + } } } diff --git a/Adamant/Modules/Settings/VisibleWallets/VisibleWalletsViewController.swift b/Adamant/Modules/Settings/VisibleWallets/VisibleWalletsViewController.swift index 8003142d6..4cf0e933b 100644 --- a/Adamant/Modules/Settings/VisibleWallets/VisibleWalletsViewController.swift +++ b/Adamant/Modules/Settings/VisibleWallets/VisibleWalletsViewController.swift @@ -13,9 +13,15 @@ import CommonKit // MARK: - Localization extension String.adamant { enum visibleWallets { - static let title = String.localized("VisibleWallets.Title", comment: "Visible Wallets page: scene title") - static let resetAlertTitle = String.localized("VisibleWallets.ResetListAlert", comment: "VisibleWallets: Reset wallets alert title") - static let reset = String.localized("NodesList.ResetButton", comment: "NodesList: 'Reset' button") + static var title: String { + String.localized("VisibleWallets.Title", comment: "Visible Wallets page: scene title") + } + static var resetAlertTitle: String { + String.localized("VisibleWallets.ResetListAlert", comment: "VisibleWallets: Reset wallets alert title") + } + static var reset: String { + String.localized("NodesList.ResetButton", comment: "NodesList: 'Reset' button") + } } } diff --git a/Adamant/Modules/Wallets/Adamant/AdmTransactionDetailsViewController.swift b/Adamant/Modules/Wallets/Adamant/AdmTransactionDetailsViewController.swift index 072bee533..8c43aeae3 100644 --- a/Adamant/Modules/Wallets/Adamant/AdmTransactionDetailsViewController.swift +++ b/Adamant/Modules/Wallets/Adamant/AdmTransactionDetailsViewController.swift @@ -49,7 +49,8 @@ final class AdmTransactionDetailsViewController: TransactionDetailsViewControlle screensFactory: ScreensFactory, dialogService: DialogService, currencyInfo: CurrencyInfoService, - addressBookService: AddressBookService + addressBookService: AddressBookService, + languageService: LanguageStorageProtocol ) { self.transfersProvider = transfersProvider self.screensFactory = screensFactory @@ -59,7 +60,8 @@ final class AdmTransactionDetailsViewController: TransactionDetailsViewControlle currencyInfo: currencyInfo, addressBookService: addressBookService, accountService: accountService, - walletService: nil + walletService: nil, + languageService: languageService ) } diff --git a/Adamant/Modules/Wallets/Adamant/AdmTransferViewController.swift b/Adamant/Modules/Wallets/Adamant/AdmTransferViewController.swift index c2fe5999c..b02d8e659 100644 --- a/Adamant/Modules/Wallets/Adamant/AdmTransferViewController.swift +++ b/Adamant/Modules/Wallets/Adamant/AdmTransferViewController.swift @@ -18,9 +18,11 @@ extension String.adamant { return String.localizedStringWithFormat(.localized("TransferScene.unsafeTransferAlert.title", comment: "Transfer: Alert title: Account not found or not initiated. Alert user that he still can send money, but need to double ckeck address"), address) } - static let accountNotFoundAlertBody = String.localized("TransferScene.unsafeTransferAlert.body", comment: "Transfer: Alert body: Account not found or not initiated. Alert user that he still can send money, but need to double ckeck address") + static var accountNotFoundAlertBody: String { String.localized("TransferScene.unsafeTransferAlert.body", comment: "Transfer: Alert body: Account not found or not initiated. Alert user that he still can send money, but need to double ckeck address") + } - static let accountNotFoundChatAlertBody = String.localized("TransferScene.unsafeChatAlert.body", comment: "Transfer: Alert body: Account is not initiated. It's not possible to start a chat, as the Blockchain doesn't store the account's public key to encrypt messages.") + static var accountNotFoundChatAlertBody: String { String.localized("TransferScene.unsafeChatAlert.body", comment: "Transfer: Alert body: Account is not initiated. It's not possible to start a chat, as the Blockchain doesn't store the account's public key to encrypt messages.") + } } } diff --git a/Adamant/Modules/Wallets/Adamant/AdmWalletFactory.swift b/Adamant/Modules/Wallets/Adamant/AdmWalletFactory.swift index 82772bc15..b4d6ff676 100644 --- a/Adamant/Modules/Wallets/Adamant/AdmWalletFactory.swift +++ b/Adamant/Modules/Wallets/Adamant/AdmWalletFactory.swift @@ -90,7 +90,8 @@ private extension AdmWalletFactory { screensFactory: screensFactory, dialogService: assembler.resolve(DialogService.self)!, currencyInfo: assembler.resolve(CurrencyInfoService.self)!, - addressBookService: assembler.resolve(AddressBookService.self)! + addressBookService: assembler.resolve(AddressBookService.self)!, + languageService: assembler.resolve(LanguageStorageProtocol.self)! ) } } diff --git a/Adamant/Modules/Wallets/Adamant/AdmWalletViewController.swift b/Adamant/Modules/Wallets/Adamant/AdmWalletViewController.swift index 5fb118b3f..392ecb955 100644 --- a/Adamant/Modules/Wallets/Adamant/AdmWalletViewController.swift +++ b/Adamant/Modules/Wallets/Adamant/AdmWalletViewController.swift @@ -12,13 +12,21 @@ import Eureka import CommonKit extension String.adamant.wallets { - static let adamant = String.localized("AccountTab.Wallets.adamant_wallet", comment: "Account tab: Adamant wallet") + static var adamant: String { + String.localized("AccountTab.Wallets.adamant_wallet", comment: "Account tab: Adamant wallet") + } - static let sendAdm = String.localized("AccountTab.Row.SendAdm", comment: "Account tab: 'Send ADM tokens' button") + static var sendAdm: String { + String.localized("AccountTab.Row.SendAdm", comment: "Account tab: 'Send ADM tokens' button") + } - static let buyAdmTokens = String.localized("AccountTab.Row.AnonymouslyBuyADM", comment: "Account tab: Anonymously buy ADM tokens") + static var buyAdmTokens: String { + String.localized("AccountTab.Row.AnonymouslyBuyADM", comment: "Account tab: Anonymously buy ADM tokens") + } - static let exchangeInChatAdmTokens = String.localized("AccountTab.Row.ExchangeADMInChat", comment: "Account tab: Exchange ADM in chat") + static var exchangeInChatAdmTokens: String { + String.localized("AccountTab.Row.ExchangeADMInChat", comment: "Account tab: Exchange ADM in chat") + } // URLs static func getFreeTokensUrl(for address: String) -> String { return String.localizedStringWithFormat(.localized("AccountTab.FreeTokens.UrlFormat", comment: "Account tab: A full 'Get free tokens' link, with %@ as address"), address) @@ -66,9 +74,6 @@ final class AdmWalletViewController: WalletViewControllerBase { override func viewDidLoad() { super.viewDidLoad() - - walletTitleLabel.text = String.adamant.wallets.adamant - if let balance = service?.wallet?.balance { hideFreeTokensRow = balance > 0 } else { @@ -88,11 +93,12 @@ final class AdmWalletViewController: WalletViewControllerBase { $0.cell.imageView?.tintColor = UIColor.adamant.tableRowIcons $0.cell.selectionStyle = .gray $0.cell.backgroundColor = UIColor.adamant.cellColor - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator if self.hideFreeTokensRow { cell.separatorInset = .zero } + row.title = Rows.buyTokens.localized }.onCellSelection { [weak self] (_, row) in guard let self = self else { return } let vc = screensFactory.makeBuyAndSell() @@ -116,9 +122,10 @@ final class AdmWalletViewController: WalletViewControllerBase { return self?.hideFreeTokensRow ?? true }) $0.cell.backgroundColor = UIColor.adamant.cellColor - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator cell.separatorInset = .zero + row.title = Rows.freeTokens.localized }.onCellSelection { [weak self] (_, row) in row.deselect() if let address = self?.service?.wallet?.address { @@ -175,8 +182,9 @@ final class AdmWalletViewController: WalletViewControllerBase { if let wallet = service?.wallet { $0.value = wallet.address } - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = BaseRows.address.localized }.onCellSelection { [weak self] (cell, row) in row.deselect() let completion = { [weak self] in @@ -205,6 +213,10 @@ final class AdmWalletViewController: WalletViewControllerBase { return addressRow } + override func setTitle() { + walletTitleLabel.text = String.adamant.wallets.adamant + } + func updateRows() { guard let admService = service as? AdmWalletService, let wallet = admService.wallet as? AdmWallet else { return diff --git a/Adamant/Modules/Wallets/Bitcoin/BtcWalletFactory.swift b/Adamant/Modules/Wallets/Bitcoin/BtcWalletFactory.swift index 45d36d3d0..f0e3dcc14 100644 --- a/Adamant/Modules/Wallets/Bitcoin/BtcWalletFactory.swift +++ b/Adamant/Modules/Wallets/Bitcoin/BtcWalletFactory.swift @@ -129,7 +129,8 @@ private extension BtcWalletFactory { currencyInfo: assembler.resolve(CurrencyInfoService.self)!, addressBookService: assembler.resolve(AddressBookService.self)!, accountService: assembler.resolve(AccountService.self)!, - walletService: service + walletService: service, + languageService: assembler.resolve(LanguageStorageProtocol.self)! ) vc.service = service diff --git a/Adamant/Modules/Wallets/Bitcoin/BtcWalletService.swift b/Adamant/Modules/Wallets/Bitcoin/BtcWalletService.swift index c3e78f06c..ea8cb127b 100644 --- a/Adamant/Modules/Wallets/Bitcoin/BtcWalletService.swift +++ b/Adamant/Modules/Wallets/Bitcoin/BtcWalletService.swift @@ -57,7 +57,9 @@ struct BtcApiCommands { // MARK: - Localization extension String.adamant { enum BtcWalletService { - static let taprootNotSupported = String.localized("WalletServices.SharedErrors.BtcTaproot", comment: "") + static var taprootNotSupported: String { + String.localized("WalletServices.SharedErrors.BtcTaproot", comment: "") + } } } diff --git a/Adamant/Modules/Wallets/Bitcoin/BtcWalletViewController.swift b/Adamant/Modules/Wallets/Bitcoin/BtcWalletViewController.swift index d8ec655e1..c74711b0f 100644 --- a/Adamant/Modules/Wallets/Bitcoin/BtcWalletViewController.swift +++ b/Adamant/Modules/Wallets/Bitcoin/BtcWalletViewController.swift @@ -10,19 +10,16 @@ import UIKit import CommonKit extension String.adamant { - static let bitcoin = String.localized("AccountTab.Wallets.bitcoin_wallet", comment: "Account tab: Bitcoin wallet") + static var bitcoin: String { + String.localized("AccountTab.Wallets.bitcoin_wallet", comment: "Account tab: Bitcoin wallet") + } - static let sendBtc = String.localized("AccountTab.Row.SendBtc", comment: "Account tab: 'Send BTC tokens' button") + static var sendBtc: String { + String.localized("AccountTab.Row.SendBtc", comment: "Account tab: 'Send BTC tokens' button") + } } final class BtcWalletViewController: WalletViewControllerBase { - // MARK: Lifecycle - - override func viewDidLoad() { - super.viewDidLoad() - - walletTitleLabel.text = String.adamant.bitcoin - } override func sendRowLocalizedLabel() -> NSAttributedString { return NSAttributedString(string: String.adamant.sendBtc) @@ -31,4 +28,8 @@ final class BtcWalletViewController: WalletViewControllerBase { override func encodeForQr(address: String) -> String? { return "bitcoin:\(address)" } + + override func setTitle() { + walletTitleLabel.text = String.adamant.bitcoin + } } diff --git a/Adamant/Modules/Wallets/Dash/DashWalletFactory.swift b/Adamant/Modules/Wallets/Dash/DashWalletFactory.swift index ffa3e29af..9c96507ee 100644 --- a/Adamant/Modules/Wallets/Dash/DashWalletFactory.swift +++ b/Adamant/Modules/Wallets/Dash/DashWalletFactory.swift @@ -138,7 +138,8 @@ private extension DashWalletFactory { currencyInfo: assembler.resolve(CurrencyInfoService.self)!, addressBookService: assembler.resolve(AddressBookService.self)!, accountService: assembler.resolve(AccountService.self)!, - walletService: service + walletService: service, + languageService: assembler.resolve(LanguageStorageProtocol.self)! ) vc.service = service diff --git a/Adamant/Modules/Wallets/Dash/DashWalletViewController.swift b/Adamant/Modules/Wallets/Dash/DashWalletViewController.swift index 6bda5de7d..552b5f216 100644 --- a/Adamant/Modules/Wallets/Dash/DashWalletViewController.swift +++ b/Adamant/Modules/Wallets/Dash/DashWalletViewController.swift @@ -11,20 +11,16 @@ import UIKit import CommonKit extension String.adamant { - static let dash = String.localized("AccountTab.Wallets.dash_wallet", comment: "Account tab: Dash wallet") + static var dash: String { + String.localized("AccountTab.Wallets.dash_wallet", comment: "Account tab: Dash wallet") + } - static let sendDash = String.localized("AccountTab.Row.SendDash", comment: "Account tab: 'Send Dash tokens' button") + static var sendDash: String { + String.localized("AccountTab.Row.SendDash", comment: "Account tab: 'Send Dash tokens' button") + } } final class DashWalletViewController: WalletViewControllerBase { - // MARK: Lifecycle - - override func viewDidLoad() { - super.viewDidLoad() - - walletTitleLabel.text = String.adamant.dash - } - override func sendRowLocalizedLabel() -> NSAttributedString { return NSAttributedString(string: String.adamant.sendDash) } @@ -32,4 +28,8 @@ final class DashWalletViewController: WalletViewControllerBase { override func encodeForQr(address: String) -> String? { return "dash:\(address)" } + + override func setTitle() { + walletTitleLabel.text = String.adamant.dash + } } diff --git a/Adamant/Modules/Wallets/Doge/DogeWalletFactory.swift b/Adamant/Modules/Wallets/Doge/DogeWalletFactory.swift index 2f6230e57..1b5bda8f6 100644 --- a/Adamant/Modules/Wallets/Doge/DogeWalletFactory.swift +++ b/Adamant/Modules/Wallets/Doge/DogeWalletFactory.swift @@ -128,7 +128,8 @@ private extension DogeWalletFactory { currencyInfo: assembler.resolve(CurrencyInfoService.self)!, addressBookService: assembler.resolve(AddressBookService.self)!, accountService: assembler.resolve(AccountService.self)!, - walletService: service + walletService: service, + languageService: assembler.resolve(LanguageStorageProtocol.self)! ) vc.service = service diff --git a/Adamant/Modules/Wallets/Doge/DogeWalletViewController.swift b/Adamant/Modules/Wallets/Doge/DogeWalletViewController.swift index 7499bbb50..fe411605e 100644 --- a/Adamant/Modules/Wallets/Doge/DogeWalletViewController.swift +++ b/Adamant/Modules/Wallets/Doge/DogeWalletViewController.swift @@ -10,20 +10,16 @@ import UIKit import CommonKit extension String.adamant { - static let doge = String.localized("AccountTab.Wallets.doge_wallet", comment: "Account tab: Doge wallet") + static var doge: String { + String.localized("AccountTab.Wallets.doge_wallet", comment: "Account tab: Doge wallet") + } - static let sendDoge = String.localized("AccountTab.Row.SendDoge", comment: "Account tab: 'Send DOGE tokens' button") + static var sendDoge: String { + String.localized("AccountTab.Row.SendDoge", comment: "Account tab: 'Send DOGE tokens' button") + } } final class DogeWalletViewController: WalletViewControllerBase { - // MARK: Lifecycle - - override func viewDidLoad() { - super.viewDidLoad() - - walletTitleLabel.text = String.adamant.doge - } - override func sendRowLocalizedLabel() -> NSAttributedString { return NSAttributedString(string: String.adamant.sendDoge) } @@ -31,4 +27,8 @@ final class DogeWalletViewController: WalletViewControllerBase { override func encodeForQr(address: String) -> String? { return "doge:\(address)" } + + override func setTitle() { + walletTitleLabel.text = String.adamant.doge + } } diff --git a/Adamant/Modules/Wallets/ERC20/ERC20WalletFactory.swift b/Adamant/Modules/Wallets/ERC20/ERC20WalletFactory.swift index 498fa885d..a436f61e3 100644 --- a/Adamant/Modules/Wallets/ERC20/ERC20WalletFactory.swift +++ b/Adamant/Modules/Wallets/ERC20/ERC20WalletFactory.swift @@ -130,7 +130,8 @@ private extension ERC20WalletFactory { currencyInfo: assembler.resolve(CurrencyInfoService.self)!, addressBookService: assembler.resolve(AddressBookService.self)!, accountService: assembler.resolve(AccountService.self)!, - walletService: service + walletService: service, + languageService: assembler.resolve(LanguageStorageProtocol.self)! ) vc.service = service diff --git a/Adamant/Modules/Wallets/ERC20/ERC20WalletViewController.swift b/Adamant/Modules/Wallets/ERC20/ERC20WalletViewController.swift index 019ca4d4b..b762db830 100644 --- a/Adamant/Modules/Wallets/ERC20/ERC20WalletViewController.swift +++ b/Adamant/Modules/Wallets/ERC20/ERC20WalletViewController.swift @@ -23,14 +23,6 @@ extension String.adamant.wallets { } final class ERC20WalletViewController: WalletViewControllerBase { - // MARK: Lifecycle - - override func viewDidLoad() { - super.viewDidLoad() - - walletTitleLabel.text = String.adamant.wallets.erc20.tokenWallet(service?.tokenName ?? "") - } - override func sendRowLocalizedLabel() -> NSAttributedString { let networkSymbol = ERC20WalletService.tokenNetworkSymbol let tokenSymbol = String.adamant.wallets.erc20.sendToken(service?.tokenSymbol ?? "") @@ -56,4 +48,8 @@ final class ERC20WalletViewController: WalletViewControllerBase { override func encodeForQr(address: String) -> String? { return "ethereum:\(address)" } + + override func setTitle() { + walletTitleLabel.text = String.adamant.wallets.erc20.tokenWallet(service?.tokenName ?? "") + } } diff --git a/Adamant/Modules/Wallets/Ethereum/EthWalletFactory.swift b/Adamant/Modules/Wallets/Ethereum/EthWalletFactory.swift index e60e6771b..694c974eb 100644 --- a/Adamant/Modules/Wallets/Ethereum/EthWalletFactory.swift +++ b/Adamant/Modules/Wallets/Ethereum/EthWalletFactory.swift @@ -128,7 +128,8 @@ private extension EthWalletFactory { currencyInfo: assembler.resolve(CurrencyInfoService.self)!, addressBookService: assembler.resolve(AddressBookService.self)!, accountService: assembler.resolve(AccountService.self)!, - walletService: service + walletService: service, + languageService: assembler.resolve(LanguageStorageProtocol.self)! ) vc.service = service diff --git a/Adamant/Modules/Wallets/Ethereum/EthWalletViewController.swift b/Adamant/Modules/Wallets/Ethereum/EthWalletViewController.swift index ae755ec1a..a6948fb56 100644 --- a/Adamant/Modules/Wallets/Ethereum/EthWalletViewController.swift +++ b/Adamant/Modules/Wallets/Ethereum/EthWalletViewController.swift @@ -16,14 +16,6 @@ extension String.adamant.wallets { } final class EthWalletViewController: WalletViewControllerBase { - // MARK: Lifecycle - - override func viewDidLoad() { - super.viewDidLoad() - - walletTitleLabel.text = String.adamant.wallets.ethereum - } - override func sendRowLocalizedLabel() -> NSAttributedString { return NSAttributedString(string: String.adamant.wallets.sendEth) } @@ -31,4 +23,8 @@ final class EthWalletViewController: WalletViewControllerBase { override func encodeForQr(address: String) -> String? { return "ethereum:\(address)" } + + override func setTitle() { + walletTitleLabel.text = String.adamant.wallets.ethereum + } } diff --git a/Adamant/Modules/Wallets/Lisk/LskWalletFactory.swift b/Adamant/Modules/Wallets/Lisk/LskWalletFactory.swift index 936a03423..861fc9a2c 100644 --- a/Adamant/Modules/Wallets/Lisk/LskWalletFactory.swift +++ b/Adamant/Modules/Wallets/Lisk/LskWalletFactory.swift @@ -128,7 +128,8 @@ private extension LskWalletFactory { currencyInfo: assembler.resolve(CurrencyInfoService.self)!, addressBookService: assembler.resolve(AddressBookService.self)!, accountService: assembler.resolve(AccountService.self)!, - walletService: service + walletService: service, + languageService: assembler.resolve(LanguageStorageProtocol.self)! ) vc.service = service diff --git a/Adamant/Modules/Wallets/Lisk/LskWalletViewController.swift b/Adamant/Modules/Wallets/Lisk/LskWalletViewController.swift index 80a91c5da..af0544723 100644 --- a/Adamant/Modules/Wallets/Lisk/LskWalletViewController.swift +++ b/Adamant/Modules/Wallets/Lisk/LskWalletViewController.swift @@ -10,20 +10,16 @@ import UIKit import CommonKit extension String.adamant { - static let lisk = String.localized("AccountTab.Wallets.lisk_wallet", comment: "Account tab: Lisk wallet") + static var lisk: String { + String.localized("AccountTab.Wallets.lisk_wallet", comment: "Account tab: Lisk wallet") + } - static let sendLsk = String.localized("AccountTab.Row.SendLsk", comment: "Account tab: 'Send LSK tokens' button") + static var sendLsk: String { + String.localized("AccountTab.Row.SendLsk", comment: "Account tab: 'Send LSK tokens' button") + } } final class LskWalletViewController: WalletViewControllerBase { - // MARK: Lifecycle - - override func viewDidLoad() { - super.viewDidLoad() - - walletTitleLabel.text = String.adamant.lisk - } - override func sendRowLocalizedLabel() -> NSAttributedString { return NSAttributedString(string: String.adamant.sendLsk) } @@ -31,4 +27,8 @@ final class LskWalletViewController: WalletViewControllerBase { override func encodeForQr(address: String) -> String? { return "lisk:\(address)" } + + override func setTitle() { + walletTitleLabel.text = String.adamant.lisk + } } diff --git a/Adamant/Modules/Wallets/TransactionDetailsViewControllerBase.swift b/Adamant/Modules/Wallets/TransactionDetailsViewControllerBase.swift index 624649463..93f4637ba 100644 --- a/Adamant/Modules/Wallets/TransactionDetailsViewControllerBase.swift +++ b/Adamant/Modules/Wallets/TransactionDetailsViewControllerBase.swift @@ -33,10 +33,16 @@ private extension TransactionStatus { // MARK: - Localization extension String.adamant { - struct transactionDetails { - static let title = String.localized("TransactionDetailsScene.Title", comment: "Transaction details: scene title") - static let yourAddress = String.adamant.notifications.yourAddress - static let requestingDataProgressMessage = String.localized("TransactionDetailsScene.RequestingData", comment: "Transaction details: 'Requesting Data' progress message.") + enum transactionDetails { + static var title: String { + String.localized("TransactionDetailsScene.Title", comment: "Transaction details: scene title") + } + static var yourAddress: String { + String.adamant.notifications.yourAddress + } + static var requestingDataProgressMessage: String { + String.localized("TransactionDetailsScene.RequestingData", comment: "Transaction details: 'Requesting Data' progress message.") + } } } @@ -148,6 +154,7 @@ class TransactionDetailsViewControllerBase: FormViewController { let addressBookService: AddressBookService let accountService: AccountService let walletService: WalletService? + let languageService: LanguageStorageProtocol // MARK: - Properties @@ -169,6 +176,7 @@ class TransactionDetailsViewControllerBase: FormViewController { let dateFormatter = DateFormatter() dateFormatter.dateStyle = .medium dateFormatter.timeStyle = .short + dateFormatter.locale = Locale(identifier: languageService.getLanguage().locale) return dateFormatter }() @@ -254,13 +262,15 @@ class TransactionDetailsViewControllerBase: FormViewController { currencyInfo: CurrencyInfoService, addressBookService: AddressBookService, accountService: AccountService, - walletService: WalletService? + walletService: WalletService?, + languageService: LanguageStorageProtocol ) { self.dialogService = dialogService self.currencyInfo = currencyInfo self.addressBookService = addressBookService self.accountService = accountService self.walletService = walletService + self.languageService = languageService super.init(style: .grouped) } diff --git a/Adamant/Modules/Wallets/TransactionsListViewControllerBase.swift b/Adamant/Modules/Wallets/TransactionsListViewControllerBase.swift index ad6cf10f3..9d1ee29f8 100644 --- a/Adamant/Modules/Wallets/TransactionsListViewControllerBase.swift +++ b/Adamant/Modules/Wallets/TransactionsListViewControllerBase.swift @@ -12,13 +12,22 @@ import CommonKit import Combine extension String.adamant { - struct transactionList { - static let title = String.localized("TransactionListScene.Title", comment: "TransactionList: scene title") - static let toChat = String.localized("TransactionListScene.ToChat", comment: "TransactionList: To Chat button") - static let startChat = String.localized("TransactionListScene.StartChat", comment: "TransactionList: Start Chat button") - static let notFound = String.localized("TransactionListScene.Error.NotFound", comment: "TransactionList: 'Transactions not found' message.") - static let noTransactionYet = String.localized("TransactionListScene.NoTransactionYet", comment: "TransactionList: 'No Transaction Yet' message.") - + enum transactionList { + static var title: String { + String.localized("TransactionListScene.Title", comment: "TransactionList: scene title") + } + static var toChat: String { + String.localized("TransactionListScene.ToChat", comment: "TransactionList: To Chat button") + } + static var startChat: String { + String.localized("TransactionListScene.StartChat", comment: "TransactionList: Start Chat button") + } + static var notFound: String { + String.localized("TransactionListScene.Error.NotFound", comment: "TransactionList: 'Transactions not found' message.") + } + static var noTransactionYet: String { + String.localized("TransactionListScene.NoTransactionYet", comment: "TransactionList: 'No Transaction Yet' message.") + } } } diff --git a/Adamant/Modules/Wallets/TransferViewControllerBase.swift b/Adamant/Modules/Wallets/TransferViewControllerBase.swift index 3a3f3aa2d..13bf2e109 100644 --- a/Adamant/Modules/Wallets/TransferViewControllerBase.swift +++ b/Adamant/Modules/Wallets/TransferViewControllerBase.swift @@ -20,27 +20,46 @@ protocol TransferViewControllerDelegate: AnyObject { // MARK: - Localization extension String.adamant { - struct transfer { - static let addressPlaceholder = String.localized("TransferScene.Recipient.Placeholder", comment: "Transfer: recipient address placeholder") - static let amountPlaceholder = String.localized("TransferScene.Amount.Placeholder", comment: "Transfer: transfer amount placeholder") - - static let addressValidationError = String.localized("TransferScene.Error.InvalidAddress", comment: "Transfer: Address validation error") - static let amountZeroError = String.localized("TransferScene.Error.TooLittleMoney", comment: "Transfer: Amount is zero, or even negative notification") - static let notEnoughFeeError = String.localized("TransferScene.Error.TooLittleFee", comment: "Transfer: Not enough fee for send a transaction") - static let feeIsTooHigh = String.localized("TransferScene.Error.FeeIsTooHigh", comment: "Transfer: Fee is higher than usual") - static let amountTooHigh = String.localized("TransferScene.Error.notEnoughMoney", comment: "Transfer: Amount is hiegher that user's total money notification") - static let accountNotFound = String.localized("TransferScene.Error.AddressNotFound", comment: "Transfer: Address not found error") - - static let transferProcessingMessage = String.localized("TransferScene.SendingFundsProgress", comment: "Transfer: Processing message") - static let transferSuccess = String.localized("TransferScene.TransferSuccessMessage", comment: "Transfer: Tokens transfered successfully message") - - static let send = String.localized("TransferScene.Send", comment: "Transfer: Send button") - - static let cantUndo = String.localized("TransferScene.CantUndo", comment: "Transfer: Send button") - - static let useMaxToTransfer = String.localized("TransferScene.UseMaxToTransfer", comment: "Tranfser: Confirm using maximum available for transfer tokens as amount to transfer.") - - private init() { } + enum transfer { + static var addressPlaceholder: String { + String.localized("TransferScene.Recipient.Placeholder", comment: "Transfer: recipient address placeholder") + } + static var amountPlaceholder: String { + String.localized("TransferScene.Amount.Placeholder", comment: "Transfer: transfer amount placeholder") + } + static var addressValidationError: String { + String.localized("TransferScene.Error.InvalidAddress", comment: "Transfer: Address validation error") + } + static var amountZeroError: String { + String.localized("TransferScene.Error.TooLittleMoney", comment: "Transfer: Amount is zero, or even negative notification") + } + static var notEnoughFeeError: String { + String.localized("TransferScene.Error.TooLittleFee", comment: "Transfer: Not enough fee for send a transaction") + } + static var feeIsTooHigh: String { + String.localized("TransferScene.Error.FeeIsTooHigh", comment: "Transfer: Fee is higher than usual") + } + static var amountTooHigh: String { + String.localized("TransferScene.Error.notEnoughMoney", comment: "Transfer: Amount is hiegher that user's total money notification") + } + static var accountNotFound: String { + String.localized("TransferScene.Error.AddressNotFound", comment: "Transfer: Address not found error") + } + static var transferProcessingMessage: String { + String.localized("TransferScene.SendingFundsProgress", comment: "Transfer: Processing message") + } + static var transferSuccess: String { + String.localized("TransferScene.TransferSuccessMessage", comment: "Transfer: Tokens transfered successfully message") + } + static var send: String { + String.localized("TransferScene.Send", comment: "Transfer: Send button") + } + static var cantUndo: String { + String.localized("TransferScene.CantUndo", comment: "Transfer: Send button") + } + static var useMaxToTransfer: String { + String.localized("TransferScene.UseMaxToTransfer", comment: "Tranfser: Confirm using maximum available for transfer tokens as amount to transfer.") + } } } diff --git a/Adamant/Modules/Wallets/WalletViewControllerBase.swift b/Adamant/Modules/Wallets/WalletViewControllerBase.swift index bad99840c..5a002d179 100644 --- a/Adamant/Modules/Wallets/WalletViewControllerBase.swift +++ b/Adamant/Modules/Wallets/WalletViewControllerBase.swift @@ -9,6 +9,7 @@ import UIKit import Eureka import CommonKit +import Combine extension String.adamant { struct wallets { @@ -65,6 +66,8 @@ class WalletViewControllerBase: FormViewController, WalletViewController { return AdamantBalanceFormat.fiatFormatter(for: currencyInfoService.currentCurrency) }() + private var subscriptions = Set() + // MARK: - IBOutlets @IBOutlet weak var walletTitleLabel: UILabel! @@ -80,7 +83,8 @@ class WalletViewControllerBase: FormViewController, WalletViewController { override func viewDidLoad() { super.viewDidLoad() - + setTitle() + addObservers() tableView.tableFooterView = UIView() let section = Section() @@ -122,11 +126,13 @@ class WalletViewControllerBase: FormViewController, WalletViewController { let height = row.value?.fiat != nil ? BalanceTableViewCell.fullHeight : BalanceTableViewCell.compactHeight cell.height = { height } + cell.titleLabel.text = BaseRows.balance.localized } balanceRow.cell.selectionStyle = .gray balanceRow.cellUpdate { (cell, _) in cell.accessoryType = .disclosureIndicator + cell.titleLabel.text = BaseRows.balance.localized }.onCellSelection { [weak self] (_, _) in guard let self = self, @@ -167,6 +173,11 @@ class WalletViewControllerBase: FormViewController, WalletViewController { ? UITableView.defaultSeparatorInset : .zero + let label = self?.sendRowLocalizedLabel() + var content = cell.defaultContentConfiguration() + content.attributedText = label + cell.contentConfiguration = content + if #unavailable(iOS 14.0) { cell.textLabel?.attributedText = label } @@ -318,8 +329,9 @@ class WalletViewControllerBase: FormViewController, WalletViewController { if let wallet = service?.wallet { $0.value = wallet.address } - }.cellUpdate { (cell, _) in + }.cellUpdate { (cell, row) in cell.accessoryType = .disclosureIndicator + row.title = BaseRows.address.localized }.onCellSelection { [weak self] (cell, row) in row.deselect() let completion = { [weak self] in @@ -351,6 +363,8 @@ class WalletViewControllerBase: FormViewController, WalletViewController { return addressRow } + func setTitle() { } + // MARK: - Other private var currentUiState: WalletServiceState = .upToDate @@ -429,6 +443,17 @@ class WalletViewControllerBase: FormViewController, WalletViewController { tableView.backgroundColor = .clear initiatingActivityIndicator.color = .adamant.primary } + + private func addObservers() { + NotificationCenter.default + .publisher(for: .LanguageStorageService.languageUpdated) + .receive(on: OperationQueue.main) + .sink { [weak self] _ in + self?.tableView.reloadData() + self?.setTitle() + } + .store(in: &subscriptions) + } } // MARK: - TransferViewControllerDelegate diff --git a/Adamant/ServiceProtocols/AccountService.swift b/Adamant/ServiceProtocols/AccountService.swift index 7d40428e1..aeee07129 100644 --- a/Adamant/ServiceProtocols/AccountService.swift +++ b/Adamant/ServiceProtocols/AccountService.swift @@ -49,13 +49,20 @@ extension Notification.Name { // MARK: - Localization extension String.adamant { - struct accountService { - static let updateAlertTitleV12 = String.localized("AccountService.update.v12.title", comment: "AccountService: Alert title. Changes in version 1.2") - static let updateAlertMessageV12 = String.localized("AccountService.update.v12.message", comment: "AccountService: Alert message. Changes in version 1.2, notify user that he needs to relogin to initiate eth & lsk wallets") - static let reloginToInitiateWallets = String.localized("AccountService.reloginToInitiateWallets", comment: "AccountService: User must relogin into app to initiate wallets") + enum accountService { + static var updateAlertTitleV12: String { + String.localized("AccountService.update.v12.title", comment: "AccountService: Alert title. Changes in version 1.2") + } + static var updateAlertMessageV12: String { + String.localized("AccountService.update.v12.message", comment: "AccountService: Alert message. Changes in version 1.2, notify user that he needs to relogin to initiate eth & lsk wallets") + } + static var reloginToInitiateWallets: String { + String.localized("AccountService.reloginToInitiateWallets", comment: "AccountService: User must relogin into app to initiate wallets") + } } } + /// - loggedAccountAddress: Newly logged account's address extension AdamantUserInfoKey { struct AccountService { diff --git a/Adamant/ServiceProtocols/DialogService.swift b/Adamant/ServiceProtocols/DialogService.swift index cf2d930e4..b1ac46f21 100644 --- a/Adamant/ServiceProtocols/DialogService.swift +++ b/Adamant/ServiceProtocols/DialogService.swift @@ -10,10 +10,18 @@ import UIKit import CommonKit extension String.adamant.alert { - static let copyToPasteboard = String.localized("Shared.CopyToPasteboard", comment: "Shared alert 'Copy' button. Used anywhere. Used for copy-paste info.") - static let share = String.localized("Shared.Share", comment: "Shared alert 'Share' button. Used anywhere for presenting standart iOS 'Share' menu.") - static let generateQr = String.localized("Shared.GenerateQRCode", comment: "Shared alert 'Generate QR' button. Used to generate QR codes with addresses and passphrases. Used with sharing and saving, anywhere.") - static let saveToPhotolibrary = String.localized("Shared.SaveToPhotolibrary", comment: "Shared alert 'Save to Photos'. Used with saving images to photolibrary") + static var copyToPasteboard: String { + String.localized("Shared.CopyToPasteboard", comment: "Shared alert 'Copy' button. Used anywhere. Used for copy-paste info.") + } + static var share: String { + String.localized("Shared.Share", comment: "Shared alert 'Share' button. Used anywhere for presenting standart iOS 'Share' menu.") + } + static var generateQr: String { + String.localized("Shared.GenerateQRCode", comment: "Shared alert 'Generate QR' button. Used to generate QR codes with addresses and passphrases. Used with sharing and saving, anywhere.") + } + static var saveToPhotolibrary: String { + String.localized("Shared.SaveToPhotolibrary", comment: "Shared alert 'Save to Photos'. Used with saving images to photolibrary") + } } enum AddressChatShareType { diff --git a/Adamant/Services/LanguageService.swift b/Adamant/Services/LanguageService.swift index 572f8e24a..832c0e7f1 100644 --- a/Adamant/Services/LanguageService.swift +++ b/Adamant/Services/LanguageService.swift @@ -18,5 +18,7 @@ final class LanguageStorageService: LanguageStorageProtocol { func setLanguage(_ language: Language) { UserDefaults.standard.set(language.rawValue, forKey: StoreKey.language.language) + UserDefaults.standard.set(language.locale, forKey: StoreKey.language.languageLocale) + NotificationCenter.default.post(name: .LanguageStorageService.languageUpdated, object: nil) } } diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings index 0aafd7a0b..9b03cb2b2 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings @@ -379,6 +379,18 @@ /* Alert "Report has been sent" */ "Chats.ReportSent" = "Bericht wurde gesendet"; +/* Date "Today" */ +"Chats.Date.Today" = "Heute"; + +/* Date "Just now" */ +"Chats.Date.JustNow" = "Gerade jetzt"; + +/* Date "A minute ago" */ +"Chats.Date.MinAgo" = "Vor einer Minute"; + +/* Date "Yesterday" */ +"Chats.Date.Yesterday" = "Gestern"; + /* Chat: inform user that he can't cancel transaction, that was sent */ "ChatScene.Error.cancelError" = "Nachricht bereits versendet"; diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings index f48c46bb4..1894074a1 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings @@ -379,6 +379,18 @@ /* Alert "Report has been sent" */ "Chats.ReportSent" = "Report has been sent"; +/* Date "Today" */ +"Chats.Date.Today" = "Today"; + +/* Date "Just now" */ +"Chats.Date.JustNow" = "Just now"; + +/* Date "A minute ago" */ +"Chats.Date.MinAgo" = "A minute ago"; + +/* Date "Yesterday" */ +"Chats.Date.Yesterday" = "Yesterday"; + /* Chat: inform user that he can't cancel transaction, that was sent */ "ChatScene.Error.cancelError" = "Message is already sent"; diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings index 8f9e9cbb5..37ae6af13 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings @@ -379,6 +379,18 @@ /* Alert "Report has been sent" */ "Chats.ReportSent" = "Запрос отправлен"; +/* Date "Today" */ +"Chats.Date.Today" = "Сегодня"; + +/* Date "Just now" */ +"Chats.Date.JustNow" = "Только что"; + +/* Date "A minute ago" */ +"Chats.Date.MinAgo" = "Минуту назад"; + +/* Date "Yesterday" */ +"Chats.Date.Yesterday" = "Вчера"; + /* Chat: inform user that he can't cancel transaction, that was sent */ "ChatScene.Error.cancelError" = "Сообщение уже отправлено"; diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index ebffe446e..488ec1b93 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -305,10 +305,10 @@ "ChatListPage.SyncingChats" = "正在同步聊天…"; /* 聊天列表:已反应 */ -"ChatListPage.Rreached" = "达到"; +"ChatListPage.Reacted" = "达到"; /* 聊天列表:删除的反应 */ -"ChatListPage.RemotedReaction" = "已删除反应"; +"ChatListPage.RemovedReaction" = "已删除反应"; /* 聊天列表:场景标题 */ "ChatListPage.Title" = "聊天"; @@ -379,6 +379,18 @@ /* 警报"报告已发送" */ "Chats.ReportSent" = "报告已发送"; +/* Date "Today" */ +"Chats.Date.Today" = "今天"; + +/* Date "Just now" */ +"Chats.Date.JustNow" = "现在"; + +/* Date "A minute ago" */ +"Chats.Date.MinAgo" = "一分钟前"; + +/* Date "Yesterday" */ +"Chats.Date.Yesterday" = "昨天"; + /* 聊天:通知用户他不能取消已发送的交易 */ "ChatScene.Error.cancelError" = "消息已发送"; @@ -434,7 +446,7 @@ "ChatScene.Error.messageIsTooBig" = "消息太大。分部分发送。"; /* 代理人页面:场景标题 */ -"Delegates.Title" = "Delegates"; +"Delegates.Title" = "与会代表"; /* 可见钱包页面:场景标题 */ "VisibleWallets.Title" = "钱包列表"; @@ -677,7 +689,7 @@ "NodesEditor.TestingInProgressMessage" = "正在检查连接…"; /* NodesEditor:Scheme行 */ -"NodesEditor.SchemeRow" = "Scheme"; +"NodesEditor.SchemeRow" = "计划"; /* NodesEditor:端口行 */ "NodesEditor.PortRow" = "端口"; @@ -707,16 +719,16 @@ "SecurityPage.Row.Notifications.ModesDescription" = "####通知模式\n\n####禁用\n无通知。\n\n####后台提取\n您的设备会自动提取新消息。没有外部调用。提取由iOS启动,实际时间由操作系统根据电池电量、蜂窝网络、应用程序使用模式等许多因素确定,无法预测。可以是20分钟、6小时,甚至可能是一天。不过,您仍然可以打开应用程序并查看新消息。\n\n####推送\n ADAMANT通知服务发送到您的设备的通知。在消息发送并获得区块链批准后,您几乎会立即收到通知——延迟几秒钟。但此模式要求您的设备在服务的数据库中注册其设备令牌。设备令牌是安全的,在大多数情况下建议使用此选项。\\n\n您可以在ADAMANT的Github页面上阅读更多关于设备注册的信息。\n \n"; /* 安全性:选定的通知类型 */ -"SecurityPage.Section.NotificationsType" = "Notifications"; +"SecurityPage.Section.NotificationsType" = "通知"; /* 安全性:关于通知类型 */ "SecurityPage.Section.AboutNotificationTypes" = "关于ANS"; /* 安全:消息通知声音 */ -"SecurityPage.Section.Messages" = "Messages"; +"SecurityPage.Section.Messages" = "信息"; /* 安全:设置通知 */ -"SecurityPage.Section.Settings" = "Settings"; +"SecurityPage.Section.Settings" = "设置"; /* 通知:禁用通知 */ "Notifications.Mode.NotificationsDisabled" = "已禁用"; @@ -737,10 +749,10 @@ "Notifications.Sound.Name" = "声音"; /* 通知:选择声音 */ -"Notifications.Sounds.Name" = "Sounds"; +"Notifications.Sounds.Name" = "声音"; /* 通知:选择提醒音调 */ -"Notifications.Alert.Tones" = "Alert Tones"; +"Notifications.Alert.Tones" = "警报音"; /* 通知:选择警报保存 */ "Notifications.Alert.Save" = "保存"; @@ -752,7 +764,7 @@ "Pinpad.EnterNewPin" = "输入新的PIN码"; /* Pinpad:要求用户重复新引脚 */ -"Pinpad.RenerPin" = "重新输入您的PIN码"; +"Pinpad.ReenterPin" = "重新输入您的PIN码"; /* QRGenerator:错误的内部生成器错误消息格式。使用%@作为错误描述 */ "QrGeneratorScene.Error.InteralErrorFormat" = "内部错误:%@。报告错误"; diff --git a/CommonKit/Sources/CommonKit/Core/SecuredStore.swift b/CommonKit/Sources/CommonKit/Core/SecuredStore.swift index decb1f1be..8a7a3d920 100644 --- a/CommonKit/Sources/CommonKit/Core/SecuredStore.swift +++ b/CommonKit/Sources/CommonKit/Core/SecuredStore.swift @@ -54,6 +54,7 @@ public extension StoreKey { enum language { public static let language = "language" + public static let languageLocale = "language.locale" } } diff --git a/CommonKit/Sources/CommonKit/Helpers/Date+adamant.swift b/CommonKit/Sources/CommonKit/Helpers/Date+adamant.swift index 3f32ed5c6..a0a95b8b6 100644 --- a/CommonKit/Sources/CommonKit/Helpers/Date+adamant.swift +++ b/CommonKit/Sources/CommonKit/Helpers/Date+adamant.swift @@ -17,31 +17,41 @@ public extension Date { /// Returns readable date with time. func humanizedDateTime(withWeekday: Bool = true) -> String { + let formatter = defaultFormatter + if year == Date().year { let dateString: String if isToday { - dateString = NSLocalizedString("Today", tableName: "DateTools", bundle: Bundle.dateToolsBundle(), comment: "") + dateString = String.localized("Chats.Date.Today") } else if daysAgo < 2 { /* We can't use 'self.timeAgoSinceNow' here, because after midnight, when it is already not 'isToday', but less than 24 hours has passed, so it is technically not 'Yesterday' yet, it will display something like '6 hours ago' */ - dateString = NSLocalizedString("Yesterday", tableName: "DateTools", bundle: Bundle.dateToolsBundle(), comment: "") + dateString = String.localized("Chats.Date.Yesterday") } else if withWeekday && weeksAgo < 1 { // This week, show weekday, month and date dateString = Date.formatterWeekDayMonth.string(from: self) } else { // This year, long ago: show month and date dateString = Date.formatterDayMonth.string(from: self) } - return "\(dateString), \(DateFormatter.localizedString(from: self, dateStyle: .none, timeStyle: .short))" - } else { - return DateFormatter.localizedString(from: self, dateStyle: .medium, timeStyle: .short) + formatter.dateStyle = .none + formatter.timeStyle = .short + + return "\(dateString), \(formatter.string(from: self))" } + + formatter.dateStyle = .medium + formatter.timeStyle = .short + return formatter.string(from: self) } func humanizedDateTimeFull() -> String { - return DateFormatter.localizedString(from: self, dateStyle: .long, timeStyle: .short) + let formatter = defaultFormatter + formatter.dateStyle = .long + formatter.timeStyle = .short + return formatter.string(from: self) } /// Returns readable day string. "Today, Yesterday, etc" @@ -49,7 +59,7 @@ public extension Date { let dateString: String if isToday { // Today - dateString = NSLocalizedString("Today", tableName: "DateTools", bundle: Bundle.dateToolsBundle(), comment: "") + dateString = String.localized("Chats.Date.Today") } else if daysAgo < 2 { // Yesterday dateString = self.timeAgoSinceNow } else if weeksAgo < 1 { // This week, show weekday, month and date @@ -71,10 +81,10 @@ public extension Date { let seconds = secondsAgo if seconds < 30 { - timeString = NSLocalizedString("Just now", tableName: "DateTools", bundle: Bundle.dateToolsBundle(), comment: "") + timeString = String.localized("Chats.Date.JustNow") expire = TimeInterval(30 - seconds) } else if seconds < 90 { - timeString = NSLocalizedString("A minute ago", tableName: "DateTools", bundle: Bundle.dateToolsBundle(), comment: "") + timeString = String.localized("Chats.Date.MinAgo") expire = TimeInterval(60 - (seconds % 60)) } else if minutesAgo < 5 { timeString = timeAgoSinceNow @@ -90,15 +100,29 @@ public extension Date { // MARK: Formatters - private static let formatterWeekDayMonth: DateFormatter = { + private static var formatterWeekDayMonth: DateFormatter { let formatter = DateFormatter() + if let localeRaw = UserDefaults.standard.string(forKey: StoreKey.language.languageLocale) { + formatter.locale = Locale(identifier: localeRaw) + } formatter.setLocalizedDateFormatFromTemplate("MMMMEEEEd") return formatter - }() + } - private static let formatterDayMonth: DateFormatter = { + private static var formatterDayMonth: DateFormatter { let formatter = DateFormatter() + if let localeRaw = UserDefaults.standard.string(forKey: StoreKey.language.languageLocale) { + formatter.locale = Locale(identifier: localeRaw) + } formatter.setLocalizedDateFormatFromTemplate("MMMMd") return formatter - }() + } + + private var defaultFormatter: DateFormatter { + let formatter = DateFormatter() + if let localeRaw = UserDefaults.standard.string(forKey: StoreKey.language.languageLocale) { + formatter.locale = Locale(identifier: localeRaw) + } + return formatter + } } diff --git a/CommonKit/Sources/CommonKit/Localization/AdamantLocalized+Notifications.swift b/CommonKit/Sources/CommonKit/Localization/AdamantLocalized+Notifications.swift index da97169d5..3f40daa77 100644 --- a/CommonKit/Sources/CommonKit/Localization/AdamantLocalized+Notifications.swift +++ b/CommonKit/Sources/CommonKit/Localization/AdamantLocalized+Notifications.swift @@ -9,10 +9,12 @@ public extension String.adamant { enum notifications { // MARK: - Content extensions error - public static let error = String.localized( - "content.error", - comment: "Notification content: error working with transaction" - ) + public static var error: String { + String.localized( + "content.error", + comment: "Notification content: error working with transaction" + ) + } public static func error(with message: String) -> String { String.localizedStringWithFormat( @@ -26,10 +28,12 @@ public extension String.adamant { // MARK: - Transfer preview - public static let newTransfer = String.localized( - "transfer.notificationTitle", - comment: "New transfer notification title" - ) + public static var newTransfer: String { + String.localized( + "transfer.notificationTitle", + comment: "New transfer notification title" + ) + } public static func yourTransferBody(with amount: String) -> String { String.localizedStringWithFormat( @@ -41,9 +45,11 @@ public extension String.adamant { ) } - public static let yourAddress = String.localized( - "transfer.notificationBody.yourAddress", - comment: "Transfer notification: 'Your address'" - ) + public static var yourAddress: String { + String.localized( + "transfer.notificationBody.yourAddress", + comment: "Transfer notification: 'Your address'" + ) + } } } From ffc037adedc1f5e2518bb1ce796c11d713dfce00 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS <99971092+StanislavDevIOS@users.noreply.github.com> Date: Fri, 12 Jan 2024 12:58:31 +0200 Subject: [PATCH 09/27] Update CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings Co-authored-by: adamant-al <33592982+adamant-al@users.noreply.github.com> --- .../CommonKit/Assets/Localization/zh.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index 8e02d64e4..a6cc4df2b 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -53,7 +53,7 @@ "Contribute.Section.DonateDescription" = "每一次捐赠都让ADAMANT变得更强大"; /* 贡献场景:"速率"部分标题 */ -"Contribute.Section.Rate" = "在app Store中对应用进行评分"; +"Contribute.Section.Rate" = "在App Store中对应用进行评分"; /* 贡献场景:"速率"部分描述 */ "Contribute.Section.RateDescription" = "反馈越多,应用程序的可见性越好。突出显示您喜欢的功能"; From 27fd4187edcd36e2755d89defa3804e50c464e74 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS <99971092+StanislavDevIOS@users.noreply.github.com> Date: Fri, 12 Jan 2024 12:58:57 +0200 Subject: [PATCH 10/27] Update CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings Co-authored-by: adamant-al <33592982+adamant-al@users.noreply.github.com> --- .../CommonKit/Assets/Localization/zh.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index a6cc4df2b..e3bc6fb30 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -80,7 +80,7 @@ "About.Row.Website.Url" = "https://adamant.im"; /* "关于场景:白皮书本地化url" */ -"About.Row.Whitepaper.Url" = "https://adamant.im/whitepaper/adamant-whitepaper-en.pdf"; +"About.Row.Whitepaper.Url" = "https://adamant.im/whitepaper/adamant-whitepaper-cn.pdf"; /* "关于场景:Project的GitHub页面本地化url" */ "About.Row.GitHub.Url" = "https://github.com/Adamant-im"; From a5715828ce75a93fbbf441c8e48b7a47b6211853 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS <99971092+StanislavDevIOS@users.noreply.github.com> Date: Fri, 12 Jan 2024 12:59:04 +0200 Subject: [PATCH 11/27] Update CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings Co-authored-by: adamant-al <33592982+adamant-al@users.noreply.github.com> --- .../CommonKit/Assets/Localization/zh.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index e3bc6fb30..72e60dcdb 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -92,7 +92,7 @@ "About.Row.Twitter.Url" = "https://twitter.com/adamant_im"; /* 关于场景:写入Adamant行 */ -"About.Row.Adamant" = "Adamant"; +"About.Row.Adamant" = "ADAMANT"; /* 关于场景:显示欢迎屏幕 */ "About.Row.Welcome" = "欢迎屏幕"; From ca42faa3a0a7280d96d796212df8a510f85b3279 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS <99971092+StanislavDevIOS@users.noreply.github.com> Date: Fri, 12 Jan 2024 12:59:12 +0200 Subject: [PATCH 12/27] Update CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings Co-authored-by: adamant-al <33592982+adamant-al@users.noreply.github.com> --- .../CommonKit/Assets/Localization/zh.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index 72e60dcdb..10fc85bd8 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -227,7 +227,7 @@ "AccountTab.Section.Application" = "应用"; /* 账户选项卡:阿达曼钱包 */ -"AccountTab.Wallets.adamant_wallet" = "adamant钱包"; +"AccountTab.Wallets.adamant_wallet" = "ADAMANT钱包"; /* 账户选项卡:以太坊钱包 */ "AccountTab.Wallets.ethereum_wallet" = "以太坊钱包"; From 4c725c8e9ace0f5471a2cfe8dc3a42a08220eb4f Mon Sep 17 00:00:00 2001 From: StanislavDevIOS <99971092+StanislavDevIOS@users.noreply.github.com> Date: Fri, 12 Jan 2024 12:59:20 +0200 Subject: [PATCH 13/27] Update CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings Co-authored-by: adamant-al <33592982+adamant-al@users.noreply.github.com> --- .../CommonKit/Assets/Localization/zh.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index 10fc85bd8..6a7b43965 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -233,7 +233,7 @@ "AccountTab.Wallets.ethereum_wallet" = "以太坊钱包"; /* 账户选项卡:Lisk钱包 */ -"AccountTab.Wallets.lisk_vallet" = "lisk钱包"; +"AccountTab.Wallets.lisk_vallet" = "Lisk钱包"; /* 账户选项卡:比特币钱包 */ "AccountTab.Wallets.bitcoin_wallet" = "比特币钱包"; From 578e0c184e110cfe20935ec1e4cfe4e8fe67b6af Mon Sep 17 00:00:00 2001 From: StanislavDevIOS <99971092+StanislavDevIOS@users.noreply.github.com> Date: Fri, 12 Jan 2024 12:59:53 +0200 Subject: [PATCH 14/27] Update CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings Co-authored-by: adamant-al <33592982+adamant-al@users.noreply.github.com> --- .../CommonKit/Assets/Localization/zh.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index 6a7b43965..7eaed272f 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -326,7 +326,7 @@ "Chats.PreIcoMessage" = "Null"; /* 已知联系人:Adamant欢迎信息。支持降价 */ -"Chats.WelcomeMessage" = "ADAMANT是一个真正的区块链信使,独立于政府、企业甚至开发商。这是由于去中心化的网络基础设施,完全开源,由用户运行。这就是为什么每一个动作,包括发送消息或保存联系人姓名,都有0.001 ADM的网络费用。\n\nBlockchain提供了卓越的安全性和隐私,这是典型的P2P和c集中的信使。此外,区块链提供了新的可能性。您可以在聊天中存储和传输密码,并完全控制您的私钥,使用ADAMANT作为2FA等。\\n\nADAMANT中,没有人可以控制、阻止、停用、限制或审查帐户。用户对内容、消息、媒体以及使用Messenger的目标和意图承担全部责任。\\n\n请注意,您的安全性和匿名性取决于您。不要关注你收到的链接,否则你的IP可能会被泄露。在设备上设置密码。了解有关安全性和匿名性的更多信息,请访问https://adamant.im/staysecured/.\\n\n请确保已保存此帐户的密码短语--注销并再次登录。把你的通行证短语也写在纸上。只有**您对通行证短语的安全负责**。它无法恢复。如果其他人得到了它,你的代币就会被盗,信件也会被读取。把这个问题看得最重要,就好像你钱包里的代币在一段时间内会花费10亿美元一样。\\n\n若要立即开始发送消息,请在\"帐户\"选项卡上**获得免费欢迎令牌**。然后创建新聊天并输入您朋友的ADM地址。建议您亲自分享ADM地址,不要使用其他信使。"; +"Chats.WelcomeMessage" = "ADAMANT是一个真正的区块链信使,独立于政府、企业甚至开发商。这是由于去中心化的网络基础设施,完全开源,由用户运行。这就是为什么每一个动作,包括发送消息或保存联系人姓名,都有0.001 ADM的网络费用。\n\nBlockchain提供了卓越的安全性和隐私,这是典型的P2P和c集中的信使。此外,区块链提供了新的可能性。您可以在聊天中存储和传输密码,并完全控制您的私钥,使用ADAMANT作为2FA等。\n\nADAMANT中,没有人可以控制、阻止、停用、限制或审查帐户。用户对内容、消息、媒体以及使用Messenger的目标和意图承担全部责任。\n\n请注意,您的安全性和匿名性取决于您。不要关注你收到的链接,否则你的IP可能会被泄露。在设备上设置密码。了解有关安全性和匿名性的更多信息,请访问https://adamant.im/staysecured/.\n\n请确保已保存此帐户的密码短语--注销并再次登录。把你的通行证短语也写在纸上。只有**您对通行证短语的安全负责**。它无法恢复。如果其他人得到了它,你的代币就会被盗,信件也会被读取。把这个问题看得最重要,就好像你钱包里的代币在一段时间内会花费10亿美元一样。\n\n若要立即开始发送消息,请在\"帐户\"选项卡上**获得免费欢迎令牌**。然后创建新聊天并输入您朋友的ADM地址。建议您亲自分享ADM地址,不要使用其他信使。"; /* 已知联系人:Adamant Exchenge消息。支持降价 */ "Chats.Exchange.WellomeMessage" = "嗨!😊 我是你的交换机器人。我即时匿名操作。键入* */help**看看我能做些什么。我要求的费用比我的机器人同伴高,所以我建议你以有竞争力的费用建立自己的机器人。ℹ️ 你可以在ADAMANT博客上了解更多信息。我非常可靠,但如果您有任何问题,请在这里留言U6386412615727665758。"; From 70b47f7ec3e6ffa2d5d0e5c7d7ff249acfea26c2 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS <99971092+StanislavDevIOS@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:00:14 +0200 Subject: [PATCH 15/27] Update CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings Co-authored-by: adamant-al <33592982+adamant-al@users.noreply.github.com> --- .../CommonKit/Assets/Localization/zh.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index 7eaed272f..7f08b91b3 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -329,7 +329,7 @@ "Chats.WelcomeMessage" = "ADAMANT是一个真正的区块链信使,独立于政府、企业甚至开发商。这是由于去中心化的网络基础设施,完全开源,由用户运行。这就是为什么每一个动作,包括发送消息或保存联系人姓名,都有0.001 ADM的网络费用。\n\nBlockchain提供了卓越的安全性和隐私,这是典型的P2P和c集中的信使。此外,区块链提供了新的可能性。您可以在聊天中存储和传输密码,并完全控制您的私钥,使用ADAMANT作为2FA等。\n\nADAMANT中,没有人可以控制、阻止、停用、限制或审查帐户。用户对内容、消息、媒体以及使用Messenger的目标和意图承担全部责任。\n\n请注意,您的安全性和匿名性取决于您。不要关注你收到的链接,否则你的IP可能会被泄露。在设备上设置密码。了解有关安全性和匿名性的更多信息,请访问https://adamant.im/staysecured/.\n\n请确保已保存此帐户的密码短语--注销并再次登录。把你的通行证短语也写在纸上。只有**您对通行证短语的安全负责**。它无法恢复。如果其他人得到了它,你的代币就会被盗,信件也会被读取。把这个问题看得最重要,就好像你钱包里的代币在一段时间内会花费10亿美元一样。\n\n若要立即开始发送消息,请在\"帐户\"选项卡上**获得免费欢迎令牌**。然后创建新聊天并输入您朋友的ADM地址。建议您亲自分享ADM地址,不要使用其他信使。"; /* 已知联系人:Adamant Exchenge消息。支持降价 */ -"Chats.Exchange.WellomeMessage" = "嗨!😊 我是你的交换机器人。我即时匿名操作。键入* */help**看看我能做些什么。我要求的费用比我的机器人同伴高,所以我建议你以有竞争力的费用建立自己的机器人。ℹ️ 你可以在ADAMANT博客上了解更多信息。我非常可靠,但如果您有任何问题,请在这里留言U6386412615727665758。"; +"Chats.Exchange.WelcomeMessage" = "嗨!😊 我是你的交换机器人。我即时匿名操作。键入* */help**看看我能做些什么。我要求的费用比我的机器人同伴高,所以我建议你以有竞争力的费用建立自己的机器人。ℹ️ 你可以在ADAMANT博客上了解更多信息。我非常可靠,但如果您有任何问题,请在这里留言U6386412615727665758。"; /* 已知联系人:Adamant押注比特币消息。支持降价 */ "Chats.BetOnBitcoin.WelcomeMessage" = "嗨!😊 我是匿名的,区块链验证的投注机器人。我接受BTC费率的投注,并向中奖者支付奖励。ℹ️ 在ADAMANT的博客上了解更多信息,或键入* */help**开始下注。通过U63864126157276665758提供支持。"; From 6f0984036e181a954c97897993abcdeac0201384 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS <99971092+StanislavDevIOS@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:00:23 +0200 Subject: [PATCH 16/27] Update CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings Co-authored-by: adamant-al <33592982+adamant-al@users.noreply.github.com> --- .../CommonKit/Assets/Localization/zh.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index 7f08b91b3..00b41180b 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -338,7 +338,7 @@ "Chats.Adelina.WelcomeMessage" = "你好,我是Adelina。让我们愉快地交谈一下!我可以做很多事情,比如:\n\n-起草电子邮件或其他文章\n-编写Python代码\n-回答关于一组文档的问题\n-支持对话\n-一系列主题的导师\n-翻译语言\n-写诗\n-模拟电子游戏中的角色等等"; /* 已知联系人:阿达曼捐赠欢迎信息。支持降价 */ -"Chats.Donate.WellomeMessage" = "感谢您的支持,我们开发了去中心化的ADAMANT Messenger——在此聊天中转移ADM、ETH和其他代币。有关其他捐赠钱包,请参阅consided.im。"; +"Chats.Donate.WelcomeMessage" = "感谢您的支持,我们开发了去中心化的ADAMANT Messenger——在此聊天中转移ADM、ETH和其他代币。有关其他捐赠钱包,请参阅adamant.im。"; /* 警报"重试或删除"标题。在caht中用于再次发送或删除失败的消息 */ "Chats.RetryOrDelete.Title" = "重试还是删除?"; From 9beb08f00441f72f218dd293676ae1949e3f0f6f Mon Sep 17 00:00:00 2001 From: StanislavDevIOS <99971092+StanislavDevIOS@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:00:31 +0200 Subject: [PATCH 17/27] Update CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings Co-authored-by: adamant-al <33592982+adamant-al@users.noreply.github.com> --- .../CommonKit/Assets/Localization/zh.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index 00b41180b..55cf0d530 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -698,7 +698,7 @@ "NodesEditor.FailedToBuildURL" = "无效主机"; /* 安全性:通知模式说明。支持降价 */ -"SecurityPage.Row.Notifications.ModesDescription" = "####通知模式\n\n####禁用\n无通知。\n\n####后台提取\n您的设备会自动提取新消息。没有外部调用。提取由iOS启动,实际时间由操作系统根据电池电量、蜂窝网络、应用程序使用模式等许多因素确定,无法预测。可以是20分钟、6小时,甚至可能是一天。不过,您仍然可以打开应用程序并查看新消息。\n\n####推送\n ADAMANT通知服务发送到您的设备的通知。在消息发送并获得区块链批准后,您几乎会立即收到通知——延迟几秒钟。但此模式要求您的设备在服务的数据库中注册其设备令牌。设备令牌是安全的,在大多数情况下建议使用此选项。\\n\n您可以在ADAMANT的Github页面上阅读更多关于设备注册的信息。\n \n"; +"SecurityPage.Row.Notifications.ModesDescription" = "####通知模式\n\n####禁用\n无通知。\n\n####后台提取\n您的设备会自动提取新消息。没有外部调用。提取由iOS启动,实际时间由操作系统根据电池电量、蜂窝网络、应用程序使用模式等许多因素确定,无法预测。可以是20分钟、6小时,甚至可能是一天。不过,您仍然可以打开应用程序并查看新消息。\n\n####推送\n ADAMANT通知服务发送到您的设备的通知。在消息发送并获得区块链批准后,您几乎会立即收到通知——延迟几秒钟。但此模式要求您的设备在服务的数据库中注册其设备令牌。设备令牌是安全的,在大多数情况下建议使用此选项。\n\n您可以在ADAMANT的GitHub页面上阅读更多关于设备注册的信息。\n\n"; /* 安全性:选定的通知类型 */ "SecurityPage.Section.NotificationsType" = "Notifications"; From 519b58707d97c0f17b0527579c320b668185c8ff Mon Sep 17 00:00:00 2001 From: StanislavDevIOS <99971092+StanislavDevIOS@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:00:42 +0200 Subject: [PATCH 18/27] Update CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings Co-authored-by: adamant-al <33592982+adamant-al@users.noreply.github.com> --- .../CommonKit/Assets/Localization/zh.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index 55cf0d530..a3d5a45e2 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -1124,7 +1124,7 @@ "EULA.Title" = "服务条款"; "EULA.Accept" = "接受"; "EULA.Decline" = "拒绝"; -"EULA.Text" = "ADAMANT Messenger基于去中心化的区块链技术,因此:\n\n✓ ADAMANT Messenger不容忍令人反感的内容或辱骂用户\n✓ ADAMANT Messenger最初专注于通信的安全性和用户的隐私。\n✓ ADAMANT Messenger始终显示完全开源的代码,许可证为GPL-3.0。源代码可在GitHub:GitHub.com/stend-im上获得。\n✓ ADAMANT Messenger按\"原样\"提供,不提供任何担保。\n✓ 开发人员只是ADAMANT Messenger的贡献者和用户。\n✓ 开发人员不控制用户的任何操作。\n✓ 开发人员在ADAMANT Messenger中没有权限。\n✓ 开发人员不可能禁用或阻止ADAMANT Messenger中的任何帐户。\n✓ 开发人员不可能获得加密密钥或读取任何ADAMANT Messenger用户的通信或其他信息。\n✓ 如果丢失,开发人员不可能恢复对任何用户帐户的访问。用户有责任保护自己的帐户的安全。\n✓ 开发人员不对用户内容、消息、媒体以及使用ADAMANT Messenger的目标和意图负责。\n✓ 开发者不存储用户之间传输的任何信息(消息、多媒体),也不对其在区块链上/中的存储负责。\n✓ 开发者不可能访问,也不对连接到ADAMANT Messenger或通过ADAMANT信使发送的任何资产(包括但不限于:加密货币)负责。\n✓ ADAMANT Messenger利用元数据作为账户之间通信的事实,在其区块链中公开提供。\n✓ 开发者不与任何第三方或外部服务合作提供任何使用数据。\n✓ ADAMANT信使基础设施(区块链节点)属于其用户,由用户运行。\n✓ 开发人员不可能停用、停止或暂停ADAMANT Messenger。开发人员对ADAMANT Messenger的运行不提供任何保证。\n✓ 开发人员不承担与ADAMANT Messenger相关的可能风险、成本和故障。\n✓ ADAMANT Messenger的用户从此对其使用承担全部责任,包括但不限于:区块链和Messenger内应用的其他技术的合法性,使用匿名消息服务,以及其他管辖法律。\\n\n通过使用ADAMANT Messenger,您从此接受这些服务条款。"; +"EULA.Text" = "ADAMANT Messenger基于去中心化的区块链技术,因此:\n\n✓ ADAMANT Messenger不容忍令人反感的内容或辱骂用户\n✓ ADAMANT Messenger最初专注于通信的安全性和用户的隐私。\n✓ ADAMANT Messenger始终显示完全开源的代码,许可证为GPL-3.0。源代码可在GitHub:GitHub.com/stend-im上获得。\n✓ ADAMANT Messenger按\"原样\"提供,不提供任何担保。\n✓ 开发人员只是ADAMANT Messenger的贡献者和用户。\n✓ 开发人员不控制用户的任何操作。\n✓ 开发人员在ADAMANT Messenger中没有权限。\n✓ 开发人员不可能禁用或阻止ADAMANT Messenger中的任何帐户。\n✓ 开发人员不可能获得加密密钥或读取任何ADAMANT Messenger用户的通信或其他信息。\n✓ 如果丢失,开发人员不可能恢复对任何用户帐户的访问。用户有责任保护自己的帐户的安全。\n✓ 开发人员不对用户内容、消息、媒体以及使用ADAMANT Messenger的目标和意图负责。\n✓ 开发者不存储用户之间传输的任何信息(消息、多媒体),也不对其在区块链上/中的存储负责。\n✓ 开发者不可能访问,也不对连接到ADAMANT Messenger或通过ADAMANT信使发送的任何资产(包括但不限于:加密货币)负责。\n✓ ADAMANT Messenger利用元数据作为账户之间通信的事实,在其区块链中公开提供。\n✓ 开发者不与任何第三方或外部服务合作提供任何使用数据。\n✓ ADAMANT信使基础设施(区块链节点)属于其用户,由用户运行。\n✓ 开发人员不可能停用、停止或暂停ADAMANT Messenger。开发人员对ADAMANT Messenger的运行不提供任何保证。\n✓ 开发人员不承担与ADAMANT Messenger相关的可能风险、成本和故障。\n✓ ADAMANT Messenger的用户从此对其使用承担全部责任,包括但不限于:区块链和Messenger内应用的其他技术的合法性,使用匿名消息服务,以及其他管辖法律。\n\n通过使用ADAMANT Messenger,您从此接受这些服务条款。"; /* 回复:未知短信错误 */ "Reply.ShortUnknownMessageError" = "未知消息"; From a178af6fb88628875f3da09d984349a8bd11a4d5 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS <99971092+StanislavDevIOS@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:00:49 +0200 Subject: [PATCH 19/27] Update CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings Co-authored-by: adamant-al <33592982+adamant-al@users.noreply.github.com> --- .../CommonKit/Assets/Localization/zh.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index a3d5a45e2..fbf793feb 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -1106,7 +1106,7 @@ "WelcomeScene.Description.Slide4" = "无需任何要求即可单击**创建帐户**(无需电子邮件/电话/任何内容)并邀请您的朋友。\n\n为了真正的安全起见,请亲自**共享您的ADAMANT地址。"; /* 欢迎:幻灯片5说明 */ -"WelcomeScene.Description.Slide5" = "项目的源代码[完全开放](https://github.com/Adamant-im/).该应用程序正在开发中,我们不断添加新功能。\\n\n如果您是开发人员,请加入我们的团队。"; +"WelcomeScene.Description.Slide5" = "项目的源代码[完全开放](https://github.com/Adamant-im/).该应用程序正在开发中,我们不断添加新功能。\n\n如果您是开发人员,请加入我们的团队。"; /* 欢迎场景。描述开始按钮 */ "WelcomeScene.Description.BeginButton" = "启动安全消息"; From 7e4d811946fee1dcc19d629ee7ce6df6ae61bad0 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS <99971092+StanislavDevIOS@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:01:03 +0200 Subject: [PATCH 20/27] Update CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings Co-authored-by: adamant-al <33592982+adamant-al@users.noreply.github.com> --- .../CommonKit/Assets/Localization/zh.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index fbf793feb..7856cd37e 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -722,7 +722,7 @@ "Notifications.Mode.ApplePush" = "推送"; /* 安全:访问Github */ -"SecurityPage.Row.VisitGithub" = "访问Github"; +"SecurityPage.Row.VisitGithub" = "访问GitHub"; /* 通知:打开系统设置 */ "Notifications.Settings.System" = "系统设置"; From 3a769f8f748bcee75dca59801d18afed1fa3595f Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Fri, 12 Jan 2024 18:13:51 +0200 Subject: [PATCH 21/27] [trello.com/c/yd3JjZ1f] fix: zh localization --- .../Localization/zh.lproj/Localizable.strings | 824 +++++++++--------- 1 file changed, 412 insertions(+), 412 deletions(-) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index 7856cd37e..0ee065d65 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -1,1145 +1,1145 @@ -/* 通知内容:处理事务时出错 */ +/* Notification content: error working with transaction */ "content.error" = "出现问题!"; -/* 通知内容:错误格式 */ +/* Notification content: error format */ "content.error.format" = "出现问题:%@"; -/* 新的转移通知标题 */ +/* New transfer notification title */ "transfer.notificationTitle" = "新转让"; -/* 转移通知正文格式 */ +/* Transfer notification body format */ "transfer.notificationBody.format" = "用户已将您%@"; -/* 转账通知:"您的地址" */ +/* Transfer notification: 'Your address' */ "transfer.notificationBody.yourAddress" = "您"; -/* 关于页面:场景标题 */ +/* About page: scene title */ "About.Title" = "关于"; -/* 关于场景:"阅读"部分标题 */ +/* About scene: 'Read about' section title. */ "About.Section.About" = "关于ADAMANT"; -/* 关于场景:"联系我们"部分标题 */ +/* About scene: 'Contact us' section title. */ "About.Section.ContactUs" = "联系我们"; -/* 贡献场景:"Crashlytics"部分标题 */ +/* Contribute scene: 'Crashlytics' section title. */ "Contribute.Section.Crashlytics" = "Crashlytics"; -/* 贡献场景:"Crashlytics"部分描述 */ +/* Contribute scene: 'Crashlytics' section description. */ "Contribute.Section.CrashlyticsDescription" = "发送匿名崩溃报告,使应用程序更加可靠。我们不收集使用统计信息。"; -/* 贡献场景:"运行节点"部分标题 */ +/* Contribute scene: 'Run nodes' section title. */ "Contribute.Section.RunNodes" = "运行ADAMANT节点"; -/* 贡献场景:"运行节点"部分描述 */ +/* Contribute scene: 'Run nodes' section description. */ "Contribute.Section.RunNodesDescription" = "支持去中心化,提高隐私级别"; -/* 贡献场景:"网络代理"部分标题 */ +/* Contribute scene: 'Network delegate' section title. */ "Contribute.Section.NetworkDelegate" = "成为网络代表"; -/* 贡献场景:"网络代理"部分描述 */ +/* Contribute scene: 'Network delegate' section description. */ "Contribute.Section.NetworkDelegateDescription" = "要成为代表,请支付注册费并获得选民的支持"; -/* 贡献场景:"代码贡献"部分标题 */ +/* Contribute scene: 'Code contribute' section title. */ "Contribute.Section.CodeContribute" = "为代码贡献力量"; -/* 贡献场景:"代码贡献"部分描述 */ +/* Contribute scene: 'Code contribute' section description. */ "Contribute.Section.CodeContributeDescription" = "如果您是开发人员,请加入我们的GitHub存储库"; -/* 贡献场景:"捐赠"部分标题 */ +/* Contribute scene: 'Donate' section title. */ "Contribute.Section.Donate" = "捐赠"; -/* 贡献场景:"捐赠"部分描述 */ +/* Contribute scene: 'Donate' section description. */ "Contribute.Section.DonateDescription" = "每一次捐赠都让ADAMANT变得更强大"; -/* 贡献场景:"速率"部分标题 */ +/* Contribute scene: 'Rate' section title. */ "Contribute.Section.Rate" = "在App Store中对应用进行评分"; -/* 贡献场景:"速率"部分描述 */ +/* Contribute scene: 'Rate' section description. */ "Contribute.Section.RateDescription" = "反馈越多,应用程序的可见性越好。突出显示您喜欢的功能"; -/* 关于场景:网站行 */ +/* About scene: Website row */ "About.Row.Website" = "网站"; -/* 关于场景:白皮书行 */ +/* About scene: The Whitepaper row */ "About.Row.Whitepaper" = "白皮书"; -/* 关于场景:Project的GitHub页面行 */ +/* About scene: Project's GitHub page row */ "About.Row.GitHub" = "项目的GitHub页面"; -/* 关于场景:给我们写一行 */ +/* About scene: Write us row */ "About.Row.WriteUs" = "电子邮件"; -/* 关于场景:我们的博客行 */ +/* About scene: Our blog row */ "About.Row.Blog" = "我们的博客"; -/* 关于场景:推特排 */ +/* About scene: Twitter row */ "About.Row.Twitter" = "推特"; -/* "关于场景:网站本地化url" */ +/* "About scene: Website localized url" */ "About.Row.Website.Url" = "https://adamant.im"; -/* "关于场景:白皮书本地化url" */ +/* "About scene: The Whitepaper localized url" */ "About.Row.Whitepaper.Url" = "https://adamant.im/whitepaper/adamant-whitepaper-cn.pdf"; -/* "关于场景:Project的GitHub页面本地化url" */ +/* "About scene: Project's GitHub page localized url" */ "About.Row.GitHub.Url" = "https://github.com/Adamant-im"; -/* "关于场景:我们的博客本地化url" */ +/* "About scene: Our blog localized url" */ "About.Row.Blog.Url" = "https://medium.com/adamant-im"; -/* "关于场景:Twitter本地化url" */ +/* "About scene: Twitter localized url" */ "About.Row.Twitter.Url" = "https://twitter.com/adamant_im"; -/* 关于场景:写入Adamant行 */ +/* About scene: Write to Adamant row */ "About.Row.Adamant" = "ADAMANT"; -/* 关于场景:显示欢迎屏幕 */ +/* About scene: Show Welcome screens */ "About.Row.Welcome" = "欢迎屏幕"; -/* 帐户选项卡:"货币"行 */ +/* Account tab: 'Currency' row */ "AccountTab.Row.Currency" = "货币"; -/* 系统帐户:ADAMANT令牌 */ +/* System accounts: ADAMANT Tokens */ "Accounts.AdamantTokens" = "欢迎使用ADAMANT"; -/* 系统帐户:PWA ADM Bounty机器人 */ -"Accounts.AdamantBountyBot" = "ADAMANT Bounty Bot"; +/* System accounts: PWA ADM Bounty bot */ +"Accounts.AdamantBountyBot" = "ADAMANT 赏金机器人"; -/* 系统帐户:ADAMANT Bounty */ +/* System accounts: ADAMANT Bounty */ "Accounts.AdamantBounty" = "ADAMANT Bounty钱包"; -/* 系统帐户:ADAMANT支持 */ -"Accounts.Support" = "ADAMANT Support"; +/* System accounts: ADAMANT Support */ +"Accounts.Support" = "ADAMANT 支持"; -/* 系统帐户:ADAMANT Exchange */ -"Accounts.AdamantExchange" = "ADAMANT Exchange"; +/* System accounts: ADAMANT Exchange */ +"Accounts.AdamantExchange" = "ADAMANT 交流"; -/* 系统账户:押注比特币价格 */ +/* System accounts: Bet on Bitcoin Price */ "Accounts.BetOnBitcoin" = "押注比特币价格"; -/* 系统帐户:Adeline */ +/* System accounts: Adelina */ "Accounts.Adelina" = "Adelina AI"; -/* 系统账户:捐赠ADAMANT基金会 */ +/* System accounts: Donates ADAMANT Foundation */ "Accounts.DonateADMFoundation" = "向ADAMANT基金会捐款"; -/* AccountsProvider:地址无效错误,%@代表地址 */ +/* AccountsProvider: Address not valid error, %@ for address */ "AccountsProvider.Error.AddressNotValidFormat" = "无效地址:%@"; -/* AccountService:警报标题。1.2版中的更改 */ +/* AccountService: Alert title. Changes in version 1.2 */ "AccountService.update.v12.title" = "版本1.2更新:加密钱包"; -/* AccountService:警报消息。1.2版本中的更改,通知用户需要重新登录才能启动eth&lsk钱包 */ +/* AccountService: Alert message. Changes in version 1.2, notify user that he needs to relogin to initiate eth & lsk wallets */ "AccountService.update.v12.message" = "您需要重新登录才能启动以太坊钱包"; -/* AccountService:用户必须重新登录应用程序才能启动钱包 */ -"AccountService.reloginToInitializeWallets" = "重新登录以启动钱包"; +/* AccountService: User must relogin into app to initiate wallets */ +"AccountService.reloginToInitiateWallets" = "重新登录以启动钱包"; -/* 登录:用户键入了无效的密码短语 */ +/* Login: user typed in invalid passphrase */ "AccountServiceError.InvalidPassphrase" = "错误的密码短语"; -/* 登录:用户键入了错误的密码短语 */ -"AccountServiceError.FrowngPassphrase" = "错误的密码短语"; +/* Login: user typed in wrong passphrase */ +"AccountServiceError.WrongPassphrase" = "错误的密码短语"; -/* 帐户选项卡:确认注销警报:注销(确定)按钮 */ +/* Account tab: Confirm logout alert: Logout (Ok) button */ "AccountTab.ConfirmLogout.Logout" = "注销"; -/* 帐户选项卡:确认注销警报 */ +/* Account tab: Confirm logout alert */ "AccountTab.ConfirmLogout.MessageFormat" = "从%@注销?"; -/* 帐户选项卡:完整的"获取免费代币"链接,地址为%@ */ +/* Account tab: A full 'Get free tokens' link, with %@ as address */ "AccountTab.FreeTokens.UrlFormat" = "https://adamant.im/free-adm-tokens/?wallet=%@"; -/* 帐户选项卡:完整的"购买代币"链接,地址为%@ */ +/* Account tab: A full 'Buy tokens' link, with %@ as address */ "AccountTab.BuyTokens.UrlFormat" = "https://adamant.im/buy-tokens/?wallet=%@"; -/* "帐户"选项卡:余额行标题 */ +/* Account tab: Balance row title */ "AccountTab.Row.Balance" = "余额"; -/* 帐户选项卡:"购买代币"按钮 */ +/* Account tab: 'Buy tokens' button */ "AccountTab.Row.BuyTokens" = "交换代币"; -/* 帐户选项卡:"注销"按钮 */ +/* Account tab: 'Logout' button */ "AccountTab.Row.Logout" = "注销"; -/* 帐户选项卡:"安全"行 */ +/* Account tab: 'Security' row */ "AccountTab.Row.Security" = "安全性"; -/* 账户选项卡:"发送代币"按钮 */ +/* Account tab: 'Send tokens' button */ "AccountTab.Row.SendTokens" = "发送令牌"; -/* 帐户选项卡:"发送ADM令牌"按钮 */ +/* Account tab: 'Send ADM tokens' button */ "AccountTab.Row.SendAdm" = "发送ADM"; -/* 账户选项卡:"发送ETH代币"按钮 */ +/* Account tab: 'Send ETH tokens' button */ "AccountTab.Row.SendEth" = "发送ETH"; -/* 账户选项卡:"发送LSK代币"按钮 */ +/* Account tab: 'Send LSK tokens' button */ "AccountTab.Row.SendLsk" = "发送LSK"; -/* 账户选项卡:"发送BTC代币"按钮 */ +/* Account tab: 'Send BTC tokens' button */ "AccountTab.Row.SendBtc" = "发送BTC"; -/* 账户选项卡:"发送DOGE代币"按钮 */ +/* Account tab: 'Send DOGE tokens' button */ "AccountTab.Row.SendDoge" = "发送DOGE"; -/* 帐户选项卡:"发送DASH令牌"按钮 */ +/* Account tab: 'Send DASH tokens' button */ "AccountTab.Row.SendDash" = "发送DASH"; -/* 账户选项卡:"发送ERC20代币"按钮 */ +/* Account tab: 'Send ERC20 tokens' button */ "AccountTab.Row.SendToken" = "发送%@"; -/* 账户选项卡:匿名购买ADM代币 */ +/* Account tab: Anonymously buy ADM tokens */ "AccountTab.Row.AnonymouslyBuyADM" = "匿名更改ADM"; -/* 帐户选项卡:在聊天中交换ADM令牌 */ -"AccountTab.Row.ExchangeADMInChat" = "聊天内交换器"; +/* Account tab: Exchange ADM tokens in chat */ +"AccountTab.Row.ExchangeADMInChat" = "聊天交流"; -/* 帐户选项卡:"地址"行 */ +/* Account tab: 'Address' row */ "AccountTab.Row.Address" = "地址"; -/* 帐户选项卡:"获取免费代币"按钮 */ +/* Account tab: 'Get free tokens' button */ "AccountTab.Row.FreeTokens" = "免费ADM令牌"; -/* 帐户选项卡:"主题"行 */ +/* Account tab: 'Theme' row */ "AccountTab.Row.Theme" = "主题"; -/* 帐户选项卡:"主题"行值"浅色" */ +/* Account tab: 'Theme' row value 'Light' */ "AccountTab.Row.Theme.Light" = "灯光"; -/* 帐户选项卡:"主题"行值"深色" */ +/* Account tab: 'Theme' row value 'Dark' */ "AccountTab.Row.Theme.Dark" = "黑暗"; -/* 帐户选项卡:"关于"行 */ +/* Account tab: 'About' row */ "AccountTab.Row.About" = "关于"; -/* 帐户选项卡:"贡献"行 */ +/* Account tab: 'Contribute' row */ "AccountTab.Row.Contribute" = "投稿"; -/* 帐户选项卡:"为代表投票"按钮 */ +/* Account tab: 'Vote for delegates' button */ "AccountTab.Row.VoteForDelegates" = "为代表投票"; -/* "帐户"选项卡:"操作"部分标题 */ +/* Account tab: Actions section title */ "AccountTab.Section.Actions" = "行动"; -/* "帐户"选项卡:"应用程序"部分标题 */ +/* Account tab: Application section title */ "AccountTab.Section.Application" = "应用"; -/* 账户选项卡:阿达曼钱包 */ +/* Account tab: Adamant wallet */ "AccountTab.Wallets.adamant_wallet" = "ADAMANT钱包"; -/* 账户选项卡:以太坊钱包 */ +/* Account tab: Ethereum wallet */ "AccountTab.Wallets.ethereum_wallet" = "以太坊钱包"; -/* 账户选项卡:Lisk钱包 */ -"AccountTab.Wallets.lisk_vallet" = "Lisk钱包"; +/* Account tab: Lisk wallet */ +"AccountTab.Wallets.lisk_wallet" = "Lisk钱包"; -/* 账户选项卡:比特币钱包 */ +/* Account tab: Bitcoin wallet */ "AccountTab.Wallets.bitcoin_wallet" = "比特币钱包"; -/* 账户选项卡:狗狗钱包 */ -"AccountTab.Wallets.doge_ewallet" = "狗狗钱包"; +/* Account tab: Doge wallet */ +"AccountTab.Wallets.doge_wallet" = "狗狗钱包"; -/* 账户选项卡:达世币钱包 */ +/* Account tab: Dash wallet */ "AccountTab.Wallets.dash_wallet" = "达世币钱包"; -/* 账户选项卡:ERC20钱包 */ +/* Account tab: ERC20 wallet */ "AccountTab.Wallets.erc20_wallet" = "%@钱包"; -/* 帐号页面:场景标题 */ +/* Account page: scene title */ "AccountTab.Title" = "帐户"; -/* "帐户"选项卡:"代理人"部分标题 */ +/* Account tab: Delegates section title */ "AccountTab.Section.Delegates" = "代理人"; -/* 产品名称 */ +/* Product name */ "ADAMANT" = "坚定不移"; -/* AddressBookService:没有足够的钱将地址保存到区块链中 */ +/* AddressBookService: Not enought money to save address into blockchain */ "AddressBookService.Error.notEnoughMoney" = "没有足够的令牌在区块链中存储数据"; -/* 应用程序:无法将deviceToken发送到ANS错误格式。%@用于错误描述 */ +/* Application: Failed to send deviceToken to ANS error format. %@ for error description */ "Application.deviceTokenErrorFormat" = "无法在ANS:%@中注册"; -/* 严重内部错误:无法生成终结点url */ +/* Serious internal error: Failed to build endpoint url */ "ApiService.InternalError.EndpointBuildFailed" = "端点构建失败。报告错误"; -/* 严重内部错误:无法签署交易 */ +/* Serious internal error: Failed to sign transaction */ "ApiService.InternalError.FailedTransactionSigning" = "事务失败"; -/* 严重内部错误:分析响应时出错 */ +/* Serious internal error: Error parsing response */ "ApiService.InternalError.PassingFailed" = "分析失败。报告错误"; -/* 严重的内部错误:没有可用的节点 */ +/* Serious internal error: No nodes available */ "ApiService.InternalError.NoNodesAvailable" = "没有活动的%@节点。查看节点列表"; -/* 尤里卡表格取消按钮 */ +/* Eureka forms Cancel button */ "Cancel" = "取消"; -/* 聊天列表:传出消息前缀 */ +/* ChatList: outgoing message prefix */ "ChatListPage.SentMessagePrefix" = "您:"; -/* 聊天列表:SearchBar占位符文本 */ +/* ChatList: SearchBar placeholder text */ "ChatListPage.SearchBar.Placeholder" = "搜索联系人或消息"; -/* 搜索页面:联系人标题 */ +/* SearchPage: Contacts header */ "SearchPage.Contacts" = "联系人"; -/* 搜索页面:联系人标题 */ +/* SearchPage: Contacts header */ "SearchPage.Contact.New" = "新联系人"; -/* 搜索页面:联系人新标题 */ +/* SearchPage: Contact new header */ "SearchPage.Contact.Add.New" = "[添加新联系人]"; -/* SearchPage:消息标题 */ +/* SearchPage: Messages header */ "SearchPage.Messages" = "信息"; -/* 聊天列表:第一次同步正在进行中 */ +/* ChatList: First syncronization is in progress */ "ChatListPage.SyncingChats" = "正在同步聊天…"; -/* 聊天列表:已反应 */ -"ChatListPage.Rreached" = "达到"; +/* ChatList: Reacted */ +"ChatListPage.Reacted" = "达到"; -/* 聊天列表:删除的反应 */ -"ChatListPage.RemotedReaction" = "已删除反应"; +/* ChatList: Removed Reaction */ +"ChatListPage.RemovedReaction" = "已删除反应"; -/* 聊天列表:场景标题 */ +/* ChatList: scene title */ "ChatListPage.Title" = "聊天"; -/* 聊天提供商:通知用户他没有钱支付消息费 */ +/* ChatsProvider: Notify user that he doesn't have money to pay a message fee */ "ChatsProvider.Error.notEnoughMoney" = "零余额。获得免费ADM代币"; -/* ChatsProvider:未找到事务错误。%@用于事务的ID */ +/* ChatsProvider: Transaction not found error. %@ for transaction's ID */ "ChatsProvider.Error.TransactionNotFoundFormat" = "找不到id为%@的消息"; -/* ChatsProvider:验证错误:消息为空 */ +/* ChatsProvider: Validation error: Message is empty */ "ChatsProvider.Validation.MessageIsEmpty" = "消息为空"; -/* ChatsProvider:验证错误:消息太长 */ +/* ChatsProvider: Validation error: Message is too long */ "ChatsProvider.Validation.MessageTooLong" = "消息太长"; -/* 已知联系人:Adamant ICO消息。支持降价 */ +/* Known contacts: Adamant ICO message. Markdown supported. */ "Chats.IcoMessage" = "Null"; -/* 已知联系人:Adamant预ICO消息 */ +/* Known contacts: Adamant pre ICO message */ "Chats.PreIcoMessage" = "Null"; -/* 已知联系人:Adamant欢迎信息。支持降价 */ +/* Known contacts: Adamant welcome message. Markdown supported. */ "Chats.WelcomeMessage" = "ADAMANT是一个真正的区块链信使,独立于政府、企业甚至开发商。这是由于去中心化的网络基础设施,完全开源,由用户运行。这就是为什么每一个动作,包括发送消息或保存联系人姓名,都有0.001 ADM的网络费用。\n\nBlockchain提供了卓越的安全性和隐私,这是典型的P2P和c集中的信使。此外,区块链提供了新的可能性。您可以在聊天中存储和传输密码,并完全控制您的私钥,使用ADAMANT作为2FA等。\n\nADAMANT中,没有人可以控制、阻止、停用、限制或审查帐户。用户对内容、消息、媒体以及使用Messenger的目标和意图承担全部责任。\n\n请注意,您的安全性和匿名性取决于您。不要关注你收到的链接,否则你的IP可能会被泄露。在设备上设置密码。了解有关安全性和匿名性的更多信息,请访问https://adamant.im/staysecured/.\n\n请确保已保存此帐户的密码短语--注销并再次登录。把你的通行证短语也写在纸上。只有**您对通行证短语的安全负责**。它无法恢复。如果其他人得到了它,你的代币就会被盗,信件也会被读取。把这个问题看得最重要,就好像你钱包里的代币在一段时间内会花费10亿美元一样。\n\n若要立即开始发送消息,请在\"帐户\"选项卡上**获得免费欢迎令牌**。然后创建新聊天并输入您朋友的ADM地址。建议您亲自分享ADM地址,不要使用其他信使。"; -/* 已知联系人:Adamant Exchenge消息。支持降价 */ +/* Known contacts: Adamant Exchenge message. Markdown supported. */ "Chats.Exchange.WelcomeMessage" = "嗨!😊 我是你的交换机器人。我即时匿名操作。键入* */help**看看我能做些什么。我要求的费用比我的机器人同伴高,所以我建议你以有竞争力的费用建立自己的机器人。ℹ️ 你可以在ADAMANT博客上了解更多信息。我非常可靠,但如果您有任何问题,请在这里留言U6386412615727665758。"; -/* 已知联系人:Adamant押注比特币消息。支持降价 */ +/* Known contacts: Adamant Bet On Bitcoin message. Markdown supported. */ "Chats.BetOnBitcoin.WelcomeMessage" = "嗨!😊 我是匿名的,区块链验证的投注机器人。我接受BTC费率的投注,并向中奖者支付奖励。ℹ️ 在ADAMANT的博客上了解更多信息,或键入* */help**开始下注。通过U63864126157276665758提供支持。"; -/* 已知联系人:Adamant Adelina消息。支持降价 */ +/* Known contacts: Adamant Adelina message. Markdown supported. */ "Chats.Adelina.WelcomeMessage" = "你好,我是Adelina。让我们愉快地交谈一下!我可以做很多事情,比如:\n\n-起草电子邮件或其他文章\n-编写Python代码\n-回答关于一组文档的问题\n-支持对话\n-一系列主题的导师\n-翻译语言\n-写诗\n-模拟电子游戏中的角色等等"; -/* 已知联系人:阿达曼捐赠欢迎信息。支持降价 */ +/* Known contacts: Adamant donate welcome message. Markdown supported. */ "Chats.Donate.WelcomeMessage" = "感谢您的支持,我们开发了去中心化的ADAMANT Messenger——在此聊天中转移ADM、ETH和其他代币。有关其他捐赠钱包,请参阅adamant.im。"; -/* 警报"重试或删除"标题。在caht中用于再次发送或删除失败的消息 */ +/* Alert 'Retry Or Delete' title. Used in caht for sending failed messages again or delete them */ "Chats.RetryOrDelete.Title" = "重试还是删除?"; -/* 警报"重试或删除"正文消息。用于聊天,用于再次发送或删除失败的消息 */ +/* Alert 'Retry Or Delete' body message. Used in chat for sending failed messages again or delete them */ "Chats.RetryOrDelete.Body" = "尝试再次发送消息,还是删除它?"; -/* 按钮"阻止" */ +/* Button "Block" */ "Chats.Block" = "区块链 区块"; -/* 警报"是否阻止此用户?" */ +/* Alert "Block this user?" */ "Chats.BlockUser" = "是否阻止此用户?"; -/* "删除"按钮 */ +/* Button "Remove" */ "Chats.Remove" = "删除"; -/* 警报"是否删除此消息?" */ +/* Alert "Delete this message?" */ "Chats.RemoveMessage" = "是否删除此消息?"; -/* Button "Report" */ +/* Button "Report" */ "Chats.Report" = "报告"; -/* "回复"按钮 */ +/* Button "Reply" */ "Chats.Reply" = "回复"; -/* "复制"按钮 */ +/* Button "Copy" */ "Chats.Copy" = "复制"; -/* 警报"报告为不合适?" */ +/* Alert "Report as inappropriate?" */ "Chats.ReportMessage" = "是否报告为不合适?"; -/* 警报"报告已发送" */ +/* Alert "Report has been sent" */ "Chats.ReportSent" = "报告已发送"; -/* 聊天:通知用户他不能取消已发送的交易 */ +/* Chat: inform user that he can't cancel transaction, that was sent */ "ChatScene.Error.cancelError" = "消息已发送"; -/* 聊天:消息输入占位符 */ +/* Chat: message input placeholder */ "ChatScene.NewMessage.Placeholder" = "新消息"; -/* 聊天:发送信息按钮 */ +/* Chat: Send message button */ "ChatScene.Send" = "发送"; -/* 聊天:"已发送资金"泡沫标题 */ +/* Chat: 'Sent funds' bubble title */ "ChatScene.Sent" = "已发送"; -/* 聊天:"收到的资金"泡沫标题 */ +/* Chat: 'Received funds' bubble title */ "ChatScene.Received" = "已接收"; -/* 聊天:"已发送资金"buble"点击了解详细信息"提示 */ +/* Chat: 'Sent funds' buble 'Tap for details' tip */ "ChatScene.tapForDetails" = "点击获取详细信息"; -/* 聊天:发送聊天事务失败的状态消息 */ +/* Chat: status message for failed to send chat transaction */ "ChatScene.MessageStatus.FailToSend" = "发送失败"; -/* 聊天:挂起聊天事务的状态消息 */ +/* Chat: status message for pending chat transaction */ "ChatScene.MessageStatus.Pending" = "待定"; -/* 聊天:警告聊天事务的状态消息 */ +/* Chat: status message for warning chat transaction */ "ChatScene.MessageStatus.Warning" = "警告"; -/* 聊天:动作正文菜单 */ +/* Chat: Body for actions menu */ "ChatScene.Actions.Body" = "%@的新名称"; -/* 聊天:操作菜单中的"重命名"操作 */ +/* Chat: 'Rename' action in actions menu */ "ChatScene.Actions.Rename" = "重命名"; -/* 聊天:操作菜单中的"姓名"字段 */ +/* Chat: 'Name' field in actions menu */ "ChatScene.Actions.NamePlaceholder" = "名称"; -/* 聊天:"免费代币"按钮 */ +/* Chat: 'Free Tokens' button */ "ChatScene.FreeTokensAlert.FreeTokens" = "🎁 免费代币"; -/* 聊天:"免费代币"消息 */ +/* Chat: 'Free Tokens' message */ "ChatScene.FreeTokensAlert.Message" = "ADAMANT是一个独特的区块链信使,独立于政府、企业甚至其开发者。这是可能的,因为它是一个去中心化的网络,完全开源,由用户运行。这就是为什么每一个动作,包括发消息或保存新联系人,都要收取0.001 ADM.的网络费。要立即开始发消息,请获得免费的欢迎令牌。"; -/* 聊天:在设备上未配置邮件应用程序的情况下打开电子邮件链接的警告消息 */ +/* Chat: warning message for opening email link without mail app configurated on device */ "ChatScene.Warning.NoMailApp" = "无法发送电子邮件。请检查邮件应用程序配置。"; -/* 聊天:打开不支持的url方案的警告消息 */ +/* Chat: warning message for opening unsupported url schemes */ "ChatScene.Warning.UnsupportedUrl" = "不支持的url协议"; -/* 聊天:滚动到消息时出错,此消息已被删除,无法再访问 */ +/* Chat: Error scrolling to message, this message has been deleted and is no longer accessible */ "ChatScene.Error.messageWasDeleted" = "很抱歉,此消息已被删除,无法再访问"; -/* 聊天:错误消息太大 */ +/* Chat: Error message is too big */ "ChatScene.Error.messageIsTooBig" = "消息太大。分部分发送。"; -/* 代理人页面:场景标题 */ -"Delegates.Title" = "Delegates"; +/* Delegates page: scene title */ +"Delegates.Title" = "与会代表"; -/* 可见钱包页面:场景标题 */ +/* Visible Wallets page: scene title */ "VisibleWallets.Title" = "钱包列表"; -/* VisibleWallets:重置钱包警报标题 */ +/* VisibleWallets: Reset wallets alert title */ "VisibleWallets.ResetListAlert" = "是否将钱包列表重置为默认值?"; -/* 代理人选项卡:关于50 ADM投票费的信息 */ +/* Delegates tab: Message about 50 ADM fee for vote */ "Delegates.NotEnoughtTokensForVote" = "没有足够的代币可以投票。您需要50个ADM"; -/* 代理人选项卡:关于新投票超时的消息 */ +/* Delegates tab: Message about time out for new vote */ "Delegates.timeOutBeforeNewVote" = "请等待上一次投票处理完毕"; -/* 代理详细信息:场景标题 */ +/* Delegate details: scene title */ "DelegateDetails.Title" = "详细信息"; -/* 代理人详细信息屏幕:"用户名"的行标题 */ +/* Delegate Details Screen: Rows title for 'Username'" */ "DelegateDetails.Row.Username" = "用户名"; -/* 代理人详细信息屏幕:"地址"的行标题 */ +/* Delegate Details Screen: Rows title for 'Address'" */ "DelegateDetails.Row.Address" = "地址"; -/* 代理人详细信息屏幕:"公钥"的行标题 */ +/* Delegate Details Screen: Rows title for 'Public Key'" */ "DelegateDetails.Row.PublicKey" = "公钥"; -/* 代表详细信息屏幕:"投票权重"的行标题" */ +/* Delegate Details Screen: Rows title for 'Vote weight'" */ "DelegateDetails.Row.VoteWeight" = "投票权重"; -/* 代理详细信息屏幕:"生成的块"的行标题 */ -"DelegateDetails.Row.ProductedBlocks" = "生产的块"; +/* Delegate Details Screen: Rows title for 'Produced blocks'" */ +"DelegateDetails.Row.ProducedBlocks" = "生产的块"; -/* 代理详细信息屏幕:"错过的块"的行标题" */ +/* Delegate Details Screen: Rows title for 'Missed blocks'" */ "DelegateDetails.Row.MissedBlocks" = "错过的块"; -/* 代理人详细信息屏幕:"费率"的行标题 */ -"DelegateDetails.Row.Rate" = "Rate"; +/* Delegate Details Screen: Rows title for 'Rate'" */ +"DelegateDetails.Row.Rate" = "费率"; -/* 代理人详细信息屏幕:"排名"的行标题 */ +/* Delegate Details Screen: Rows title for 'Rank'" */ "DelegateDetails.Row.Rank" = "等级"; -/* 代理人详细信息屏幕:"批准"的行标题" */ +/* Delegate Details Screen: Rows title for 'Approval'" */ "DelegateDetails.Row.Approval" = "审批"; -/* 代理人详细信息屏幕:"生产力"的行标题" */ +/* Delegate Details Screen: Rows title for 'Productivity'" */ "DelegateDetails.Row.Productivity" = "生产率"; -/* 代表详细信息屏幕:"锻造时间"的行标题" */ +/* Delegate Details Screen: Rows title for 'Forging time'" */ "DelegateDetails.Row.ForgingTime" = "锻造时间"; -/* 代表详细信息屏幕:"伪造"的行标题 */ +/* Delegate Details Screen: Rows title for 'Forged'" */ "DelegateDetails.Row.Forged" = "伪造"; -/* 代表:成功投票的消息 */ +/* Delegates: Message for Successfull voting */ "Delegates.Vote.Success" = "您的投票已发送"; -/* Storybard-代表投票面板:"支持票"标签 */ +/* Storybard - Delegate vote panel: 'Upvotes' label */ "Delegates.VotePanel.Upvotes" = "向上投票:"; -/* Storybard-代表投票面板:"否决票"标签 */ +/* Storybard - Delegate vote panel: 'Downvotes' label */ "Delegates.VotePanel.Downvotes" = "反对票:"; -/* Storybard-代表投票面板:"新"标签 */ +/* Storybard - Delegate vote panel: 'New' label */ "Delegates.VotePanel.New" = "新:"; -/* Storybard-代表投票面板:"总计"标签 */ +/* Storybard - Delegate vote panel: 'Total' label */ "Delegates.VotePanel.Total" = "总计:"; -/* 共享错误:找不到帐户错误。使用%@作为地址 */ +/* Shared error: Account not found error. Using %@ for address. */ "Error.AccountNotFoundFormat" = "找不到帐户:%@"; -/* 共享错误:帐户未启动 */ +/* Shared error: Account not initiated */ "Error.AccountNotInitiated" = "帐户未启动"; -/* 共享错误:消息的内部错误格式为%@ */ +/* Shared error: Internal error format, %@ for message */ "Error.InteralErrorFormat" = "内部错误:%@"; -/* 共享错误:消息的基本格式为%@ */ +/* Shared error: Base format, %@ for message */ "Error.BaseErrorFormat" = "错误:%@"; -/* 支持电子邮件的错误消息标题 */ +/* Error messge title for support email */ "Error.Mail.Title" = "iOS应用程序中的错误"; -/* 支持电子邮件的错误消息正文 */ +/* Error messge body for support email */ "Error.Mail.Body" = "你好,\n\n我有这个错误:\n\n%@\n\n我的设备信息:\n\n%@"; -/*支持电子邮件的错误消息正文,以及详细的错误描述。其中,第一个%@-错误的短消息,第二个%@–详细描述,第三个%@-设备信息 */ +/* Error messge body for support email, with detailed error description. Where first %@ - error's short message, second %@ - detailed description, third %@ - deviceInfo */ "Error.Mail.Body.Detailed" = "你好,\n\n我有这个错误:\n\n%@\n\n%@\n\n设备:\n\n%@"; -/* 共享错误:网络问题。在大多数情况下-无连接 */ +/* Shared error: Network problems. In most cases - no connection */ "Error.NoNetwork" = "无连接"; -/* 共享错误:请求已取消 */ +/* Shared error: Request cancelled */ "Error.RequestCancelled" = "请求已取消"; -/* 共享错误:消息的远程错误格式为%@ */ +/* Shared error: Remote error format, %@ for message */ "Error.RemoteServerErrorFormat" = "区块链节点错误:%@"; -/* 共享错误:用户未登录 */ +/* Shared error: User not logged */ "Error.UserNotLogged" = "用户未登录"; -/* 共享未知错误 */ -"Error.UnnowError" = "未知错误。报告错误"; +/* Shared unknown error */ +"Error.UnknownError" = "未知错误。报告错误"; -/* 登录:通知用户,他在设置中禁用了摄像头,需要授权应用程序 */ +/* Login: Notify user, that he disabled camera in settings, and need to authorize application. */ "LoginScene.Error.AuthorizeCamera" = "您需要授权ADAMANT才能使用设备的摄像头"; -/* 登录:用户禁用了对光库的访问,他可以在设置中授权应用程序 */ +/* Login: User disabled access to photolibrary, he can authorize application in settings */ "LoginScene.Error.AuthorizePhotolibrary" = "您需要授权ADAMANT才能使用您的照片库"; -/* 登录:没有网络错误 */ +/* Login: No network error. */ "LoginScene.Error.NoInternet" = "没有连接到Internet"; -/* 登录:通知用户他正尝试在没有密码的情况下登录 */ +/* Login: notify user that he is trying to login without a passphrase */ "LoginScene.Error.NoPassphrase" = "输入密码短语"; -/* 登录:通知用户所选照片不包含带密码的有效二维码 */ +/* Login: Notify user that picked photo doesn't contains a valid qr code with passphrase */ "LoginScene.Error.NoQrOnPhoto" = "所选图像不包含有效的二维码"; -/* 登录:通知用户QR阅读器不支持该设备 */ +/* Login: Notify user that device not supported by QR reader */ "LoginScene.Error.QrNotSupported" = "设备不支持读取二维码"; -/* 登录:通知用户扫描的QR不包含密码短语 */ +/* Login: Notify user that scanned QR doesn't contains a passphrase. */ "LoginScene.Error.WrongQr" = "二维码不包含有效的密码短语"; -/* 登录:通知用户我们正在尝试登录 */ +/* Login: notify user that we are trying to log in */ "LoginScene.LoggingInProgress" = "正在登录…"; -/* 登录:使用biometry或pincode登录到以前的帐户 */ +/* Login: Login into previous account with biometry or pincode */ "LoginScene.LoginIntoAdamant" = "登录到ADAMANT"; -/* 登录:生成新密码短语按钮 */ +/* Login: generate new passphrase button */ "LoginScene.Row.Generate" = "生成新密码短语"; -/* 登录:登录按钮 */ +/* Login: Login button */ "LoginScene.Row.Login" = "登录"; -/* 登录:密码短语占位符 */ +/* Login: Passphrase placeholder */ "LoginScene.Row.Passphrase.Placeholder" = "密码短语"; -/* 登录:使用密码按钮登录 */ +/* Login: Login with pincode button */ "LoginScene.Row.Pincode" = "使用PIN码登录"; -/* 登录:使用二维码按钮登录 */ +/* Login: Login with QR button. */ "LoginScene.Row.Qr" = "使用二维码登录"; -/* 登录:安全警报,通知用户必须保存新密码。支持向下标记,居中对齐 */ +/* Login: security alert, notify user that he must save his new passphrase. Markdown supported, center aligned. */ "LoginScene.Row.SavePassphraseAlert" = "**保存新钱包和Messenger帐户的密码短语**。没有登录信息可以进入钱包,只需要密码短语。**如果丢失,无法恢复**。"; -/* 登录:对用户的一个小提示,他可以点击密码短语来保存它 */ +/* Login: a small hint for a user, that he can tap on passphrase to save it */ "LoginScene.Row.TapToSave" = "点击保存"; -/* 登录:使用现有密码段登录 */ +/* Login: login with existing passphrase section */ "LoginScene.Section.Login" = "登录"; -/* 登录:创建新帐户部分 */ +/* Login: Create new account section */ "LoginScene.Section.NewAccount" = "新帐户"; -/* 新聊天:收件人地址占位符。请注意,地址文本字段总是显示U字母,所以您可以将这一行留空 */ +/* New chat: Recipient address placeholder. Note that address text field always shows U letter, so you can left this line blank. */ "NewChatScene.Address.Placeholder" = ""; -/* 新聊天:通知用户找不到指定的地址(%@)。使用%@作为地址 */ +/* New chat: Notify user that specified address (%@) not found. Using %@ for address */ "NewChatScene.Error.AddressNotFoundFormat" = "未找到地址:%@"; -/* 新聊天:通知用户他输入了无效地址 */ +/* New chat: Notify user that he did enter invalid address */ "NewChatScene.Error.InvalidAddress" = "输入有效地址"; -/* 新聊天:通知用户他无法开始与自己聊天 */ +/* New chat: Notify user that he can't start chat with himself */ "NewChatScene.Error.OwnAddress" = "你不需要加密的匿名聊天来与自己交谈"; -/* 新聊天:通知用户扫描的二维码不包含地址 */ +/* New Chat: Notify user that scanned QR doesn't contains an address */ "NewChatScene.Error.WrongQr" = "二维码不包含有效地址"; -/* 新聊天:使用地址按钮扫描二维码 */ +/* New chat: Scan QR with address button */ "NewChatScene.ScanQr" = "扫描二维码"; -/* 新聊天:场景标题 */ +/* New chat: scene title */ "NewChatScene.Title" = "新聊天"; -/* 新聊天:显示我的地址按钮的二维码 */ +/* New chat: Show QR for my address button */ "NewChatScene.MyQr" = "显示我的二维码"; -/* 新聊天:"这是什么意思?",有关未初始化帐户的信息的帮助按钮 */ +/* New Chat: 'What does it mean?', a help button for info about uninitialized accounts. */ "NewChatScene.NotInitialized.HelpButton" = "这是什么意思?"; -/* NodesList:按钮标签 */ +/* NodesList: Button label */ "NodesList.NodesList" = "ADM节点列表"; -/* 节点列表:场景标题 */ +/* NodesList: scene title */ "NodesList.Title" = "ADM节点列表"; -/* NodesList:"添加新节点"按钮标签 */ +/* NodesList: 'Add new node' button lable */ "NodesList.AddNewNode" = "添加新节点"; -/* NodesList:重置节点警报标题 */ +/* NodesList: Reset nodes alert title */ "NodesList.ResetNodeListAlert" = "是否将节点列表重置为默认值?"; -/* NodesList:"重置"按钮 */ +/* NodesList: 'Reset' button */ "NodesList.ResetButton" = "重置"; -/* NodesList:"首选最快的节点"开关 */ +/* NodesList: 'Prefer the fastest node' switch */ "NodesList.PreferTheFastestNode" = "首选最快的节点"; -/* NodesList:"首选最快的节点"开关 */ +/* NodesList: 'Prefer the fastest node' switch */ "NodesList.PreferTheFastestNode.Footer" = "处理请求更快,但可能会减少隐私"; -/* 节点列表。NodeCell:节点ping */ +/* NodesList.NodeCell: Node ping */ "NodesList.NodeCell.Ping" = "Ping"; -/* 节点列表。NodeCell:毫秒 */ +/* NodesList.NodeCell: Milliseconds */ "NodesList.NodeCell.Milliseconds" = "ms"; -/* 节点列表。NodeCell:节点正在同步 */ +/* NodesList.NodeCell: Node is synchronizing */ "NodesList.NodeCell.Synchronizing" = "正在同步"; -/* 节点列表。NodeCell:节点处于脱机状态 */ -"NodesList.NodeCell.Online" = "脱机"; +/* NodesList.NodeCell: Node is offline */ +"NodesList.NodeCell.Offline" = "离线"; -/* 节点列表。NodeCell:节点已禁用 */ +/* NodesList.NodeCell: Node is disabled */ "NodesList.NodeCell.Disabled" = "已禁用"; -/* 节点列表。NodeCell:节点版本 */ +/* NodesList.NodeCell: Node version */ "NodesList.NodeCell.Version" = "版本"; -/* NodeList:如果用户删除了所有节点,则通知默认节点已加载 */ +/* NodeList: Inform that default nodes was loaded, if user deleted all nodes */ "NodeList.DefaultNodesLoaded" = "已加载默认节点列表"; -/* 硬币节点列表:标题 */ +/* CoinsNodesList: Title */ "CoinsNodesList.Title" = "Coin和服务节点列表"; -/* CoinsNodesList:ServiceNode */ +/* CoinsNodesList: ServiceNode */ "CoinsNodesList.ServiceNode" = "服务"; -/* NodesEditor:新节点场景标题 */ +/* NodesEditor: New node scene title */ "NodesEditor.NewNodeTitle" = "新节点"; -/* NodesEditor:删除节点确认消息 */ +/* NodesEditor: Delete node confirmation message */ "NodesEditor.DeleteNodeAlert" = "是否删除此节点?"; -/* NodesEditor:测试正在进行中 */ +/* NodesEditor: Testing in progress */ "NodesEditor.TestingInProgressMessage" = "正在检查连接…"; -/* NodesEditor:Scheme行 */ -"NodesEditor.SchemeRow" = "Scheme"; +/* NodesEditor: Scheme row */ +"NodesEditor.SchemeRow" = "计划"; -/* NodesEditor:端口行 */ +/* NodesEditor: Port row */ "NodesEditor.PortRow" = "端口"; -/* NodesEditor:主机行 */ +/* NodesEditor: Host row */ "NodesEditor.HostRow" = "主机"; -/* NodesEditor:Web套接字 */ -"NodesEditor.Webockets" = "Web套接字"; +/* NodesEditor: Web sockets */ +"NodesEditor.WebSockets" = "Web套接字"; -/* NodesEditor:支持Web套接字 */ -"NodesEditor.WebocketsSupported" = "支持"; +/* NodesEditor: Web sockets are supported */ +"NodesEditor.WebSocketsSupported" = "支持"; -/* NodesEditor:不支持Web套接字 */ -"NodesEditor.WebocketsNotSupported" = "不支持"; +/* NodesEditor: Web sockets aren't supported */ +"NodesEditor.WebSocketsNotSupported" = "不支持"; -/* NodesEditor:删除节点按钮 */ +/* NodesEditor: Delete node button */ "NodesEditor.DeleteNodeButton" = "删除"; -/* NodesEditor:主机行占位符 */ +/* NodesEditor: Host row placeholder */ "NodesEditor.HostRow.Placeholder" = "IP或主机名"; -/* NodesEditor:无法生成URL警报 */ +/* NodesEditor: Failed to build URL alert */ "NodesEditor.FailedToBuildURL" = "无效主机"; -/* 安全性:通知模式说明。支持降价 */ +/* Security: Notification modes description. Markdown supported. */ "SecurityPage.Row.Notifications.ModesDescription" = "####通知模式\n\n####禁用\n无通知。\n\n####后台提取\n您的设备会自动提取新消息。没有外部调用。提取由iOS启动,实际时间由操作系统根据电池电量、蜂窝网络、应用程序使用模式等许多因素确定,无法预测。可以是20分钟、6小时,甚至可能是一天。不过,您仍然可以打开应用程序并查看新消息。\n\n####推送\n ADAMANT通知服务发送到您的设备的通知。在消息发送并获得区块链批准后,您几乎会立即收到通知——延迟几秒钟。但此模式要求您的设备在服务的数据库中注册其设备令牌。设备令牌是安全的,在大多数情况下建议使用此选项。\n\n您可以在ADAMANT的GitHub页面上阅读更多关于设备注册的信息。\n\n"; -/* 安全性:选定的通知类型 */ -"SecurityPage.Section.NotificationsType" = "Notifications"; +/* Security: Selected notifications types */ +"SecurityPage.Section.NotificationsType" = "通知"; -/* 安全性:关于通知类型 */ +/* Security: About Notification types */ "SecurityPage.Section.AboutNotificationTypes" = "关于ANS"; -/* 安全:消息通知声音 */ -"SecurityPage.Section.Messages" = "Messages"; +/* Security: Messages Notification sound */ +"SecurityPage.Section.Messages" = "信息"; -/* 安全:设置通知 */ -"SecurityPage.Section.Settings" = "Settings"; +/* Security: Settings Notification */ +"SecurityPage.Section.Settings" = "设置"; -/* 通知:禁用通知 */ +/* Notifications: Disable notifications */ "Notifications.Mode.NotificationsDisabled" = "已禁用"; -/* 通知:使用后台提取通知 */ +/* Notifications: Use Background fetch notifications */ "Notifications.Mode.BackgroundFetch" = "后台获取"; -/* 通知:使用Apple推送通知 */ +/* Notifications: Use Apple Push notifications */ "Notifications.Mode.ApplePush" = "推送"; -/* 安全:访问Github */ +/* Security: Visit Github */ "SecurityPage.Row.VisitGithub" = "访问GitHub"; -/* 通知:打开系统设置 */ +/* Notifications: Open system Settings */ "Notifications.Settings.System" = "系统设置"; -/* 通知:选择声音 */ +/* Notifications: Select Sound */ "Notifications.Sound.Name" = "声音"; -/* 通知:选择声音 */ -"Notifications.Sounds.Name" = "Sounds"; +/* Notifications: Select Sounds */ +"Notifications.Sounds.Name" = "声音"; -/* 通知:选择提醒音调 */ -"Notifications.Alert.Tones" = "Alert Tones"; +/* Notifications: Select Alert Tones */ +"Notifications.Alert.Tones" = "警报音"; -/* 通知:选择警报保存 */ +/* Notifications: Select Alert Save */ "Notifications.Alert.Save" = "保存"; -/* 通知:警报取消 */ +/* Notifications: Alerts Cancel */ "Notifications.Alert.Cancel" = "取消"; -/* Pinpad:要求用户创建新引脚 */ +/* Pinpad: Ask user to create new pin */ "Pinpad.EnterNewPin" = "输入新的PIN码"; -/* Pinpad:要求用户重复新引脚 */ -"Pinpad.RenerPin" = "重新输入您的PIN码"; +/* Pinpad: Ask user to repeat new pin */ +"Pinpad.ReenterPin" = "重新输入您的PIN码"; -/* QRGenerator:错误的内部生成器错误消息格式。使用%@作为错误描述 */ +/* QRGenerator: Bad Internal generator error message format. Using %@ for error description */ "QrGeneratorScene.Error.InteralErrorFormat" = "内部错误:%@。报告错误"; -/* QRGenerator:用户键入了无效的密码短语 */ +/* QRGenerator: user typed in invalid passphrase */ "QrGeneratorScene.Error.InvalidPassphrase" = "输入有效的密码短语"; -/* QRGenerator:密码短语文本视图占位符 */ +/* QRGenerator: Passphrase textview placeholder */ "QrGeneratorScene.Passphrase.Placeholder" = "密码短语"; -/* QRGenerator:生成的QR下的小"点击保存"工具提示 */ +/* QRGenerator: small 'Tap to save' tooltip under generated QR */ "QrGeneratorScene.TapToSave" = "点击保存"; -/* QRGenerator:场景标题 */ +/* QRGenerator: scene title */ "QrGeneratorScene.Title" = "QR生成器"; -/* PrivateKeyGenerator:场景标题 */ +/* PrivateKeyGenerator: scene title */ "PkGeneratorScene.Title" = "私钥生成器"; -/* PrivateKeyGenerator:安全警报。确保密码的安全 */ +/* PrivateKeyGenerator: Security alert. Keep your passphrase safe */ "PkGeneratorScene.Alert" = "ADAMANT帐户包括加密钱包。所有这些钱包都与您的密码连接,只有您可以访问这些钱包。您可以导出私钥以在其他应用程序中使用它们。将密钥存储在安全的地方。"; -/* PrivateKeyGenerator:"生成"按钮 */ +/* PrivateKeyGenerator: Generate button */ "PkGeneratorScene.GenerateButton" = "生成密钥"; -/* 安全:场景标题 */ +/* Security: scene title */ "SecurityPage.Title" = "安全性"; -/* 安全:关闭"保持登录"确认 */ +/* Security: turn off 'Stay Logged In' confirmation */ "SecurityPage.DoNotStayLoggedIn" = "不保持登录状态"; -/* 配置:关闭生物测量的授权原因 */ +/* Config: Authorization reason for turning biometry off */ "SecurityPage.DoNotUseBiometry" = "不使用biometry登录"; -/* 安全性:生成带有密码短语行的QR */ +/* Security: Generate QR with passphrase row */ "SecurityPage.Row.GenerateQr" = "生成带有密码短语的QR"; -/* 安全性:使用密码短语行生成PrivateKey */ +/* Security: Generate PrivateKey with passphrase row */ "SecurityPage.Row.GeneratePk" = "导出私钥"; -/* 安全性:显示通知 */ +/* Security: Show notifications */ "SecurityPage.Row.Notifications" = "通知"; -/* 安全:保持记录行 */ +/* Security: Stay logged row */ "SecurityPage.Row.StayLoggedIn" = "保持登录状态"; -/* 安全:安全部分 */ +/* Security: Security section */ "SecurityPage.Section.Security" = "安全性"; -/* 配置:场景标题 */ +/* Config: scene title */ "SettingsPage.Title" = "设置"; -/* 安全:开启生物测量的授权原因 */ +/* Security: Authorization reason for turning biometry on */ "SecurityPage.UseBiometry" = "使用生物测量"; -/* 共享警报"取消"按钮。在任何地方使用 */ +/* Shared alert 'Cancel' button. Used anywhere */ "Shared.Cancel" = "取消"; -/* 共享警报通知:关于项目复制到粘贴板的消息 */ +/* Shared alert notification: message about item copied to pasteboard. */ "Shared.CopiedToPasteboard" = "已复制到粘贴板"; -/* 共享警报"复制"按钮。在任何地方使用。用于复制粘贴信息 */ +/* Shared alert 'Copy' button. Used anywhere. Used for copy-paste info. */ "Shared.CopyToPasteboard" = "复制到粘贴板"; -/* 共享警报"聊天"按钮。用于与收件人聊天 */ +/* Shared alert 'Chat With' button. Used to chat with recipient */ "Shared.ChatWith" = "与聊天"; -/* 共享警报"发送ADM到"按钮。用于将ADM发送到收件人 */ +/* Shared alert 'Send ADM To' button. Used to send ADM to recipient */ "Shared.SendAdmTo" = "将ADM发送到"; -/* 共享警报完成消息。在任何地方使用 */ +/* Shared alert Done message. Used anywhere */ "Shared.Done" = "完成"; -/* 共享警报"错误"标题。在任何地方使用 */ +/* Shared alert 'Error' title. Used anywhere */ "Shared.Error" = "错误"; -/* 共享警报"生成QR"按钮。用于生成带有地址和密码短语的二维码。用于随时随地共享和保存 */ +/* Shared alert 'Generate QR' button. Used to generate QR codes with addresses and passphrases. Used with sharing and saving, anywhere. */ "Shared.GenerateQRCode" = "生成二维码"; -/* 共享警报通知:无internet连接消息的标题 */ +/* Shared alert notification: title for no internet connection message. */ "Shared.NoInternet.Title" = "无互联网连接"; -/* 共享警报通知:没有互联网连接的正文消息 */ +/* Shared alert notification: body message for no internet connection. */ "Shared.NoInternet.Body" = "请检查您的互联网连接,然后重试"; -/* 共享警报"确定"按钮。在任何地方使用 */ -"Shared.Ok" = "Ok"; +/* Shared alert 'Ok' button. Used anywhere */ +"Shared.Ok" = "好的"; -/* 共享警报"保存"按钮。在任何地方使用 */ +/* Shared alert 'Save' button. Used anywhere */ "Shared.Save" = "保存"; -/* 共享警报"保存到照片"。用于将图像保存到光库 */ +/* Shared alert 'Save to Photos'. Used with saving images to photolibrary */ "Shared.SaveToPhotolibrary" = "保存到照片"; -/* 共享警报"设置"按钮。用于转到应用程序设置页面上的系统设置应用程序。应与"设置"应用程序标题相同 */ +/* Shared alert 'Settings' button. Used to go to system Settings app, on application settings page. Should be same as Settings application title. */ "Shared.Settings" = "设置"; -/* 共享警报"共享"按钮。用于任何地方展示标准的iOS"共享"菜单 */ +/* Shared alert 'Share' button. Used anywhere for presenting standart iOS 'Share' menu. */ "Shared.Share" = "共享"; -/* 共享警报"重试"按钮。在任何地方使用 */ +/* Shared alert 'Retry' button. Used anywhere. */ "Shared.Retry" = "重试"; -/* 共享警报"删除"按钮。在任何地方使用 */ +/* Shared alert 'Delete' button. Used anywhere. */ "Shared.Delete" = "删除"; -/* ShareQR场景:用户未经授权将图像写入照片库 */ -"ShareQR.protorilibraryNotAuthorized" = "您需要授权ADAMANT才能使用您的照片库"; +/* ShareQR scene: User had not authorized access to write images to photolibrary */ +"ShareQR.photolibraryNotAuthorized" = "您需要授权ADAMANT才能使用您的照片库"; -/* 主选项卡栏:帐户页面 */ +/* Main tab bar: Account page */ "Tabs.Account" = "帐户"; -/* 主选项卡栏:聊天页面 */ +/* Main tab bar: Chats page */ "Tabs.Chats" = "聊天"; -/* 主选项卡栏:设置页面 */ +/* Main tab bar: Settings page */ "Tabs.Settings" = "设置"; -/* TransactionList:场景标题 */ +/* TransactionList: scene title */ "TransactionListScene.Title" = "事务"; -/* TransactionList:To Chat按钮 */ +/* TransactionList: To Chat button */ "TransactionListScene.ToChat" = "聊天"; -/* 事务列表:开始聊天按钮 */ +/* TransactionList: Start Chat button */ "TransactionListScene.StartChat" = "开始聊天"; -/* TransactionList:"未找到事务"消息 */ +/* TransactionList: 'Transactions not found' message. */ "TransactionListScene.Error.NotFound" = "未找到事务"; -/* TransactionList:"尚未进行交易"消息 */ +/* TransactionList: 'No transactions yet' message. */ "TransactionListScene.NoTransactionYet" = "还没有事务"; -/* TransactionList:"找不到事务"本地化来自API的错误消息 */ +/* TransactionList: 'Transactions not found' localize error message from API. */ "No transactions found" = "未找到交易"; -/* 交易发送:收件人最低剩余余额要求 */ +/* Transaction send: recipient minimum remaining balance requirement */ "TransactionSend.Minimum.Balance" = "收件人必须至少具有0.05 LSK--发送更多令牌"; -/* 事务状态:正在更新 */ -"TransactionStatus.Updateing" = "正在更新…"; +/* Transaction status: updating in progress */ +"TransactionStatus.Updating" = "正在更新…"; -/* 交易状态:交易处于挂起状态 */ +/* Transaction status: transaction is pending */ "TransactionStatus.Pending" = "待定"; -/* 交易状态:成功 */ +/* Transaction status: success */ "TransactionStatus.Success" = "成功"; -/* 交易状态:交易失败 */ +/* Transaction status: transaction failed */ "TransactionStatus.Failed" = "失败"; -/* 交易状态:不一致 */ +/* Transaction status: inconsistent */ "TransactionStatus.Inconsistent" = "不一致"; -/* 事务状态:时间戳不一致错误 */ +/* Transaction status: inconsistent wrong timestamp */ "TransactionStatus.Inconsistent.WrongTimestamp" = "消息和Tx有不同的时间戳。这是可能的,但要检查两次"; -/* 交易状态:原因标题不一致 */ +/* Transaction status: inconsistent reason title */ "TransactionStatus.Inconsistent.Reason.Title" = "不一致的原因"; -/* 事务细节:场景标题 */ +/* Transaction details: scene title */ "TransactionDetailsScene.Title" = "详细信息"; -/* 交易明细:金额行 */ +/* Transaction details: amount row. */ "TransactionDetailsScene.Row.Amount" = "金额"; -/* 事务详细信息:块id行 */ +/* Transaction details: Block id row. */ "TransactionDetailsScene.Row.Block" = "区块链 区块"; -/* 交易明细:交易交付状态 */ +/* Transaction details: Transaction delivery status. */ "TransactionDetailsScene.Row.Status" = "事务状态"; -/* 交易明细:确认行 */ +/* Transaction details: confirmations row. */ "TransactionDetailsScene.Row.Confirmations" = "确认"; -/* 交易明细:日期行 */ +/* Transaction details: date row. */ "TransactionDetailsScene.Row.Date" = "日期"; -/* 事务详细信息:"在资源管理器中打开事务"行 */ +/* Transaction details: 'Open transaction in explorer' row. */ "TransactionDetailsScene.Row.Explorer" = "在资源管理器中打开"; -/* 交易明细:费用行 */ +/* Transaction details: fee row. */ "TransactionDetailsScene.Row.Fee" = "费用"; -/* 交易详细信息:发件人行 */ +/* Transaction details: sender row. */ "TransactionDetailsScene.Row.From" = "来自"; -/* 交易明细:当时的法定价值 */ +/* Transaction details: fiat value at the time */ "TransactionDetailsScene.Row.HistoryFiat" = "Txn时的值"; -/* 交易明细:当时的法定价值 */ +/* Transaction details: fiat value at the time */ "TransactionDetailsScene.Row.CurrentFiat" = "当前值"; -/* 事务详细信息:Id行 */ +/* Transaction details: Id row. */ "TransactionDetailsScene.Row.Id" = "同上"; -/* 交易明细:收单行 */ +/* Transaction details: recipient row. */ "TransactionDetailsScene.Row.To" = "至"; -/* 导出交易:"共享交易摘要"按钮 */ +/* Export transaction: 'Share transaction summary' button */ "TransactionDetailsScene.Share.Summary" = "摘要"; -/* 导出交易:"共享交易URL"按钮 */ +/* Export transaction: 'Share transaction URL' button */ "TransactionDetailsScene.Share.URL" = "网址"; -/* "交易详细信息:‘评论’部分" */ +/* "Transaction details: 'Comments' section" */ "TransactionDetailsScene.Section.Comment" = "评论"; -/* "事务详细信息:"操作"部分" */ +/* "Transaction details: 'Actions' section" */ "TransactionDetailsScene.Section.Actions" = "行动"; -/* 事务详细信息:"请求数据"进度消息 */ +/* Transaction details: 'Requesting Data' progress message. */ "TransactionDetailsScene.RequestingData" = "正在请求数据…"; -/* 交易详细信息:"您的地址"标志 */ +/* Transaction details: 'Your address' flag. */ "TransactionDetailsScene.YourAddress" = "您"; -/* TransfersProvider:找不到交易错误。%@信息%s(%s)用于事务的ID */ +/* TransfersProvider: Transaction not found error. %@ for transaction's ID */ "TransfersProvider.Error.TransactionNotFoundFormat" = "找不到ID为%@的事务"; -/* 转账:最低交易金额为0.00001 */ +/* Transfer: Minimal transaction amount is 0.00001 */ "TransferScene.Error.MinAmount" = "最低交易金额为0.00001"; -/* 转账:转账金额占位符 */ +/* Transfer: transfer amount placeholder */ "TransferScene.Amount.Placeholder" = "发送"; -/* 传输:找不到地址错误 */ +/* Transfer: Address not found error */ "TransferScene.Error.AddressNotFound" = "找不到地址"; -/* 传输:地址验证错误 */ +/* Transfer: Address validation error */ "TransferScene.Error.InvalidAddress" = "输入有效地址"; -/* 转账:金额高于用户的总金额通知 */ +/* Transfer: Amount is hiegher that user's total money notification */ "TransferScene.Error.notEnoughMoney" = "你没有那个标志"; -/* 转账:金额为零,甚至是负面通知 */ +/* Transfer: Amount is zero, or even negative notification */ "TransferScene.Error.TooLittleMoney" = "你应该发送更多的标志"; -/* 转账:发送交易的费用不足 */ +/* Transfer: Not enough fee for send a transaction */ "TransferScene.Error.TooLittleFee" = "费用不足"; -/* 转账:费用比平时高 */ +/* Transfer: Fee is higher than usual */ "TransferScene.Error.FeeIsTooHigh" = "注意:tx费用高于常规费用"; -/* 转账:警报标题:未找到帐户或未启动帐户。提醒用户他仍然可以汇款,但需要加倍确认地址 */ +/* Transfer: Alert title: Account not found or not initiated. Alert user that he still can send money, but need to double ckeck address */ "TransferScene.unsafeTransferAlert.title" = "无法验证%@"; -/* 转账:预警主体:未找到账户或未启动账户。提醒用户他仍然可以汇款,但需要加倍确认地址 */ +/* Transfer: Alert body: Account not found or not initiated. Alert user that he still can send money, but need to double ckeck address */ "TransferScene.unsafeTransferAlert.body" = "找不到帐户,或未启动帐户。请仔细检查收件人地址并确认交易"; -/* 转账:预警主体:未发起账户。无法启动聊天,因为区块链不存储帐户的公钥来加密消息 */ +/* Transfer: Alert body: Account is not initiated. It's not possible to start a chat, as the Blockchain doesn't store the account's public key to encrypt messages. */ "TransferScene.unsafeChatAlert.body" = "帐户未启动。由于区块链不存储帐户的公钥来加密消息,因此无法启动聊天。"; -/* 转移:收件人地址占位符 */ -"TransferScene.Receiver.Placeholder" = "收件人的"; +/* Transfer: recipient address placeholder */ +"TransferScene.Recipient.Placeholder" = "收件人的"; -/* 转让:坚持转让的金额 */ +/* Transfer: amount of adamant to transfer. */ "TransferScene.Row.Amount" = "金额"; -/* 转账:加密货币的法定价值 */ +/* Transfer: fiat value of crypto-amout */ "TransferScene.Row.Fiat" = "价值"; -/* 转移:记录的用户余额 */ +/* Transfer: logged user balance. */ "TransferScene.Row.Balance" = "余额"; -/* 转账:最高转账金额:可用账户资金减去转账费用 */ +/* Transfer: maximum amount to transfer: available account money substracting transfer fee */ "TransferScene.Row.MaxToTransfer" = "要传输的最大值"; -/* 转移:收件人地址 */ -"TransferScene.Row.ReceipientAddress" = "地址"; +/* Transfer: recipient address */ +"TransferScene.Row.RecipientAddress" = "地址"; -/* 转移:收件人姓名 */ -"TransferScene.Row.ReceipientName" = "名称"; +/* Transfer: recipient name */ +"TransferScene.Row.RecipientName" = "名称"; -/* 传输:发送按钮 */ +/* Transfer: Send button */ "TransferScene.Row.Send" = "发送"; -/* 转账:交易总金额:转账附加费 */ +/* Transfer: total amount of transaction: money to transfer adding fee */ "TransferScene.Row.Total" = "总计"; -/* 转让:转让费 */ +/* Transfer: transfer fee */ "TransferScene.Row.TransactionFee" = "费用"; -/* 转让:在聊天中转让的评论 */ +/* Transfer: comment for transfer in chat */ "TransferScene.Row.Comments" = "评论"; -/* 转让:转让增加费 */ +/* Transfer: transfer increase fee */ "TransferScene.Row.IncreaseFee" = "增加费用"; -/* 转移:"转移信息"部分 */ +/* Transfer: 'Transfer info' section */ "TransferScene.Section.TransferInfo" = "传输信息"; -/* 转账:"您的钱包"部分 */ +/* Transfer: 'Your wallet' section */ "TransferScene.Section.YourWallet" = "您的钱包"; -/* 传输:"收件人信息"部分 */ +/* Transfer: 'Recipient info' section */ "TransferScene.Section.Recipient" = "收件人"; -/* 转移:确认转移警报:发送令牌按钮 */ +/* Transfer: Confirm transfer alert: Send tokens button */ "TransferScene.Send" = "发送"; -/* 传输:确认传输警报:"无法撤消"消息 */ +/* Transfer: Confirm transfer alert: 'Can't Undo' message */ "TransferScene.CantUndo" = "您将无法撤消此操作"; -/* Tranfser:确认使用可用于转移代币的最大金额作为转移金额 */ +/* Tranfser: Confirm using maximum available for transfer tokens as amount to transfer. */ "TransferScene.UseMaxToTransfer" = "使用所有可用代币作为转账金额?"; -/* Tranfser:灰尘错误 */ +/* Tranfser: Dust error. */ "TransferScene.Dust.Error" = "灰尘数量--发送更多代币"; -/*传输:确认将%1$@令牌传输到%2$@消息。注意两个变量:在运行时%1$@将是金额(带ADM后缀),%2$@将是收件人地址。您可以使用这个所谓的"仓位代币"在金额之前使用地址 */ +/* Transfer: Confirm transfer %1$@ tokens to %2$@ message. Note two variables: at runtime %1$@ will be amount (with ADM suffix), and %2$@ will be recipient address. You can use address before amount with this so called 'position tokens'. */ "TransferScene.SendConfirmFormat" = "将%1$@发送到%2$@?"; -/* 传输:正在处理消息 */ +/* Transfer: Processing message */ "TransferScene.SendingFundsProgress" = "正在发送令牌…"; -/* 传输:令牌传输成功消息 */ +/* Transfer: Tokens transfered successfully message */ "TransferScene.TransferSuccessMessage" = "完成!"; -/* 钱包服务:共享错误,用户没有足够的钱 */ +/* Wallet Services: Shared error, user do not have enought money. */ "WalletServices.SharedErrors.notEnoughMoney" = "代币不足"; -/* 钱包服务:共享错误,用户尚未启动特定的钱包 */ +/* Wallet Services: Shared error, user has not yet initiated a specific wallet. */ "WalletServices.SharedErrors.WalletNotInitiated" = "收款人的钱包尚未启动"; -/* 钱包服务:共享错误,金额格式无效。%@金额 */ +/* Wallet Services: Shared error, invalid amount format. %@ for amount */ "WalletServices.SharedErrors.InvalidAmountFormat" = "要发送的金额无效:%@"; -/* 钱包服务:共享错误,找不到交易 */ +/* Wallet Services: Shared error, transaction not found */ "WalletServices.SharedErrors.TransactionNotFound" = "未找到交易"; -/* 钱包服务:共享错误,BTC Taproot不工作 */ +/* Wallet Services: Shared error, BTC Taproot doesn't work */ "WalletServices.SharedErrors.BtcTaproot" = "ADAMANT不支持Taproot比特币地址"; -/* 钱包服务:等待其他交易获得批准 */ +/* Wallet Services: Wait until other transactions approved */ "WalletServices.SharedErrors.walletFrezzed" = "等待其他交易获得批准"; -/* 钱包服务:交易不可用 */ +/* Wallet Services: Transaction unavailable */ "WalletServices.SharedErrors.transactionUnavailable" = "交易不可用"; -/* 钱包服务:无法验证交易 */ -"WalletServices.SharedErrors.consistentTransaction" = "无法验证交易"; +/* Wallet Services: Cannot verify transaction */ +"WalletServices.SharedErrors.inconsistentTransaction" = "无法验证交易"; -/* 欢迎:跳过按钮 */ +/* Welcome: Skip button */ "WelcomeScene.Skip" = "跳过"; -/* 欢迎:幻灯片1说明 */ +/* Welcome: Slide 1 Description */ "WelcomeScene.Description.Slide1" = "欢迎来到ADAMANT,真正的**区块链**信使。"; -/* 欢迎:幻灯片2说明 */ +/* Welcome: Slide 2 Description */ "WelcomeScene.Description.Slide2" = "ADAMANT是您的消息以及聊天加密货币传输工具的**匿名性**和**安全性**。\n\n[为什么其他消息不安全?](https://medium.com/adamant-im/adamant-security-features-e7cc836ff52c)"; -/* 欢迎:幻灯片3说明 */ +/* Welcome: Slide 3 Description */ "WelcomeScene.Description.Slide3" = "ADAMANT基础设施不属于任何人,是**去中心化的**。\n\n它由ADM代币支付的消息维护。新帐户可能会收到免费代币用于测试。"; -/* 欢迎:幻灯片4说明 */ +/* Welcome: Slide 4 Description */ "WelcomeScene.Description.Slide4" = "无需任何要求即可单击**创建帐户**(无需电子邮件/电话/任何内容)并邀请您的朋友。\n\n为了真正的安全起见,请亲自**共享您的ADAMANT地址。"; -/* 欢迎:幻灯片5说明 */ +/* Welcome: Slide 5 Description */ "WelcomeScene.Description.Slide5" = "项目的源代码[完全开放](https://github.com/Adamant-im/).该应用程序正在开发中,我们不断添加新功能。\n\n如果您是开发人员,请加入我们的团队。"; -/* 欢迎场景。描述开始按钮 */ +/* WelcomeScene.Description.BeginButton */ "WelcomeScene.Description.BeginButton" = "启动安全消息"; -/* 欢迎:下一屏幕按钮 */ +/* Welcome: Next screen button */ "WelcomeScene.Description.ContinueButton" = "继续"; -/* 欢迎:跳过按钮 */ +/* Welcome: Skip button */ "WelcomeScene.Description.SkipButton" = "跳过"; /* Welcome: Description accept */ "WelcomeScene.Description.Accept" = "我接受"; -/* 欧拉 */ +/* EULA */ "EULA.Title" = "服务条款"; "EULA.Accept" = "接受"; "EULA.Decline" = "拒绝"; "EULA.Text" = "ADAMANT Messenger基于去中心化的区块链技术,因此:\n\n✓ ADAMANT Messenger不容忍令人反感的内容或辱骂用户\n✓ ADAMANT Messenger最初专注于通信的安全性和用户的隐私。\n✓ ADAMANT Messenger始终显示完全开源的代码,许可证为GPL-3.0。源代码可在GitHub:GitHub.com/stend-im上获得。\n✓ ADAMANT Messenger按\"原样\"提供,不提供任何担保。\n✓ 开发人员只是ADAMANT Messenger的贡献者和用户。\n✓ 开发人员不控制用户的任何操作。\n✓ 开发人员在ADAMANT Messenger中没有权限。\n✓ 开发人员不可能禁用或阻止ADAMANT Messenger中的任何帐户。\n✓ 开发人员不可能获得加密密钥或读取任何ADAMANT Messenger用户的通信或其他信息。\n✓ 如果丢失,开发人员不可能恢复对任何用户帐户的访问。用户有责任保护自己的帐户的安全。\n✓ 开发人员不对用户内容、消息、媒体以及使用ADAMANT Messenger的目标和意图负责。\n✓ 开发者不存储用户之间传输的任何信息(消息、多媒体),也不对其在区块链上/中的存储负责。\n✓ 开发者不可能访问,也不对连接到ADAMANT Messenger或通过ADAMANT信使发送的任何资产(包括但不限于:加密货币)负责。\n✓ ADAMANT Messenger利用元数据作为账户之间通信的事实,在其区块链中公开提供。\n✓ 开发者不与任何第三方或外部服务合作提供任何使用数据。\n✓ ADAMANT信使基础设施(区块链节点)属于其用户,由用户运行。\n✓ 开发人员不可能停用、停止或暂停ADAMANT Messenger。开发人员对ADAMANT Messenger的运行不提供任何保证。\n✓ 开发人员不承担与ADAMANT Messenger相关的可能风险、成本和故障。\n✓ ADAMANT Messenger的用户从此对其使用承担全部责任,包括但不限于:区块链和Messenger内应用的其他技术的合法性,使用匿名消息服务,以及其他管辖法律。\n\n通过使用ADAMANT Messenger,您从此接受这些服务条款。"; -/* 回复:未知短信错误 */ +/* Reply: Short unknown message error */ "Reply.ShortUnknownMessageError" = "未知消息"; -/* 回复:长未知消息错误 */ +/* Reply: Long unknown message error */ "Reply.LongUnknownMessageError" = "我们没有找到此邮件"; -/* 回复:失败的消息回复错误 */ +/* Reply: Failed message reply error */ "Reply.failedMessageError" = "无法回复失败的消息"; -/* 挂起的消息回复错误 */ +/* Pending message reply error */ "Reply.pendingMessageError" = "您无法回复挂起的消息。请等待确认(估计1-2秒)"; -/* 包括合作伙伴名称 */ +/* Include partner name */ "PartnerQR.includePartnerName" = "包括联系人姓名"; -/* 包括合作伙伴url */ +/* Include partner url */ "PartnerQR.includePartnerURL" = "包括Web应用程序链接"; From 68ec9b606a9e3242f8dc21aaf3ec486b3e2b9b55 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Fri, 12 Jan 2024 19:29:09 +0200 Subject: [PATCH 22/27] [trello.com/c/AT07OnsL] fix: update system accounts name when change language --- Adamant/App/AppDelegate.swift | 1 + .../AdamantAccountsProvider.swift | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/Adamant/App/AppDelegate.swift b/Adamant/App/AppDelegate.swift index e17971c03..64b21f67a 100644 --- a/Adamant/App/AppDelegate.swift +++ b/Adamant/App/AppDelegate.swift @@ -572,6 +572,7 @@ extension AppDelegate { ) } + // TODO: Figireout why we cant use AdamantContacts.adamantWelcomeWallet.address for senderId (chat is not shown) if let welcome = AdamantContacts.adamantWelcomeWallet.welcomeMessage { _ = try? await chatProvider.fakeReceived( message: welcome.message, diff --git a/Adamant/Services/DataProviders/AdamantAccountsProvider.swift b/Adamant/Services/DataProviders/AdamantAccountsProvider.swift index a0dda4a56..04babdba3 100644 --- a/Adamant/Services/DataProviders/AdamantAccountsProvider.swift +++ b/Adamant/Services/DataProviders/AdamantAccountsProvider.swift @@ -9,6 +9,7 @@ import Foundation import CoreData import CommonKit +import Combine // MARK: - Provider @MainActor @@ -46,6 +47,7 @@ final class AdamantAccountsProvider: AccountsProvider { // MARK: Properties private let knownContacts: [String:KnownContact] + private var subscriptions = Set() // MARK: Lifecycle nonisolated init( @@ -139,6 +141,31 @@ final class AdamantAccountsProvider: AccountsProvider { } } } + + Task { + await addObservers() + } + } + + private func addObservers() { + NotificationCenter.default + .publisher(for: .LanguageStorageService.languageUpdated) + .receive(on: OperationQueue.main) + .sink { [weak self] _ in + Task { + await self?.updateSystemAccountsName() + } + } + .store(in: &subscriptions) + } + + private func updateSystemAccountsName() async { + for account in AdamantContacts.allCases { + let accountInDataBase = try? await getAccount(byAddress: account.address) + let newName = account.name.checkAndReplaceSystemWallets() + accountInDataBase?.name = newName + accountInDataBase?.chatroom?.title = newName + } } private func getAccount( From 770d109614bb20656b87437a33fd1e63d0c6cb90 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Fri, 12 Jan 2024 19:30:25 +0200 Subject: [PATCH 23/27] [trello.com/c/AT07OnsL] fix: localization in eth wallet --- .../Wallets/Ethereum/EthWalletViewController.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Adamant/Modules/Wallets/Ethereum/EthWalletViewController.swift b/Adamant/Modules/Wallets/Ethereum/EthWalletViewController.swift index a6948fb56..9345c01d1 100644 --- a/Adamant/Modules/Wallets/Ethereum/EthWalletViewController.swift +++ b/Adamant/Modules/Wallets/Ethereum/EthWalletViewController.swift @@ -10,9 +10,13 @@ import UIKit import CommonKit extension String.adamant.wallets { - static let ethereum = String.localized("AccountTab.Wallets.ethereum_wallet", comment: "Account tab: Ethereum wallet") + static var ethereum: String { + String.localized("AccountTab.Wallets.ethereum_wallet", comment: "Account tab: Ethereum wallet") + } - static let sendEth = String.localized("AccountTab.Row.SendEth", comment: "Account tab: 'Send ETH tokens' button") + static var sendEth: String { + String.localized("AccountTab.Row.SendEth", comment: "Account tab: 'Send ETH tokens' button") + } } final class EthWalletViewController: WalletViewControllerBase { From 1955d0da02c017ef748411b01753d6f424233df5 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Fri, 12 Jan 2024 19:40:22 +0200 Subject: [PATCH 24/27] [trello.com/c/AT07OnsL] fix: contribute screen localization --- .../Settings/Contribute/ContributeState.swift | 84 ++++++++++--------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/Adamant/Modules/Settings/Contribute/ContributeState.swift b/Adamant/Modules/Settings/Contribute/ContributeState.swift index cc78b0eea..201ca1ec5 100644 --- a/Adamant/Modules/Settings/Contribute/ContributeState.swift +++ b/Adamant/Modules/Settings/Contribute/ContributeState.swift @@ -21,47 +21,49 @@ struct ContributeState { let crashButtonTitle: String let linkRows: [LinkRow] - static let initial = Self( - isCrashlyticsOn: false, - isCrashButtonOn: false, - name: .localized("AccountTab.Row.Contribute", comment: .empty), - crashliticsRowImage: .asset(named: "row_crashlytics") ?? .init(), - crashliticsRowName: .localized("Contribute.Section.Crashlytics", comment: .empty), - crashliticsRowDescription: .localized("Contribute.Section.CrashlyticsDescription", comment: .empty), - crashButtonTitle: "Simulate crash", - linkRows: [ - .init( - image: .asset(named: "row_nodes") ?? .init(), - name: .localized("Contribute.Section.RunNodes", comment: .empty), - description: .localized("Contribute.Section.RunNodesDescription", comment: .empty), - link: URL(string: "https://news.adamant.im/how-to-run-your-adamant-node-on-ubuntu-990e391e8fcc") - ), - .init( - image: .asset(named: "row_vote-delegates") ?? .init(), - name: .localized("Contribute.Section.NetworkDelegate", comment: .empty), - description: .localized("Contribute.Section.NetworkDelegateDescription", comment: .empty), - link: URL(string: "https://news.adamant.im/how-to-become-an-adamant-delegate-745f01d032f") - ), - .init( - image: .asset(named: "row_github") ?? .init(), - name: .localized("Contribute.Section.CodeContribute", comment: .empty), - description: .localized("Contribute.Section.CodeContributeDescription", comment: .empty), - link: URL(string: "https://github.com/Adamant-im") - ), - .init( - image: .asset(named: "row_buy-coins") ?? .init(), - name: .localized("Contribute.Section.Donate", comment: .empty), - description: .localized("Contribute.Section.DonateDescription", comment: .empty), - link: URL(string: "https://adamant.im/donate") - ), - .init( - image: .asset(named: "row_rate") ?? .init(), - name: .localized("Contribute.Section.Rate", comment: .empty), - description: .localized("Contribute.Section.RateDescription", comment: .empty), - link: URL(string: "https://itunes.apple.com/app/id1341473829?action=write-review") - ) - ] - ) + static var initial: ContributeState { + Self( + isCrashlyticsOn: false, + isCrashButtonOn: false, + name: .localized("AccountTab.Row.Contribute", comment: .empty), + crashliticsRowImage: .asset(named: "row_crashlytics") ?? .init(), + crashliticsRowName: .localized("Contribute.Section.Crashlytics", comment: .empty), + crashliticsRowDescription: .localized("Contribute.Section.CrashlyticsDescription", comment: .empty), + crashButtonTitle: "Simulate crash", + linkRows: [ + .init( + image: .asset(named: "row_nodes") ?? .init(), + name: .localized("Contribute.Section.RunNodes", comment: .empty), + description: .localized("Contribute.Section.RunNodesDescription", comment: .empty), + link: URL(string: "https://news.adamant.im/how-to-run-your-adamant-node-on-ubuntu-990e391e8fcc") + ), + .init( + image: .asset(named: "row_vote-delegates") ?? .init(), + name: .localized("Contribute.Section.NetworkDelegate", comment: .empty), + description: .localized("Contribute.Section.NetworkDelegateDescription", comment: .empty), + link: URL(string: "https://news.adamant.im/how-to-become-an-adamant-delegate-745f01d032f") + ), + .init( + image: .asset(named: "row_github") ?? .init(), + name: .localized("Contribute.Section.CodeContribute", comment: .empty), + description: .localized("Contribute.Section.CodeContributeDescription", comment: .empty), + link: URL(string: "https://github.com/Adamant-im") + ), + .init( + image: .asset(named: "row_buy-coins") ?? .init(), + name: .localized("Contribute.Section.Donate", comment: .empty), + description: .localized("Contribute.Section.DonateDescription", comment: .empty), + link: URL(string: "https://adamant.im/donate") + ), + .init( + image: .asset(named: "row_rate") ?? .init(), + name: .localized("Contribute.Section.Rate", comment: .empty), + description: .localized("Contribute.Section.RateDescription", comment: .empty), + link: URL(string: "https://itunes.apple.com/app/id1341473829?action=write-review") + ) + ] + ) + } } extension ContributeState { From 42e3e246c60d4951f28dd1c5f08f7f799f4c52dc Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Mon, 15 Jan 2024 14:43:19 +0200 Subject: [PATCH 25/27] [trello.com/c/AT07OnsL] code improvements --- Adamant.xcodeproj/project.pbxproj | 4 ---- .../ServiceProtocols/LanguageStorageProtocol.swift | 1 + .../CommonKit/Localization/AdamantLocalized.swift | 7 ++++--- .../Sources/CommonKit}/Models/Language.swift | 14 +++++++------- 4 files changed, 12 insertions(+), 14 deletions(-) rename {Adamant => CommonKit/Sources/CommonKit}/Models/Language.swift (71%) diff --git a/Adamant.xcodeproj/project.pbxproj b/Adamant.xcodeproj/project.pbxproj index 8dfeaf3ed..3960244e5 100644 --- a/Adamant.xcodeproj/project.pbxproj +++ b/Adamant.xcodeproj/project.pbxproj @@ -35,7 +35,6 @@ 3AC76E3D2AB09118008042C4 /* ElegantEmojiPicker in Frameworks */ = {isa = PBXBuildFile; productRef = 3AC76E3C2AB09118008042C4 /* ElegantEmojiPicker */; }; 3AF08D5F2B4EB3A200EB82B1 /* LanguageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF08D5E2B4EB3A200EB82B1 /* LanguageService.swift */; }; 3AF08D612B4EB3C400EB82B1 /* LanguageStorageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF08D602B4EB3C400EB82B1 /* LanguageStorageProtocol.swift */; }; - 3AF08D632B4EEAFF00EB82B1 /* Language.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF08D622B4EEAFF00EB82B1 /* Language.swift */; }; 3C06931576393125C61FB8F6 /* Pods_Adamant.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33975C0D891698AA7E74EBCC /* Pods_Adamant.framework */; }; 41047B70294B5EE10039E956 /* VisibleWalletsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41047B6F294B5EE10039E956 /* VisibleWalletsViewController.swift */; }; 41047B72294B5F210039E956 /* VisibleWalletsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41047B71294B5F210039E956 /* VisibleWalletsTableViewCell.swift */; }; @@ -676,7 +675,6 @@ 3AF08D5D2B4E7FFC00EB82B1 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/Localizable.strings; sourceTree = ""; }; 3AF08D5E2B4EB3A200EB82B1 /* LanguageService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageService.swift; sourceTree = ""; }; 3AF08D602B4EB3C400EB82B1 /* LanguageStorageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageStorageProtocol.swift; sourceTree = ""; }; - 3AF08D622B4EEAFF00EB82B1 /* Language.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Language.swift; sourceTree = ""; }; 41047B6F294B5EE10039E956 /* VisibleWalletsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleWalletsViewController.swift; sourceTree = ""; }; 41047B71294B5F210039E956 /* VisibleWalletsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleWalletsTableViewCell.swift; sourceTree = ""; }; 41047B73294C61D10039E956 /* VisibleWalletsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleWalletsService.swift; sourceTree = ""; }; @@ -2010,7 +2008,6 @@ 93E8EDCE2AF1CD9F003E163C /* NodeStatusInfo.swift */, 93B28EBF2B076667007F268B /* APIResponseModel.swift */, 936658902B0AB9DC00BDB2D3 /* NodeWithGroup.swift */, - 3AF08D622B4EEAFF00EB82B1 /* Language.swift */, ); path = Models; sourceTree = ""; @@ -3294,7 +3291,6 @@ 93ADE0722ACA66AF008ED641 /* VibrationSelectionView.swift in Sources */, 648C696F22915A12006645F5 /* DashTransaction.swift in Sources */, 3A41939A2A5D554A006A6B22 /* Reaction.swift in Sources */, - 3AF08D632B4EEAFF00EB82B1 /* Language.swift in Sources */, 93CCAE752B06CC3600EA5B94 /* LskNodeApiService.swift in Sources */, 6416B1A321AD7EA1006089AC /* LskTransactionDetailsViewController.swift in Sources */, 6449BA6F235CA0930033B936 /* ERC20WalletService+Send.swift in Sources */, diff --git a/Adamant/ServiceProtocols/LanguageStorageProtocol.swift b/Adamant/ServiceProtocols/LanguageStorageProtocol.swift index c922c7e98..629566766 100644 --- a/Adamant/ServiceProtocols/LanguageStorageProtocol.swift +++ b/Adamant/ServiceProtocols/LanguageStorageProtocol.swift @@ -7,6 +7,7 @@ // import Foundation +import CommonKit protocol LanguageStorageProtocol { func getLanguage() -> Language diff --git a/CommonKit/Sources/CommonKit/Localization/AdamantLocalized.swift b/CommonKit/Sources/CommonKit/Localization/AdamantLocalized.swift index 018953825..e2e9bdf77 100644 --- a/CommonKit/Sources/CommonKit/Localization/AdamantLocalized.swift +++ b/CommonKit/Sources/CommonKit/Localization/AdamantLocalized.swift @@ -12,9 +12,10 @@ public extension String { enum adamant {} static func localized(_ key: String, comment: String = .empty) -> String { - guard let language = UserDefaults.standard.string(forKey: StoreKey.language.language), - !language.isEmpty, - let path = Bundle.module.path(forResource: language, ofType: "lproj") + guard let languageRaw = UserDefaults.standard.string(forKey: StoreKey.language.language), + !languageRaw.isEmpty, + languageRaw != Language.auto.rawValue, + let path = Bundle.module.path(forResource: languageRaw, ofType: "lproj") else { return NSLocalizedString(key, bundle: .module, comment: comment) } diff --git a/Adamant/Models/Language.swift b/CommonKit/Sources/CommonKit/Models/Language.swift similarity index 71% rename from Adamant/Models/Language.swift rename to CommonKit/Sources/CommonKit/Models/Language.swift index caf354c46..d1edbd56b 100644 --- a/Adamant/Models/Language.swift +++ b/CommonKit/Sources/CommonKit/Models/Language.swift @@ -8,20 +8,20 @@ import Foundation -extension Notification.Name { +public extension Notification.Name { struct LanguageStorageService { - static let languageUpdated = Notification.Name("adamant.language.languageUpdated") + public static let languageUpdated = Notification.Name("adamant.language.languageUpdated") } } -enum Language: String { +public enum Language: String { case ru case en case de case zh - case auto = "" + case auto - var name: String { + public var name: String { switch self { case .ru: return "Русский" case .en: return "English" @@ -31,7 +31,7 @@ enum Language: String { } } - var locale: String { + public var locale: String { switch self { case .ru: return "ru_RU" case .en: return "en_EN" @@ -41,5 +41,5 @@ enum Language: String { } } - static let all: [Language] = [.auto, .en, .ru, .de, .zh] + public static let all: [Language] = [.auto, .en, .ru, .de, .zh] } From 756bb2d72179c6c0f44f53ba5a7109c7f000cc84 Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Mon, 15 Jan 2024 14:57:09 +0200 Subject: [PATCH 26/27] [trello.com/c/v31G9yHx] feat: Add STORJ token --- .../storj_notification.imageset/Contents.json | 23 ++++++++++++++++++ .../storj_notification.png | Bin 0 -> 1320 bytes .../storj_notification@2x.png | Bin 0 -> 2734 bytes .../storj_notification@3x.png | Bin 0 -> 4434 bytes .../storj_wallet.imageset/Contents.json | 23 ++++++++++++++++++ .../storj_wallet.imageset/storj_wallet.png | Bin 0 -> 1320 bytes .../storj_wallet.imageset/storj_wallet@2x.png | Bin 0 -> 2734 bytes .../storj_wallet.imageset/storj_wallet@3x.png | Bin 0 -> 4434 bytes .../storj_wallet_row.imageset/Contents.json | 23 ++++++++++++++++++ .../storj_wallet_row.png | Bin 0 -> 1320 bytes .../storj_wallet_row@2x.png | Bin 0 -> 2734 bytes .../storj_wallet_row@3x.png | Bin 0 -> 4434 bytes .../CommonKit/Models/ethereumTokensList.swift | 12 +++++++++ .../storj_notificationContent.png | Bin 0 -> 4434 bytes 14 files changed, 81 insertions(+) create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_notification.imageset/Contents.json create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_notification.imageset/storj_notification.png create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_notification.imageset/storj_notification@2x.png create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_notification.imageset/storj_notification@3x.png create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet.imageset/Contents.json create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet.imageset/storj_wallet.png create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet.imageset/storj_wallet@2x.png create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet.imageset/storj_wallet@3x.png create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet_row.imageset/Contents.json create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet_row.imageset/storj_wallet_row.png create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet_row.imageset/storj_wallet_row@2x.png create mode 100644 CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet_row.imageset/storj_wallet_row@3x.png create mode 100644 NotificationServiceExtension/WalletImages/storj_notificationContent.png diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_notification.imageset/Contents.json b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_notification.imageset/Contents.json new file mode 100644 index 000000000..6c5b00d47 --- /dev/null +++ b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_notification.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "storj_notification.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "storj_notification@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "storj_notification@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_notification.imageset/storj_notification.png b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_notification.imageset/storj_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..5bbfbec4aa281d21a573623db25bae92513aa10b GIT binary patch literal 1320 zcmV+@1=sqCP);VOU*@Ku2C^F^Qf2mF4WLdw6=*k=5;<=>lp z{%ynd`D&-gkRcrwG(y_Jh~1LLkw$QJZb`;;`6%LQN@IxQ=k+FC^QIxgeC&!;KBTe1 zk*^O#?D!) zs~LczNJhLX*xh}>y(x_~jTc^!v&S6b0R`GaSGp-gnZsk(g-8ol2ixgsK z9FR;emlDL4@10+GA%~>b2Klk8>9H}z=#9a!72NF}m+o=?ej&s3qTn5AM(TGYy_dN= z2mj{rNGlPG>uZ2Ow*^&Q3UK z(gd3}Sf=!VUI*chJFR%gO$Gmi8^|i+k`im~SqUu@pd_OYuZSL`qY6peb)0=9b+LnU zEmVAc@pa?o$SbiHu}9uil6blpb+>{NJF<3P+Qk8&~c%Yu@cK1*DHFcE)gD_l&nqbEMkZ-vaT%$$SJRi zt3i>z;%Y)kHj3l4hx<9%o@gi(9zdx_+#jOXq7bnMYP2uu9iHvZRjS^RQf4`GyZ{_b zJ31{{I2d=%wuhps_b05rCt~UWd9!H6XKV~97vTS6xS)0W!Bv|f5IcT^!Q%?9OdOKTcL3e{E)XbpqY3lP>?Y-5g-eS$c%btOhdM#Tx-{9wyM zY-Y&fpPa-un_B*1CYqrbJaWXY-7&_piD*4?Sc}e!V?CU zj=A4(%@mYqW61%Xr2-qY{L&eQfq_mvkf5ItqdoA(2n+KhP;o7LAgFq3Q>!}0<*@=~ z^qc5RsYD+X%ZFTVwPljnoQ@7NWM@<+b({QCxyp z%9?SH3C`V|Rn%%Pc_Q>%iXAT9+LIG|F7l288D!{HD$l9bo(E<-5+u_1S|Caf=rs}y zd<^|Fjbp!Ei8ghF2?q`+jVsC1Z=RXw7)t3zhSmdmlW)jXzSkbyOzE1?zp<(==%swdciOi^)}nzeHIg$G0k?1e+3 zYLWy-)$*9ytN;&ubXmn~Y$HU;Ry!1|C=XW)@b$i|3^Lp*7B00bU>j`I(&jS_W8rL> zgG_~VgqFH~?{$1Zl#ysv^{&`}`a)tS&JQNG(R#s4jFa3c)Ph@a?WDf$YeE|PB+>B6 z;To~Gme+0Ls;M?Z*;d3#@WV)>SB<)2)5gtFDs5H2MG)N~Qi*qUZYf+-8E`}l9tF@O eO+Np>00RITdY`ltuX>pP0000m+ zxgYiyyTFK@3H|ohe`EeJJ<{3@t$vr0Z>x`0ILX`e}GMCDjPLM$>YrOzBCAC7N=6Yw+b~t9|a297l7vC z^^v-q>llrJu(kwEbZS-z+9PlVz*4Bi#Pb%U-tIV~ONF}K9eLlN?BC~s*fCp55W|&< zU_CkVz7))FA=SOxzfU~_Himou)&giIYAevD0q{o84Apyiz`-SdgDo2xEdb!GuLt-rV^1+;BC|lr z>jL3J*}y*vGhSR~@<*0{sRH8?nT1peREwVN7}=Sn^!&@7z1J5LZtLp8!P~3s8+au;E2{Fr zL?^K}0eH#YXOwg4$LAE6H0bt%Kfo2UFZekpS}{YS8J=Ti5wKT268C~n@4%HF93Wp^ zNQgjA#TA85zOw_+a1Z$Nt21zjJ$^`?#`AFju;Rxx|L3)76b+b&Pt+)R*TQ^UUG!U+ zCTE+RlMK3gW&<8to5m*f$&V|j*>kXebx--!#AMXgq)n10q`dY`rf6gV2Dzk^uN*^K zRu~PHAlh}3G^vfUMPAdT;MK{#C~}oz61Od~Dwsu{^g-g^w!Tiozw4$M0^4aFpZT?l zS=1u7SenOdUK;O0zx4<6>qsq_MTxqh*Wu`UTLULN%o}sBPqcl}l=&CKRv7)cw^-J~rp})vKsj3s zH8p`c6wm($_NCPPuG|okGebXuaGg)D!=Qi@-RHT5+ELlo3h~W{0N1gaOnDF7hk(0* zB$pkk_dxl!IRbnC!A+;gVPn?^qXoeWTApy5iFl_?cm7M4q*3<(hIV=knV1r61%ViXbG!;qN>j^=tZJr#5ePaPqD8OY3 zN$aaV^InlSs3LHOlq!kyCkdX(It^)#Z8(N|ulyKkxAb>XwAZFTY-2aOPuI_G8 zu1Fv?i>PcLf%?e0?Zwj-^Y%KRf-cWe;@(VHGIE0K#=q2b~Hhna8x0I3{OC`0o>T3H; zsKgr#qN3s4g!wgnIBk4!Zf#aZyM*7G;J9J$^_jU03eHWDAV@nHh~9(T3OG$;V^d?^ z%3{H>Q#UqlSi8ln;Wjo(pyjNga|J4;JW+Rx3vf%;&FXo!-A4pS($sFu-aC{U!D}jr ztw*WV-Zd6#F=gkm0=k&>p_R}dOyLbwU)8|7AEgmg3J>tsh+o|Ta8z4O@PkK9*VBj- zw!b_V(Bv%24s|NW#&mP=+_cB5)#`bxW7g~lrMu-sbaeL-c-^@9uJ7u3^kDzt*cjB} zP;o^hjxp~-z`#x7kPRSFO*Ed5 zDgH|%UhnGCWuI|=Zk^w(Oc@!Q)$?l4=Zht1n~2o`tu6USpw;Ky`8p@HIA_9-?^HS) z%N_0_XpP|M_(vhts{mTolw@vf-Y0S8H?7$F)JuwdTA}cqDj3x0oP4AL>QCn1Sn|G! ze^#3!S;cX}0->1%SSmbN1~2K3g;AXq3Sd)sk;Id^;3=l;V|I$9?8*i-qE7b#hs|5C z)3yeOuqhHr&b-TwGdeBLgI7c&?NXMquWK-;UGH|%`2sb_buO{_YugK#g+w_!r_F5z z0Dl+8%yx43SJ{{dPXM=_Rndf1>Dor13_MI7K%y?+QwPhzdMbc^6^Sn z20L~gI%tECIEAz<*~jL^Ulf&SOZJ|dROK$|+J6N*_H^uSArUw`@F?r@s#23st#8sL zSBmW{>3X`))HWj@Rps&OvlP^uOk7Z zZ+8gho5}}^p}zd*0RvZ;5Bik9JqY)R5_e*%(^#(MZ(pEdt3H#&7Ym%Uto+)cd~l6F zvjGpleY`OnaPGMZD#?T;B1J^`6P|CCpnS6&$_M$iNLvmS1<2$ o&koBXN;o2qp(c%8>3;zR0OoX*Hl~?x*8l(j07*qoM6N<$g6>8#-~a#s literal 0 HcmV?d00001 diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_notification.imageset/storj_notification@3x.png b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_notification.imageset/storj_notification@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..152293b8d992210cba14427a3cfd0e5de5bddc15 GIT binary patch literal 4434 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 Y04R?rd^Bi9+W-In07*qoM6N<$g2TgLZvX%Q literal 0 HcmV?d00001 diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet.imageset/Contents.json b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet.imageset/Contents.json new file mode 100644 index 000000000..f04d7e847 --- /dev/null +++ b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "storj_wallet.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "storj_wallet@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "storj_wallet@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet.imageset/storj_wallet.png b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet.imageset/storj_wallet.png new file mode 100644 index 0000000000000000000000000000000000000000..5bbfbec4aa281d21a573623db25bae92513aa10b GIT binary patch literal 1320 zcmV+@1=sqCP);VOU*@Ku2C^F^Qf2mF4WLdw6=*k=5;<=>lp z{%ynd`D&-gkRcrwG(y_Jh~1LLkw$QJZb`;;`6%LQN@IxQ=k+FC^QIxgeC&!;KBTe1 zk*^O#?D!) zs~LczNJhLX*xh}>y(x_~jTc^!v&S6b0R`GaSGp-gnZsk(g-8ol2ixgsK z9FR;emlDL4@10+GA%~>b2Klk8>9H}z=#9a!72NF}m+o=?ej&s3qTn5AM(TGYy_dN= z2mj{rNGlPG>uZ2Ow*^&Q3UK z(gd3}Sf=!VUI*chJFR%gO$Gmi8^|i+k`im~SqUu@pd_OYuZSL`qY6peb)0=9b+LnU zEmVAc@pa?o$SbiHu}9uil6blpb+>{NJF<3P+Qk8&~c%Yu@cK1*DHFcE)gD_l&nqbEMkZ-vaT%$$SJRi zt3i>z;%Y)kHj3l4hx<9%o@gi(9zdx_+#jOXq7bnMYP2uu9iHvZRjS^RQf4`GyZ{_b zJ31{{I2d=%wuhps_b05rCt~UWd9!H6XKV~97vTS6xS)0W!Bv|f5IcT^!Q%?9OdOKTcL3e{E)XbpqY3lP>?Y-5g-eS$c%btOhdM#Tx-{9wyM zY-Y&fpPa-un_B*1CYqrbJaWXY-7&_piD*4?Sc}e!V?CU zj=A4(%@mYqW61%Xr2-qY{L&eQfq_mvkf5ItqdoA(2n+KhP;o7LAgFq3Q>!}0<*@=~ z^qc5RsYD+X%ZFTVwPljnoQ@7NWM@<+b({QCxyp z%9?SH3C`V|Rn%%Pc_Q>%iXAT9+LIG|F7l288D!{HD$l9bo(E<-5+u_1S|Caf=rs}y zd<^|Fjbp!Ei8ghF2?q`+jVsC1Z=RXw7)t3zhSmdmlW)jXzSkbyOzE1?zp<(==%swdciOi^)}nzeHIg$G0k?1e+3 zYLWy-)$*9ytN;&ubXmn~Y$HU;Ry!1|C=XW)@b$i|3^Lp*7B00bU>j`I(&jS_W8rL> zgG_~VgqFH~?{$1Zl#ysv^{&`}`a)tS&JQNG(R#s4jFa3c)Ph@a?WDf$YeE|PB+>B6 z;To~Gme+0Ls;M?Z*;d3#@WV)>SB<)2)5gtFDs5H2MG)N~Qi*qUZYf+-8E`}l9tF@O eO+Np>00RITdY`ltuX>pP0000m+ zxgYiyyTFK@3H|ohe`EeJJ<{3@t$vr0Z>x`0ILX`e}GMCDjPLM$>YrOzBCAC7N=6Yw+b~t9|a297l7vC z^^v-q>llrJu(kwEbZS-z+9PlVz*4Bi#Pb%U-tIV~ONF}K9eLlN?BC~s*fCp55W|&< zU_CkVz7))FA=SOxzfU~_Himou)&giIYAevD0q{o84Apyiz`-SdgDo2xEdb!GuLt-rV^1+;BC|lr z>jL3J*}y*vGhSR~@<*0{sRH8?nT1peREwVN7}=Sn^!&@7z1J5LZtLp8!P~3s8+au;E2{Fr zL?^K}0eH#YXOwg4$LAE6H0bt%Kfo2UFZekpS}{YS8J=Ti5wKT268C~n@4%HF93Wp^ zNQgjA#TA85zOw_+a1Z$Nt21zjJ$^`?#`AFju;Rxx|L3)76b+b&Pt+)R*TQ^UUG!U+ zCTE+RlMK3gW&<8to5m*f$&V|j*>kXebx--!#AMXgq)n10q`dY`rf6gV2Dzk^uN*^K zRu~PHAlh}3G^vfUMPAdT;MK{#C~}oz61Od~Dwsu{^g-g^w!Tiozw4$M0^4aFpZT?l zS=1u7SenOdUK;O0zx4<6>qsq_MTxqh*Wu`UTLULN%o}sBPqcl}l=&CKRv7)cw^-J~rp})vKsj3s zH8p`c6wm($_NCPPuG|okGebXuaGg)D!=Qi@-RHT5+ELlo3h~W{0N1gaOnDF7hk(0* zB$pkk_dxl!IRbnC!A+;gVPn?^qXoeWTApy5iFl_?cm7M4q*3<(hIV=knV1r61%ViXbG!;qN>j^=tZJr#5ePaPqD8OY3 zN$aaV^InlSs3LHOlq!kyCkdX(It^)#Z8(N|ulyKkxAb>XwAZFTY-2aOPuI_G8 zu1Fv?i>PcLf%?e0?Zwj-^Y%KRf-cWe;@(VHGIE0K#=q2b~Hhna8x0I3{OC`0o>T3H; zsKgr#qN3s4g!wgnIBk4!Zf#aZyM*7G;J9J$^_jU03eHWDAV@nHh~9(T3OG$;V^d?^ z%3{H>Q#UqlSi8ln;Wjo(pyjNga|J4;JW+Rx3vf%;&FXo!-A4pS($sFu-aC{U!D}jr ztw*WV-Zd6#F=gkm0=k&>p_R}dOyLbwU)8|7AEgmg3J>tsh+o|Ta8z4O@PkK9*VBj- zw!b_V(Bv%24s|NW#&mP=+_cB5)#`bxW7g~lrMu-sbaeL-c-^@9uJ7u3^kDzt*cjB} zP;o^hjxp~-z`#x7kPRSFO*Ed5 zDgH|%UhnGCWuI|=Zk^w(Oc@!Q)$?l4=Zht1n~2o`tu6USpw;Ky`8p@HIA_9-?^HS) z%N_0_XpP|M_(vhts{mTolw@vf-Y0S8H?7$F)JuwdTA}cqDj3x0oP4AL>QCn1Sn|G! ze^#3!S;cX}0->1%SSmbN1~2K3g;AXq3Sd)sk;Id^;3=l;V|I$9?8*i-qE7b#hs|5C z)3yeOuqhHr&b-TwGdeBLgI7c&?NXMquWK-;UGH|%`2sb_buO{_YugK#g+w_!r_F5z z0Dl+8%yx43SJ{{dPXM=_Rndf1>Dor13_MI7K%y?+QwPhzdMbc^6^Sn z20L~gI%tECIEAz<*~jL^Ulf&SOZJ|dROK$|+J6N*_H^uSArUw`@F?r@s#23st#8sL zSBmW{>3X`))HWj@Rps&OvlP^uOk7Z zZ+8gho5}}^p}zd*0RvZ;5Bik9JqY)R5_e*%(^#(MZ(pEdt3H#&7Ym%Uto+)cd~l6F zvjGpleY`OnaPGMZD#?T;B1J^`6P|CCpnS6&$_M$iNLvmS1<2$ o&koBXN;o2qp(c%8>3;zR0OoX*Hl~?x*8l(j07*qoM6N<$g6>8#-~a#s literal 0 HcmV?d00001 diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet.imageset/storj_wallet@3x.png b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet.imageset/storj_wallet@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..152293b8d992210cba14427a3cfd0e5de5bddc15 GIT binary patch literal 4434 zcmV-Y5v}ftP)>DFVq6SQCNi2&}p8#heI68N6kC8qY9I;vXbP_E)8nOO{9w z_|QK9{=~B(UE%03?u3SV=_L}5U~zG&LxqP zNEw2VK*qZo(&feLSMmBwB0bjyG4H7-iIhIbI4RzC#cL*f3?y6^uR}q!Q_XMS`>W!W z2>;p_-(OI#5-D9t`6LkXgc5IK@cTPd`9w@2r58fpqqO6Myt1(k(H4C!UK3K~L`oMz zg4%s^C8Th@6p6`kUR*Dyp8kq6>VjH4l$;bN@45JWhIS~&in^F2rLC0A3qqZHy!M;m z{E)OHNvRFd)82Z%_O|9e1jLxSpc0qD-vdrO1YLIv-zCYvVb+#p3FE8DPK%`WH+k7f}@7C~hR=RFNT}`A6MPA*{tEBCOx{*k! zB1vlS^`qhERhUz+lcOV(Sg<9yGLU#{v?Zq{LasG!R=@+^dsDTKK19$uOMQ7?YU>l5&W{{)P4jEI7S6l@qBtR8RF%R5^cTE7#Yq$#) zJ;psDV}hP-OoQ{Sq5HtILu8V+SwW->Z#S+yIT0b$Ym4%gN+yI1x$-ifjZCQ>zlWK~_b=fn{WFDYkH-_FCBz(mj?ai$!*raBB z!Ff9R3=$c8AR?D;GYO$q#rNPHX62(uP!Azx1b0kujBZ#dL{4*j;d>xy;dg6SFMs4f zMwciYAmOPrhdZ=a7dC2r?17N)`E!_j{p)@4R&i>O5GPKk()TjWSB&kl z=o*{!zlYdIj=hS;HT9QlfK{2(u{j@#LubNsY&+ zwsTM8yBD-!iav=q@7pNdGTt0sxyA#+df1$}5DiSm_o$&Uw}MRxJW?KX(^cQ%d6P`h zU|3LpLofXeH~uG**_06vqQObFe1jQAo`v!KjpHq~PldlPecF`&c-)GNVj%I##}iVf zKC(c>i~}mi^NxL8RKJsj!j&}T#3w2FaZ;72zNz{AlE%9ixHKGhE1_d5DV5@%#;x1x zJJ9cfES__wtGuVjn$Le&{*KTrUKIcTVL5)&5TxWt6i&-~=u&CsY*eX5aOq%4lD1U| zxzre^P04%asbgg6YeYikI*l0{%%D_o>-Um|-xqK9ro93Wj8V`bl2Q@sVH9Rod~eA< zFN&*>8c1RzNh!{R+fcoO`{J;ha6uk^AP2$4e`=~)7TT%jjP}W0?8ft^a#_)4^{S|3)bdI~!o!RGs;HRLZ6dL}-zV3rUBYxofiG7^afPjvf zqyyKsl@}UHC2dSf!LFKMKm7~eLrx-IZ~We}FXuRsCX!W{pMs|1)N*VwUmOA^wx1QW!R=HlF5ASTJOgPDO0pDV^c#ukMd?LU_Non(k4-wJw~a}A=x{hG`4l=h1nsdm z=D#upkjGmNa@-nxMj?@Obzu8Yn-PfehWoUW0E7g>ge?5YYu-FKv~eOFZBDyBpnWPB zx?-LyZQ)wpuA%nBQPrJA8)L7$W{ffG7r4}6y3PUGUwn`HQm|Lk7E~ZaPrc~0z0Z}` z`bJ8I-t%5%d$Eu0z1R}}L%HPI#P*R^>?Kl4aFnI6>qzx7zOHyxN7_CUvTru!`<9?W zIzF>*B*#xB`5b$HETm7QtlfUYC7oC1H&m<%$F1@?`%cWhkTR>YBZV!yt`&_+tB#uB zZqt@X89!uaK%Q84tC&?Lj>3KUBat$0DVfzs$$7_}0$JOaM9O%vwXn;&f?69GC*p=k z8KK8r7XXY>GU@sNDYB7(*^(0}BU9ay|9$Vt7~M#uB{)3`B4u3oX=#sj2~dM(R~Kx8 zYJ5$kj9gOULV2I+hJz_mn~em$@ja0;ZX`W@CRywyc;iPRC7}&GNEX$XL`p&%;KwrR z?8`lolF$aG5;guvq>RvZ97q+jTgkKMM9TK?P4d6Kmu;R(&Lka(l`KrG+C%eYcERjct`P%8^c_jLG0f^gT-ZM5K(=1Ft*J($|0mPDq=q$3)8J zP#ZUip>2I6=E2edBvLlzg-cHV@x%muBc?1e=o^tT5>H(APb4PP;OT?PQ{}iMN!cN2K|VyU+iN|RLsYoY7io1y>DpK3;SBny{c{2 z<)=rMgnTY_uu`p|G@Ak-ZcXORooA@WM5JEOmW<_6D6D(&VX4-LN>Cq(#HZu4dV{U*+~B( zFRlf@;!YM?XidtJDq1(Oy8;hVyxtVXH$e~Y+l|nlCIoRH=8=7l`CNG=CE9WPLGsYS z5Pd0p87ZJY8!5DkJmIEVs(U|ONhvPpYy*<9SA{Pl2QRex5Tej(4PRzHNqH&!eNYe! z>I?pc{cwCeXcCg_#tztVo*D*K>?;VZT0$aEI}WIX&ZdG`()#Mim&BwI zx}^N6>(*nvZ8#+e^{V-4!;``}B1EFT>nc#-*n*>b#mAQY*=ANHd6=1MOx?Y2aO+os zQM*?V(`2{jJ8>Z@Kor+PF}|6>^=?W$@*^pcWSnTJuWc$JoQ)6<=Dv1%Pz!RdDOz@_jU5E*#-I$;7dqMz*2gk>SkPx@P z`H`8NEHGWCTnL`{)P|V2zr7>1-3c}RWHG)8s|W-S;eB&ynWNVw67x-C|C2WuzV}Lm z>-TCWZ2^nLIb8~cZde@3BB?c_Brh_KlEghH>V5e!f^>-HvTq2RAA@9o8bn95wuayH2zTkoO1s$i+j53mJ|NCmSc9?)W<8d>Y%f zn&%TQ$hk&|P@XAe@XQojVfGv%IF(5FEDgm|kQ-e7yJhNFNUkZJGl`6RJ`p~^v_wv5 z>`}Jh8ZwOtsc$VP&x@B5DU^wP^m#mH6jRT%km-U*8Br=4XZ0Nd*fC%dJTiZ2LRIM}`>F8MJz*q_Lreawv<$KH$R<=+=l zbB|J!Lfy=9K(9LQLSx5W=~e8|YxMA8n=&D;DRD$HW?gFZxNE(P9enONH)h|^Y6Xp6 z+ms4&ZqVM`5C=cuyv1P!w2LtgfAA4Y>mFAa3dGDk9I zeR-fh6%2hZqm1S4)+~I1_M_wfec6rYeIg`a#CnQ=mA16iByO9AFe~=VGU+~%G7fV3 zOh>)8NpkOTA3S3bS6(AhniFG=#7LSXq;P+i#QZt4Osr3&?1oCW36TR^_1eSzAzI&L zN6M)L2{}65aD+}cz!yxBP@#mSrzR{69586##n1>jI7wL{xl*Pso440UO=5D-2PQvK zkg-TZ%7~QB+naSEau+hk0!;#bC@x1;e^NMJuQhh#I`#-2B4s=F=BlLfM~dH+tFI}G z89`d+(gc8Y)lFZQcuX;-F8HuF*`E-(42i~7sSGRjH9B6Wn9)%%8Loz`st51rXp+-} zAXCH7UGGPvBq&j*Zgc7yBBgI|QYDJ-)zuVIrCXi~YMel%)B-0M-h?D7IXb3*d^vpQ1>QFbVw%{6^U{3?Bq_BZ?lIqbzP53?Wg;bk2Mr$t6@KsI zx_BLK4($67B~GMl7UDYN$~DhB?&N$bPfcA+q_mNiB5|H9t`1hn_9CKZqg;vhvSnKMc7gb<`r4k`vabwPXFL`q-etP42< zNy?XY{$kZR903q;v80|PQu-!l%GB|fRis_h9ygIPG&w;U-XJ-vf-iW5wnrkPIsPxe Y04R?rd^Bi9+W-In07*qoM6N<$g2TgLZvX%Q literal 0 HcmV?d00001 diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet_row.imageset/Contents.json b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet_row.imageset/Contents.json new file mode 100644 index 000000000..018c82fbf --- /dev/null +++ b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet_row.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "storj_wallet_row.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "storj_wallet_row@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "storj_wallet_row@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet_row.imageset/storj_wallet_row.png b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet_row.imageset/storj_wallet_row.png new file mode 100644 index 0000000000000000000000000000000000000000..5bbfbec4aa281d21a573623db25bae92513aa10b GIT binary patch literal 1320 zcmV+@1=sqCP);VOU*@Ku2C^F^Qf2mF4WLdw6=*k=5;<=>lp z{%ynd`D&-gkRcrwG(y_Jh~1LLkw$QJZb`;;`6%LQN@IxQ=k+FC^QIxgeC&!;KBTe1 zk*^O#?D!) zs~LczNJhLX*xh}>y(x_~jTc^!v&S6b0R`GaSGp-gnZsk(g-8ol2ixgsK z9FR;emlDL4@10+GA%~>b2Klk8>9H}z=#9a!72NF}m+o=?ej&s3qTn5AM(TGYy_dN= z2mj{rNGlPG>uZ2Ow*^&Q3UK z(gd3}Sf=!VUI*chJFR%gO$Gmi8^|i+k`im~SqUu@pd_OYuZSL`qY6peb)0=9b+LnU zEmVAc@pa?o$SbiHu}9uil6blpb+>{NJF<3P+Qk8&~c%Yu@cK1*DHFcE)gD_l&nqbEMkZ-vaT%$$SJRi zt3i>z;%Y)kHj3l4hx<9%o@gi(9zdx_+#jOXq7bnMYP2uu9iHvZRjS^RQf4`GyZ{_b zJ31{{I2d=%wuhps_b05rCt~UWd9!H6XKV~97vTS6xS)0W!Bv|f5IcT^!Q%?9OdOKTcL3e{E)XbpqY3lP>?Y-5g-eS$c%btOhdM#Tx-{9wyM zY-Y&fpPa-un_B*1CYqrbJaWXY-7&_piD*4?Sc}e!V?CU zj=A4(%@mYqW61%Xr2-qY{L&eQfq_mvkf5ItqdoA(2n+KhP;o7LAgFq3Q>!}0<*@=~ z^qc5RsYD+X%ZFTVwPljnoQ@7NWM@<+b({QCxyp z%9?SH3C`V|Rn%%Pc_Q>%iXAT9+LIG|F7l288D!{HD$l9bo(E<-5+u_1S|Caf=rs}y zd<^|Fjbp!Ei8ghF2?q`+jVsC1Z=RXw7)t3zhSmdmlW)jXzSkbyOzE1?zp<(==%swdciOi^)}nzeHIg$G0k?1e+3 zYLWy-)$*9ytN;&ubXmn~Y$HU;Ry!1|C=XW)@b$i|3^Lp*7B00bU>j`I(&jS_W8rL> zgG_~VgqFH~?{$1Zl#ysv^{&`}`a)tS&JQNG(R#s4jFa3c)Ph@a?WDf$YeE|PB+>B6 z;To~Gme+0Ls;M?Z*;d3#@WV)>SB<)2)5gtFDs5H2MG)N~Qi*qUZYf+-8E`}l9tF@O eO+Np>00RITdY`ltuX>pP0000m+ zxgYiyyTFK@3H|ohe`EeJJ<{3@t$vr0Z>x`0ILX`e}GMCDjPLM$>YrOzBCAC7N=6Yw+b~t9|a297l7vC z^^v-q>llrJu(kwEbZS-z+9PlVz*4Bi#Pb%U-tIV~ONF}K9eLlN?BC~s*fCp55W|&< zU_CkVz7))FA=SOxzfU~_Himou)&giIYAevD0q{o84Apyiz`-SdgDo2xEdb!GuLt-rV^1+;BC|lr z>jL3J*}y*vGhSR~@<*0{sRH8?nT1peREwVN7}=Sn^!&@7z1J5LZtLp8!P~3s8+au;E2{Fr zL?^K}0eH#YXOwg4$LAE6H0bt%Kfo2UFZekpS}{YS8J=Ti5wKT268C~n@4%HF93Wp^ zNQgjA#TA85zOw_+a1Z$Nt21zjJ$^`?#`AFju;Rxx|L3)76b+b&Pt+)R*TQ^UUG!U+ zCTE+RlMK3gW&<8to5m*f$&V|j*>kXebx--!#AMXgq)n10q`dY`rf6gV2Dzk^uN*^K zRu~PHAlh}3G^vfUMPAdT;MK{#C~}oz61Od~Dwsu{^g-g^w!Tiozw4$M0^4aFpZT?l zS=1u7SenOdUK;O0zx4<6>qsq_MTxqh*Wu`UTLULN%o}sBPqcl}l=&CKRv7)cw^-J~rp})vKsj3s zH8p`c6wm($_NCPPuG|okGebXuaGg)D!=Qi@-RHT5+ELlo3h~W{0N1gaOnDF7hk(0* zB$pkk_dxl!IRbnC!A+;gVPn?^qXoeWTApy5iFl_?cm7M4q*3<(hIV=knV1r61%ViXbG!;qN>j^=tZJr#5ePaPqD8OY3 zN$aaV^InlSs3LHOlq!kyCkdX(It^)#Z8(N|ulyKkxAb>XwAZFTY-2aOPuI_G8 zu1Fv?i>PcLf%?e0?Zwj-^Y%KRf-cWe;@(VHGIE0K#=q2b~Hhna8x0I3{OC`0o>T3H; zsKgr#qN3s4g!wgnIBk4!Zf#aZyM*7G;J9J$^_jU03eHWDAV@nHh~9(T3OG$;V^d?^ z%3{H>Q#UqlSi8ln;Wjo(pyjNga|J4;JW+Rx3vf%;&FXo!-A4pS($sFu-aC{U!D}jr ztw*WV-Zd6#F=gkm0=k&>p_R}dOyLbwU)8|7AEgmg3J>tsh+o|Ta8z4O@PkK9*VBj- zw!b_V(Bv%24s|NW#&mP=+_cB5)#`bxW7g~lrMu-sbaeL-c-^@9uJ7u3^kDzt*cjB} zP;o^hjxp~-z`#x7kPRSFO*Ed5 zDgH|%UhnGCWuI|=Zk^w(Oc@!Q)$?l4=Zht1n~2o`tu6USpw;Ky`8p@HIA_9-?^HS) z%N_0_XpP|M_(vhts{mTolw@vf-Y0S8H?7$F)JuwdTA}cqDj3x0oP4AL>QCn1Sn|G! ze^#3!S;cX}0->1%SSmbN1~2K3g;AXq3Sd)sk;Id^;3=l;V|I$9?8*i-qE7b#hs|5C z)3yeOuqhHr&b-TwGdeBLgI7c&?NXMquWK-;UGH|%`2sb_buO{_YugK#g+w_!r_F5z z0Dl+8%yx43SJ{{dPXM=_Rndf1>Dor13_MI7K%y?+QwPhzdMbc^6^Sn z20L~gI%tECIEAz<*~jL^Ulf&SOZJ|dROK$|+J6N*_H^uSArUw`@F?r@s#23st#8sL zSBmW{>3X`))HWj@Rps&OvlP^uOk7Z zZ+8gho5}}^p}zd*0RvZ;5Bik9JqY)R5_e*%(^#(MZ(pEdt3H#&7Ym%Uto+)cd~l6F zvjGpleY`OnaPGMZD#?T;B1J^`6P|CCpnS6&$_M$iNLvmS1<2$ o&koBXN;o2qp(c%8>3;zR0OoX*Hl~?x*8l(j07*qoM6N<$g6>8#-~a#s literal 0 HcmV?d00001 diff --git a/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet_row.imageset/storj_wallet_row@3x.png b/CommonKit/Sources/CommonKit/Assets/Shared.xcassets/Wallets/storj_wallet_row.imageset/storj_wallet_row@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..152293b8d992210cba14427a3cfd0e5de5bddc15 GIT binary patch literal 4434 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 Y04R?rd^Bi9+W-In07*qoM6N<$g2TgLZvX%Q literal 0 HcmV?d00001 diff --git a/CommonKit/Sources/CommonKit/Models/ethereumTokensList.swift b/CommonKit/Sources/CommonKit/Models/ethereumTokensList.swift index 22b1dcdf9..d62fb8656 100644 --- a/CommonKit/Sources/CommonKit/Models/ethereumTokensList.swift +++ b/CommonKit/Sources/CommonKit/Models/ethereumTokensList.swift @@ -207,6 +207,18 @@ defaultGasPriceGwei: 30, defaultGasLimit: 58000, warningGasPriceGwei: 70), + ERC20Token(symbol: "STORJ", + name: "Storj", + contractAddress: "0xb64ef51c888972c908cfacf59b47c1afbc0ab8ac", + decimals: 8, + naturalUnits: 8, + defaultVisibility: true, + defaultOrdinalLevel: 100, + reliabilityGasPricePercent: 10, + reliabilityGasLimitPercent: 10, + defaultGasPriceGwei: 30, + defaultGasLimit: 58000, + warningGasPriceGwei: 70), ERC20Token(symbol: "TUSD", name: "TrueUSD", contractAddress: "0x0000000000085d4780b73119b644ae5ecd22b376", diff --git a/NotificationServiceExtension/WalletImages/storj_notificationContent.png b/NotificationServiceExtension/WalletImages/storj_notificationContent.png new file mode 100644 index 0000000000000000000000000000000000000000..152293b8d992210cba14427a3cfd0e5de5bddc15 GIT binary patch literal 4434 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 Y04R?rd^Bi9+W-In07*qoM6N<$g2TgLZvX%Q literal 0 HcmV?d00001 From f611327d7766d26627e96462a6a8ee998c4c8eae Mon Sep 17 00:00:00 2001 From: StanislavDevIOS Date: Mon, 15 Jan 2024 14:57:20 +0200 Subject: [PATCH 27/27] [trello.com/c/v31G9yHx] bump version --- Adamant.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Adamant.xcodeproj/project.pbxproj b/Adamant.xcodeproj/project.pbxproj index 3960244e5..ab5dee1ab 100644 --- a/Adamant.xcodeproj/project.pbxproj +++ b/Adamant.xcodeproj/project.pbxproj @@ -3710,7 +3710,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.3.1; + MARKETING_VERSION = 3.4.0; PRODUCT_BUNDLE_IDENTIFIER = "im.adamant.adamant-messenger-dev"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -3741,7 +3741,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.3.1; + MARKETING_VERSION = 3.4.0; PRODUCT_BUNDLE_IDENTIFIER = "im.adamant.adamant-messenger"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "";