From 1b4040135e5d13889af032a118e5e4d5e384ffc9 Mon Sep 17 00:00:00 2001 From: Danny Moesch Date: Mon, 14 Jan 2019 20:57:45 +0100 Subject: [PATCH] Localize strings in code --- pass.xcodeproj/project.pbxproj | 12 + pass/AppDelegate.swift | 4 +- .../AboutRepositoryTableViewController.swift | 16 +- .../AboutTableViewController.swift | 14 +- .../AddPasswordTableViewController.swift | 4 +- .../AdvancedSettingsTableViewController.swift | 31 +-- .../BasicStaticTableViewController.swift | 4 +- .../CommitLogsTableViewController.swift | 2 +- .../GeneralSettingsTableViewController.swift | 48 ++-- .../GitConfigSettingTableViewController.swift | 2 +- ...SHKeyArmorSettingTableViewController.swift | 12 +- .../GitServerSettingTableViewController.swift | 66 ++--- ...GPKeyArmorSettingTableViewController.swift | 30 +-- .../PGPKeySettingTableViewController.swift | 14 +- .../PasswordDetailTableViewController.swift | 50 ++-- .../PasswordEditorTableViewController.swift | 41 +-- .../Controllers/PasswordsViewController.swift | 58 ++--- pass/Controllers/QRScannerController.swift | 16 +- .../SSHKeySettingTableViewController.swift | 4 +- .../SettingsTableViewController.swift | 80 +++--- .../SpecialThanksTableViewController.swift | 2 +- pass/Helpers/UtilsExtension.swift | 2 +- pass/Views/LabelTableViewCell.swift | 2 +- pass/en.lproj/Localizable.strings | 238 +++++++++++++++++- pass/en.lproj/Localizable.stringsdict | 76 ++++++ .../CredentialProviderViewController.swift | 8 +- passExtension/ExtensionViewController.swift | 8 +- .../PasscodeLockViewController.swift | 18 +- passKit/Helpers/AppError.swift | 23 +- passKit/Helpers/FileManagerExtension.swift | 2 +- passKit/Helpers/Utils.swift | 2 +- passKit/Models/Password.swift | 4 +- passKit/Models/PasswordStore.swift | 47 ++-- passKit/Parser/OtpType.swift | 8 +- passKitTests/Models/PasswordTest.swift | 6 +- passKitTests/Parser/OtpTypeTest.swift | 6 +- 36 files changed, 626 insertions(+), 334 deletions(-) create mode 100644 pass/en.lproj/Localizable.stringsdict diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj index 5b65db3..4ef076a 100644 --- a/pass.xcodeproj/project.pbxproj +++ b/pass.xcodeproj/project.pbxproj @@ -26,6 +26,7 @@ 30B04860209A5141001013CA /* PasswordTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B0485F209A5141001013CA /* PasswordTest.swift */; }; 30BF5EC821EA8FB5000E4154 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30BF5ECA21EA8FB5000E4154 /* Localizable.strings */; }; 30BF5ECF21EA90D1000E4154 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30BF5ECE21EA90D1000E4154 /* String.swift */; }; + 30BF5ED721ED2434000E4154 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 30BF5ED521ED2434000E4154 /* Localizable.stringsdict */; }; 30FD2F78214D9E0E005E0A92 /* ParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30FD2F77214D9E0E005E0A92 /* ParserTest.swift */; }; 61326CDA7A73757FB68DCB04 /* Pods_passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB3F5541E51ADC8C6B56642 /* Pods_passKit.framework */; }; A20691F41F2A3D0E0096483D /* SecurePasteboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20691F31F2A3D0E0096483D /* SecurePasteboard.swift */; }; @@ -208,6 +209,7 @@ 30B0485F209A5141001013CA /* PasswordTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordTest.swift; sourceTree = ""; }; 30BF5EC921EA8FB5000E4154 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 30BF5ECE21EA90D1000E4154 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = String.swift; path = Localization/String.swift; sourceTree = ""; }; + 30BF5ED621ED2434000E4154 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; 30FD2F77214D9E0E005E0A92 /* ParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParserTest.swift; sourceTree = ""; }; 31C3033E8868D05B2C55C8B1 /* Pods-passExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-passExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-passExtension/Pods-passExtension.debug.xcconfig"; sourceTree = ""; }; 3A5620D17DF5E86B61761D0E /* Pods_pass.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_pass.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -703,6 +705,7 @@ DC917BDF1E2E8231000FDF54 /* LaunchScreen.storyboard */, DC917BDA1E2E8231000FDF54 /* Main.storyboard */, 30BF5ECA21EA8FB5000E4154 /* Localizable.strings */, + 30BF5ED521ED2434000E4154 /* Localizable.stringsdict */, ); path = pass; sourceTree = ""; @@ -1015,6 +1018,7 @@ 30BF5EC821EA8FB5000E4154 /* Localizable.strings in Resources */, DCFB77A31E500D9C008DE471 /* PasswordDetailTitleTableViewCell.xib in Resources */, DC917BDE1E2E8231000FDF54 /* Assets.xcassets in Resources */, + 30BF5ED721ED2434000E4154 /* Localizable.stringsdict in Resources */, DCDDEAB01E4639F300F68193 /* LabelTableViewCell.xib in Resources */, DC917BDC1E2E8231000FDF54 /* Main.storyboard in Resources */, A2802BFA1E70813A00879216 /* SliderTableViewCell.xib in Resources */, @@ -1324,6 +1328,14 @@ name = Localizable.strings; sourceTree = ""; }; + 30BF5ED521ED2434000E4154 /* Localizable.stringsdict */ = { + isa = PBXVariantGroup; + children = ( + 30BF5ED621ED2434000E4154 /* en */, + ); + name = Localizable.stringsdict; + sourceTree = ""; + }; A239F59A2158C08C00576CBF /* MainInterface.storyboard */ = { isa = PBXVariantGroup; children = ( diff --git a/pass/AppDelegate.swift b/pass/AppDelegate.swift index a09a02c..ef7e533 100644 --- a/pass/AppDelegate.swift +++ b/pass/AppDelegate.swift @@ -140,7 +140,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { * The store could not be migrated to the current model version. Check the error message to determine what the actual problem was. */ - fatalError("Unresolved error \(error), \(error.userInfo)") + fatalError("UnresolvedError".localize("\(error), \(error.userInfo)")) } }) return container @@ -157,7 +157,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // Replace this implementation with code to handle the error appropriately. // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. let nserror = error as NSError - fatalError("Unresolved error \(nserror), \(nserror.userInfo)") + fatalError("UnresolvedError".localize("\(nserror), \(nserror.userInfo)")) } } } diff --git a/pass/Controllers/AboutRepositoryTableViewController.swift b/pass/Controllers/AboutRepositoryTableViewController.swift index af5c3dc..fd5e346 100644 --- a/pass/Controllers/AboutRepositoryTableViewController.swift +++ b/pass/Controllers/AboutRepositoryTableViewController.swift @@ -11,7 +11,7 @@ import passKit class AboutRepositoryTableViewController: BasicStaticTableViewController { - private static let VALUE_NOT_AVAILABLE = "Value not available" + private static let VALUE_NOT_AVAILABLE = "ValueNotAvailable".localize() private var needRefresh = false private var indicator: UIActivityIndicatorView = { @@ -62,12 +62,12 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController { let type = UITableViewCellAccessoryType.none strongSelf.tableData = [ // section 0 - [[.style: CellDataStyle.value1, .accessoryType: type, .title: "Passwords", .detailText: passwords], - [.style: CellDataStyle.value1, .accessoryType: type, .title: "Size", .detailText: size], - [.style: CellDataStyle.value1, .accessoryType: type, .title: "Local Commits", .detailText: localCommits], - [.style: CellDataStyle.value1, .accessoryType: type, .title: "Last Synced", .detailText: lastSynced], - [.style: CellDataStyle.value1, .accessoryType: type, .title: "Commits", .detailText: commits], - [.title: "Commit Logs", .action: "segue", .link: "showCommitLogsSegue"], + [[.style: CellDataStyle.value1, .accessoryType: type, .title: "Passwords".localize(), .detailText: passwords], + [.style: CellDataStyle.value1, .accessoryType: type, .title: "Size".localize(), .detailText: size], + [.style: CellDataStyle.value1, .accessoryType: type, .title: "LocalCommits".localize(), .detailText: localCommits], + [.style: CellDataStyle.value1, .accessoryType: type, .title: "LastSynced".localize(), .detailText: lastSynced], + [.style: CellDataStyle.value1, .accessoryType: type, .title: "Commits".localize(), .detailText: commits], + [.title: "CommitLogs".localize(), .action: "segue", .link: "showCommitLogsSegue"], ], ] strongSelf.indicator.stopAnimating() @@ -95,7 +95,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController { private func lastSyncedTimeString() -> String { guard let date = self.passwordStore.lastSyncedTime else { - return "Oops! Sync again?" + return "SyncAgain?".localize() } let formatter = DateFormatter() formatter.dateStyle = .medium diff --git a/pass/Controllers/AboutTableViewController.swift b/pass/Controllers/AboutTableViewController.swift index 91348c9..f329edf 100644 --- a/pass/Controllers/AboutTableViewController.swift +++ b/pass/Controllers/AboutTableViewController.swift @@ -13,13 +13,13 @@ class AboutTableViewController: BasicStaticTableViewController { override func viewDidLoad() { tableData = [ // section 0 - [[.title: "Website", .action: "link", .link: "https://github.com/mssun/pass-ios.git"], - [.title: "Help", .action: "link", .link: "https://github.com/mssun/passforios/wiki"], - [.title: "Contact Developer", .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"],], + [[.title: "Website".localize(), .action: "link", .link: "https://github.com/mssun/pass-ios.git"], + [.title: "Help".localize(), .action: "link", .link: "https://github.com/mssun/passforios/wiki"], + [.title: "ContactDeveloper".localize(), .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"],], // section 1, - [[.title: "Open Source Components", .action: "segue", .link: "showOpenSourceComponentsSegue"], - [.title: "Special Thanks", .action: "segue", .link: "showSpecialThanksSegue"],], + [[.title: "OpenSourceComponents".localize(), .action: "segue", .link: "showOpenSourceComponentsSegue"], + [.title: "SpecialThanks".localize(), .action: "segue", .link: "showSpecialThanksSegue"],], ] super.viewDidLoad() } @@ -29,7 +29,7 @@ class AboutTableViewController: BasicStaticTableViewController { let view = UIView() let footerLabel = UILabel(frame: CGRect(x: 8, y: 15, width: tableView.frame.width, height: 60)) footerLabel.numberOfLines = 0 - footerLabel.text = "Pass for iOS \(Bundle.main.releaseVersionNumber!) (\(Bundle.main.buildVersionNumber!))" + footerLabel.text = "PassForIos".localize() + " \(Bundle.main.releaseVersionNumber!) (\(Bundle.main.buildVersionNumber!))" footerLabel.font = UIFont.preferredFont(forTextStyle: .footnote) footerLabel.textColor = UIColor.lightGray footerLabel.textAlignment = .center @@ -41,7 +41,7 @@ class AboutTableViewController: BasicStaticTableViewController { override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { if section == 1 { - return "Acknowledgements".uppercased() + return "Acknowledgements".localize().uppercased() } return nil } diff --git a/pass/Controllers/AddPasswordTableViewController.swift b/pass/Controllers/AddPasswordTableViewController.swift index c6755e5..16df9f1 100644 --- a/pass/Controllers/AddPasswordTableViewController.swift +++ b/pass/Controllers/AddPasswordTableViewController.swift @@ -32,8 +32,8 @@ class AddPasswordTableViewController: PasswordEditorTableViewController { if identifier == "saveAddPasswordSegue" { // check PGP key guard passwordStore.privateKey != nil else { - let alertTitle = "Cannot Add Password" - let alertMessage = "PGP Key is not set. Please set your PGP Key first." + let alertTitle = "CannotAddPassword".localize() + let alertMessage = "PgpKeyNotSet.".localize() Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) return false } diff --git a/pass/Controllers/AdvancedSettingsTableViewController.swift b/pass/Controllers/AdvancedSettingsTableViewController.swift index 4982034..09862d0 100644 --- a/pass/Controllers/AdvancedSettingsTableViewController.swift +++ b/pass/Controllers/AdvancedSettingsTableViewController.swift @@ -41,45 +41,38 @@ class AdvancedSettingsTableViewController: UITableViewController { self.gitSignatureTableViewCell.detailTextLabel?.text = "\(gitSignatureName) <\(gitSignatureEmail)>" if SharedDefaults[.gitSignatureName] == nil && SharedDefaults[.gitSignatureEmail] == nil { self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.systemFont(ofSize: 17) - gitSignatureTableViewCell.detailTextLabel?.text = "Not Set" + gitSignatureTableViewCell.detailTextLabel?.text = "NotSet".localize() } } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) if tableView.cellForRow(at: indexPath) == eraseDataTableViewCell { - let alert = UIAlertController(title: "Erase Password Store Data?", message: "This will delete all local data and settings. Password store data on your remote server will not be affected.", preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "Erase Password Data", style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in - SVProgressHUD.show(withStatus: "Erasing ...") + let alert = UIAlertController(title: "ErasePasswordStoreData?".localize(), message: "EraseExplanation.".localize(), preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in + SVProgressHUD.show(withStatus: "Erasing...".localize()) self.passwordStore.erase() self.navigationController!.popViewController(animated: true) - SVProgressHUD.showSuccess(withStatus: "Done") + SVProgressHUD.showSuccess(withStatus: "Done".localize()) SVProgressHUD.dismiss(withDelay: 1) })) - alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.cancel, handler:nil)) + alert.addAction(UIAlertAction(title: "Dismiss".localize(), style: UIAlertActionStyle.cancel, handler:nil)) self.present(alert, animated: true, completion: nil) } else if tableView.cellForRow(at: indexPath) == discardChangesTableViewCell { - let alert = UIAlertController(title: "Discard All Changes?", message: "Do you want to permanently discard all changes to the local copy of your password data? You cannot undo this action.", preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "Discard All Changes", style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in - SVProgressHUD.show(withStatus: "Resetting ...") + let alert = UIAlertController(title: "DiscardAllLocalChanges?".localize(), message: "DiscardExplanation.".localize(), preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "DiscardAllLocalChanges".localize(), style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in + SVProgressHUD.show(withStatus: "Resetting...".localize()) do { let numberDiscarded = try self.passwordStore.reset() self.navigationController!.popViewController(animated: true) - switch numberDiscarded { - case 0: - SVProgressHUD.showSuccess(withStatus: "No local commits") - case 1: - SVProgressHUD.showSuccess(withStatus: "Discarded 1 commit") - default: - SVProgressHUD.showSuccess(withStatus: "Discarded \(numberDiscarded) commits") - } + SVProgressHUD.showSuccess(withStatus: "DiscardedCommits(%d)".localize(numberDiscarded)) SVProgressHUD.dismiss(withDelay: 1) } catch { - Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) } })) - alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.cancel, handler:nil)) + alert.addAction(UIAlertAction(title: "Dismiss".localize(), style: UIAlertActionStyle.cancel, handler:nil)) self.present(alert, animated: true, completion: nil) } } diff --git a/pass/Controllers/BasicStaticTableViewController.swift b/pass/Controllers/BasicStaticTableViewController.swift index cf24efc..9fd77c2 100644 --- a/pass/Controllers/BasicStaticTableViewController.swift +++ b/pass/Controllers/BasicStaticTableViewController.swift @@ -101,8 +101,8 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo sendEmail(toRecipients: [urlComponents.path], subject: subject) } else { let email = urlComponents.path - let alertTitle = "Cannot open Mail App" - let alertMessage = "Email copied: \(email)" + let alertTitle = "CannotOpenMail".localize() + let alertMessage = "CopiedEmail".localize(email) Utils.copyToPasteboard(textToCopy: email) Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) } diff --git a/pass/Controllers/CommitLogsTableViewController.swift b/pass/Controllers/CommitLogsTableViewController.swift index 110282a..adf7697 100644 --- a/pass/Controllers/CommitLogsTableViewController.swift +++ b/pass/Controllers/CommitLogsTableViewController.swift @@ -51,7 +51,7 @@ class CommitLogsTableViewController: UITableViewController { do { return try passwordStore.getRecentCommits(count: 20) } catch { - Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) return [] } } diff --git a/pass/Controllers/GeneralSettingsTableViewController.swift b/pass/Controllers/GeneralSettingsTableViewController.swift index e8059a9..955c606 100644 --- a/pass/Controllers/GeneralSettingsTableViewController.swift +++ b/pass/Controllers/GeneralSettingsTableViewController.swift @@ -58,22 +58,22 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { override func viewDidLoad() { tableData = [ // section 0 - [[.title: "About Repository", .action: "segue", .link: "showAboutRepositorySegue"],], + [[.title: "AboutRepository".localize(), .action: "segue", .link: "showAboutRepositorySegue"],], // section 1 [ - [.title: "Password Generator Flavor", .action: "none", .style: CellDataStyle.value1], + [.title: "PasswordGeneratorFlavor".localize(), .action: "none", .style: CellDataStyle.value1], ], // section 2 [ - [.title: "Remember PGP Key Passphrase", .action: "none",], - [.title: "Remember Git Credential Passphrase", .action: "none",], + [.title: "RememberPgpKeyPassphrase".localize(), .action: "none",], + [.title: "RememberGitCredentialPassphrase".localize(), .action: "none",], ], [ - [.title: "Show Folders", .action: "none",], - [.title: "Hide Unknown Fields", .action: "none",], - [.title: "Hide OTP Fields", .action: "none",], + [.title: "ShowFolders".localize(), .action: "none",], + [.title: "HideUnknownFields".localize(), .action: "none",], + [.title: "HideOtpFields".localize(), .action: "none",], ], ] @@ -84,7 +84,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = super.tableView(tableView, cellForRowAt: indexPath) switch cell.textLabel!.text! { - case "Hide Unknown Fields": + case "HideUnknownFields".localize(): cell.accessoryType = .none let detailButton = UIButton(type: .detailDisclosure) hideUnknownSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideUnknownSwitch.bounds.width, height: hideUnknownSwitch.bounds.height) @@ -96,7 +96,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { cell.accessoryView = accessoryView cell.selectionStyle = .none hideUnknownSwitch.isOn = SharedDefaults[.isHideUnknownOn] - case "Hide OTP Fields": + case "HideOtpFields".localize(): cell.accessoryType = .none let detailButton = UIButton(type: .detailDisclosure) hideOTPSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideOTPSwitch.bounds.width, height: hideOTPSwitch.bounds.height) @@ -108,19 +108,19 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { cell.accessoryView = accessoryView cell.selectionStyle = .none hideOTPSwitch.isOn = SharedDefaults[.isHideOTPOn] - case "Remember PGP Key Passphrase": + case "RememberPgpKeyPassphrase".localize(): cell.accessoryType = .none cell.selectionStyle = .none cell.accessoryView = rememberPGPPassphraseSwitch - case "Remember Git Credential Passphrase": + case "RememberGitCredentialPassphrase".localize(): cell.accessoryType = .none cell.selectionStyle = .none cell.accessoryView = rememberGitCredentialPassphraseSwitch - case "Show Folders": + case "ShowFolders".localize(): cell.accessoryType = .none cell.selectionStyle = .none cell.accessoryView = showFolderSwitch - case "Password Generator Flavor": + case "PasswordGeneratorFlavor".localize(): cell.accessoryType = .disclosureIndicator cell.detailTextLabel?.text = PasswordGeneratorFlavour.from(SharedDefaults[.passwordGeneratorFlavor]).name default: break @@ -131,7 +131,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { super.tableView(tableView, didSelectRowAt: indexPath) let cell = tableView.cellForRow(at: indexPath)! - if cell.textLabel!.text! == "Password Generator Flavor" { + if cell.textLabel!.text! == "PasswordGeneratorFlavor".localize() { tableView.deselectRow(at: indexPath, animated: true) showPasswordGeneratorFlavorActionSheet(sourceCell: cell) } @@ -141,12 +141,12 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) var randomFlavorActionTitle = "" var appleFlavorActionTitle = "" - randomFlavorActionTitle = "✓ Random String" - appleFlavorActionTitle = "Apple's Keychain Style" if SharedDefaults[.passwordGeneratorFlavor] == PasswordGeneratorFlavour.RANDOM.rawValue { + randomFlavorActionTitle = "✓ " + "RandomString".localize() + appleFlavorActionTitle = "ApplesKeychainStyle".localize() } else { - randomFlavorActionTitle = "Random String" - appleFlavorActionTitle = "✓ Apple's Keychain Style" + randomFlavorActionTitle = "RandomString".localize() + appleFlavorActionTitle = "✓ " + "ApplesKeychainStyle".localize() } let randomFlavorAction = UIAlertAction(title: randomFlavorActionTitle, style: .default) { _ in SharedDefaults[.passwordGeneratorFlavor] = PasswordGeneratorFlavour.RANDOM.rawValue @@ -158,7 +158,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { sourceCell.detailTextLabel?.text = PasswordGeneratorFlavour.APPLE.name } - let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) + let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil) optionMenu.addAction(randomFlavorAction) optionMenu.addAction(appleFlavorAction) optionMenu.addAction(cancelAction) @@ -168,15 +168,15 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { } @objc func tapHideUnknownSwitchDetailButton(_ sender: Any?) { - let alertMessage = "Only \"key: value\" format in additional fields is supported. Unsupported fields will be given \"unknown\" keys. Turn on this switch to hide unsupported fields." - let alertTitle = "Hide Unknown Fields" + let alertMessage = "HideUnknownFieldsExplanation.".localize() + let alertTitle = "HideUnknownFields".localize() Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) } @objc func tapHideOTPSwitchDetailButton(_ sender: Any?) { - let keywordsString = Constants.OTP_KEYWORDS.joined(separator: ",") - let alertMessage = "Turn on this switch to hide the fields related to one time passwords (i.e., \(keywordsString))." - let alertTitle = "Hide One Time Password Fields" + let keywordsString = Constants.OTP_KEYWORDS.joined(separator: ", ") + let alertMessage = "HideOtpFieldsExplanation.".localize(keywordsString) + let alertTitle = "HideOtpFields".localize() Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) } diff --git a/pass/Controllers/GitConfigSettingTableViewController.swift b/pass/Controllers/GitConfigSettingTableViewController.swift index a0e79d0..30682e7 100644 --- a/pass/Controllers/GitConfigSettingTableViewController.swift +++ b/pass/Controllers/GitConfigSettingTableViewController.swift @@ -32,7 +32,7 @@ class GitConfigSettingTableViewController: UITableViewController { let name = nameTextField.text!.isEmpty ? Globals.gitSignatureDefaultName : nameTextField.text! let email = emailTextField.text!.isEmpty ? Globals.gitSignatureDefaultEmail : nameTextField.text! guard GTSignature(name: name, email: email, time: nil) != nil else { - Utils.alert(title: "Error", message: "Invalid name or email.", controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: "InvalidNameOrEmail".localize(), controller: self, completion: nil) return false } } diff --git a/pass/Controllers/GitSSHKeyArmorSettingTableViewController.swift b/pass/Controllers/GitSSHKeyArmorSettingTableViewController.swift index 803e9c5..1602f63 100644 --- a/pass/Controllers/GitSSHKeyArmorSettingTableViewController.swift +++ b/pass/Controllers/GitSSHKeyArmorSettingTableViewController.swift @@ -29,7 +29,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie numberOfSegments = 0 previousSegment = "" key = "" - message = "Looking for the starting frame." + message = "LookingForStartingFrame.".localize() hasStarted = false isDone = false } @@ -52,7 +52,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie // check the number of segments numberOfSegments = numberOfSegments + 1 guard numberOfSegments <= ScannedSSHKey.maxNumberOfGif else { - key = "Too many QR codes" + key = "TooManyQrCodes".localize() return } @@ -64,7 +64,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie } // update message - message = "\(numberOfSegments) scanned QR codes." + message = "ScannedQrCodes(%d)".localize(numberOfSegments) } } var scanned = ScannedSSHKey() @@ -74,7 +74,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie armorPrivateKeyTextView.text = SharedDefaults[.gitSSHPrivateKeyArmor] armorPrivateKeyTextView.delegate = self - scanPrivateKeyCell?.textLabel?.text = "Scan Private Key QR Codes" + scanPrivateKeyCell?.textLabel?.text = "ScanPrivateKeyQrCodes".localize() scanPrivateKeyCell?.textLabel?.textColor = Globals.blue scanPrivateKeyCell?.selectionStyle = .default scanPrivateKeyCell?.accessoryType = .disclosureIndicator @@ -85,7 +85,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie do { try passwordStore.initGitSSHKey(with: armorPrivateKeyTextView.text) } catch { - Utils.alert(title: "Cannot Save", message: "Cannot Save SSH Key", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "CannotSaveSshKey".localize(), controller: self, completion: nil) } SharedDefaults[.gitSSHKeySource] = "armor" self.navigationController!.popViewController(animated: true) @@ -113,7 +113,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie func checkScannedOutput(line: String) -> (accept: Bool, message: String) { scanned.addSegment(segment: line) if scanned.isDone { - return (accept: true, message: "Done") + return (accept: true, message: "Done".localize()) } else { return (accept: false, message: scanned.message) } diff --git a/pass/Controllers/GitServerSettingTableViewController.swift b/pass/Controllers/GitServerSettingTableViewController.swift index 0410a55..66adecc 100644 --- a/pass/Controllers/GitServerSettingTableViewController.swift +++ b/pass/Controllers/GitServerSettingTableViewController.swift @@ -84,7 +84,7 @@ class GitServerSettingTableViewController: UITableViewController { SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultStyle(.light) - SVProgressHUD.show(withStatus: "Prepare Repository") + SVProgressHUD.show(withStatus: "PrepareRepository".localize()) var gitCredential: GitCredential if auth == "Password" { gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: username)) @@ -112,7 +112,7 @@ class GitServerSettingTableViewController: UITableViewController { }, checkoutProgressBlock: { (path, completedSteps, totalSteps) in DispatchQueue.main.async { - SVProgressHUD.showProgress(Float(completedSteps)/Float(totalSteps), status: "Checkout Master Branch") + SVProgressHUD.showProgress(Float(completedSteps)/Float(totalSteps), status: "CheckingOutBranch".localize(branchName)) } }) DispatchQueue.main.async { @@ -121,16 +121,16 @@ class GitServerSettingTableViewController: UITableViewController { SharedDefaults[.gitBranchName] = branchName SharedDefaults[.gitAuthenticationMethod] = auth SVProgressHUD.dismiss() - let savePassphraseAlert = UIAlertController(title: "Done", message: "Do you want to save the Git credential password/passphrase?", preferredStyle: UIAlertControllerStyle.alert) + let savePassphraseAlert = UIAlertController(title: "Done".localize(), message: "WantToSaveGitCredential?".localize(), preferredStyle: UIAlertControllerStyle.alert) // no - savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in + savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: UIAlertActionStyle.default) { _ in SharedDefaults[.isRememberGitCredentialPassphraseOn] = false self.passwordStore.gitPassword = nil self.passwordStore.gitSSHPrivateKeyPassphrase = nil self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self) }) // yes - savePassphraseAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive) {_ in + savePassphraseAlert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertActionStyle.destructive) {_ in SharedDefaults[.isRememberGitCredentialPassphraseOn] = true self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self) }) @@ -141,9 +141,9 @@ class GitServerSettingTableViewController: UITableViewController { let error = error as NSError var message = error.localizedDescription if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError { - message = "\(message)\nUnderlying error: \(underlyingError.localizedDescription)" + message = "\(message)\n\("UnderlyingError".localize()): \(underlyingError.localizedDescription)" } - Utils.alert(title: "Error", message: message, controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: message, controller: self, completion: nil) } } } @@ -156,7 +156,7 @@ class GitServerSettingTableViewController: UITableViewController { } else if cell == authSSHKeyCell { if !passwordStore.gitSSHKeyExists() { - Utils.alert(title: "Cannot Select SSH Key", message: "Please setup SSH key first.", controller: self, completion: nil) + Utils.alert(title: "CannotSelectSshKey".localize(), message: "PleaseSetupSshKeyFirst.".localize(), controller: self, completion: nil) authenticationMethod = "Password" } else { authenticationMethod = "SSH Key" @@ -170,7 +170,7 @@ class GitServerSettingTableViewController: UITableViewController { // some sanity checks guard let gitURL = URL(string: gitURLTextField.text!) else { - Utils.alert(title: "Cannot Save", message: "Please set the Git repository URL.", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "SetGitRepositoryUrl".localize(), controller: self, completion: nil) return } @@ -179,28 +179,28 @@ class GitServerSettingTableViewController: UITableViewController { break case let val where val == "ssh": guard let sshUsername = gitURL.user, sshUsername.isEmpty == false else { - Utils.alert(title: "Cannot Save", message: "Cannot find the username in the Git repository URL. Example URL: ssh://git@server/path/to/repo.git.", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "CannotFindUsername.".localize(), controller: self, completion: nil) return } guard let username = usernameTextField.text, username == sshUsername else { - Utils.alert(title: "Cannot Save", message: "Please check the entered username and the username in the Git repository URL. They should match.", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "CheckEnteredUsername.".localize(), controller: self, completion: nil) return } case let val where val == "http": - Utils.alert(title: "Cannot Save", message: "Please use https instead of http.", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "UseHttps.".localize(), controller: self, completion: nil) return default: - Utils.alert(title: "Cannot Save", message: "Please specify the scheme of the Git repository URL (https or ssh).", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "SpecifySchema.".localize(), controller: self, completion: nil) return } if passwordStore.repositoryExisted() { - let alert = UIAlertController(title: "Overwrite?", message: "This operation will overwrite your current password store data (repository). Data on your remote server will not be affected.", preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "Overwrite", style: UIAlertActionStyle.destructive, handler: { _ in + let alert = UIAlertController(title: "Overwrite?".localize(), message: "OperationWillOverwriteData.".localize(), preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "Overwrite".localize(), style: UIAlertActionStyle.destructive, handler: { _ in // perform segue only after a successful clone self.cloneAndSegueIfSuccess() })) - alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil)) + alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertActionStyle.cancel, handler: nil)) self.present(alert, animated: true, completion: nil) } else { // perform segue only after a successful clone @@ -210,9 +210,9 @@ class GitServerSettingTableViewController: UITableViewController { func showSSHKeyActionSheet() { let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - var urlActionTitle = "Download from URL" - var armorActionTitle = "ASCII-Armor Encrypted Key" - var fileActionTitle = "iTunes File Sharing" + var urlActionTitle = "DownloadFromUrl".localize() + var armorActionTitle = "AsciiArmorEncryptedKey".localize() + var fileActionTitle = "ITunesFileSharing".localize() if SharedDefaults[.gitSSHKeySource] == "url" { urlActionTitle = "✓ \(urlActionTitle)" @@ -227,41 +227,41 @@ class GitServerSettingTableViewController: UITableViewController { let armorAction = UIAlertAction(title: armorActionTitle, style: .default) { _ in self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self) } - let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) + let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil) optionMenu.addAction(urlAction) optionMenu.addAction(armorAction) if passwordStore.gitSSHKeyExists(inFileSharing: true) { // might keys updated via iTunes, or downloaded/pasted inside the app - fileActionTitle.append(" (Import)") + fileActionTitle.append(" (\("Import".localize()))") let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in do { try self.passwordStore.gitSSHKeyImportFromFileSharing() SharedDefaults[.gitSSHKeySource] = "file" - SVProgressHUD.showSuccess(withStatus: "Imported") + SVProgressHUD.showSuccess(withStatus: "Imported".localize()) SVProgressHUD.dismiss(withDelay: 1) } catch { - Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) } } optionMenu.addAction(fileAction) } else { - fileActionTitle.append(" (Tips)") + fileActionTitle.append(" (\("Tips".localize()))") let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in - let title = "Tips" - let message = "Copy your ASCII-armored private key to Pass with the name \"ssh_key\" (without quotes) via iTunes. Then come back and click \"iTunes File Sharing\" to finish." + let title = "Tips".localize() + let message = "CopyPrivateKeyToPass.".localize() Utils.alert(title: title, message: message, controller: self) } optionMenu.addAction(fileAction) } if SharedDefaults[.gitSSHKeySource] != nil { - let deleteAction = UIAlertAction(title: "Remove Git SSH Keys", style: .destructive) { _ in + let deleteAction = UIAlertAction(title: "RemoveSShKeys".localize(), style: .destructive) { _ in self.passwordStore.removeGitSSHKeys() SharedDefaults[.gitSSHKeySource] = nil if let sshLabel = self.sshLabel { sshLabel.isEnabled = false - self.checkAuthenticationMethod(method: "Password") + self.checkAuthenticationMethod(method: "Password".localize()) } } optionMenu.addAction(deleteAction) @@ -278,23 +278,23 @@ class GitServerSettingTableViewController: UITableViewController { var message = "" switch credential { case .http: - message = "Please fill in the password of your Git account." + message = "FillInGitAccountPassword.".localize() case .ssh: - message = "Please fill in the passphrase of your SSH key." + message = "FillInSshKeyPassphrase.".localize() } DispatchQueue.main.async { SVProgressHUD.dismiss() - let alert = UIAlertController(title: "Password", message: message, preferredStyle: UIAlertControllerStyle.alert) + let alert = UIAlertController(title: "Password".localize(), message: message, preferredStyle: UIAlertControllerStyle.alert) alert.addTextField(configurationHandler: {(textField: UITextField!) in textField.text = lastPassword ?? "" textField.isSecureTextEntry = true }) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in + alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in password = alert.textFields!.first!.text sem.signal() })) - alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in + alert.addAction(UIAlertAction(title: "Cancel".localize(), style: .cancel) { _ in password = nil sem.signal() }) diff --git a/pass/Controllers/PGPKeyArmorSettingTableViewController.swift b/pass/Controllers/PGPKeyArmorSettingTableViewController.swift index 22bcf32..a59992b 100644 --- a/pass/Controllers/PGPKeyArmorSettingTableViewController.swift +++ b/pass/Controllers/PGPKeyArmorSettingTableViewController.swift @@ -36,7 +36,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe numberOfSegments = 0 previousSegment = "" key = "" - message = "Looking for the starting frame." + message = "LookingForStartingFrame.".localize() hasStarted = false isDone = false } @@ -55,12 +55,12 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe switch keyType { case .publicKey: if findPrivate { - message = "Please scan public key." + message = "ScanPrivateKey.".localize() } hasStarted = findPublic case .privateKey: if findPublic { - message = "Please scan private key." + message = "ScanPrivateKey.".localize() } hasStarted = findPrivate } @@ -72,7 +72,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe // check the number of segments numberOfSegments = numberOfSegments + 1 guard numberOfSegments <= ScannedPGPKey.maxNumberOfGif else { - key = "Too many QR codes" + key = "TooManyQrCodes" return } @@ -83,7 +83,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe } // update message - message = "\(numberOfSegments) scanned QR codes." + message = "ScannedQrCodes(%d)".localize(numberOfSegments) } } var scanned = ScannedPGPKey() @@ -94,12 +94,12 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe armorPrivateKeyTextView.text = SharedDefaults[.pgpPrivateKeyArmor] pgpPassphrase = passwordStore.pgpKeyPassphrase - scanPublicKeyCell?.textLabel?.text = "Scan Public Key QR Codes" + scanPublicKeyCell?.textLabel?.text = "ScanPublicKeyQrCodes".localize() scanPublicKeyCell?.textLabel?.textColor = Globals.blue scanPublicKeyCell?.selectionStyle = .default scanPublicKeyCell?.accessoryType = .disclosureIndicator - scanPrivateKeyCell?.textLabel?.text = "Scan Private Key QR Codes" + scanPrivateKeyCell?.textLabel?.text = "ScanPrivateKeyQrCodes".localize() scanPrivateKeyCell?.textLabel?.textColor = Globals.blue scanPrivateKeyCell?.selectionStyle = .default scanPrivateKeyCell?.accessoryType = .disclosureIndicator @@ -107,25 +107,25 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe @IBAction func save(_ sender: Any) { guard armorPublicKeyTextView.text.isEmpty == false else { - Utils.alert(title: "Cannot Save", message: "Please set public key first.", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "SetPublicKey.".localize(), controller: self, completion: nil) return } guard armorPrivateKeyTextView.text.isEmpty == false else { - Utils.alert(title: "Cannot Save", message: "Please set private key first.", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKey.".localize(), controller: self, completion: nil) return } - let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert) + let savePassphraseAlert = UIAlertController(title: "Passphrase".localize(), message: "WantToSavePassphrase?".localize(), preferredStyle: UIAlertControllerStyle.alert) // no - savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in + savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: UIAlertActionStyle.default) { _ in self.pgpPassphrase = nil SharedDefaults[.isRememberPGPPassphraseOn] = false self.performSegue(withIdentifier: "savePGPKeySegue", sender: self) }) // yes - savePassphraseAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive) {_ in + savePassphraseAlert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertActionStyle.destructive) {_ in // ask for the passphrase - let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in + let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in self.pgpPassphrase = alert.textFields?.first?.text SharedDefaults[.isRememberPGPPassphraseOn] = true self.performSegue(withIdentifier: "savePGPKeySegue", sender: self) @@ -163,7 +163,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe func checkScannedOutput(line: String) -> (accept: Bool, message: String) { scanned.addSegment(segment: line) if scanned.isDone { - return (accept: true, message: "Done") + return (accept: true, message: "Done".localize()) } else { return (accept: false, message: scanned.message) } diff --git a/pass/Controllers/PGPKeySettingTableViewController.swift b/pass/Controllers/PGPKeySettingTableViewController.swift index 2b01510..1657a21 100644 --- a/pass/Controllers/PGPKeySettingTableViewController.swift +++ b/pass/Controllers/PGPKeySettingTableViewController.swift @@ -26,11 +26,11 @@ class PGPKeySettingTableViewController: UITableViewController { private func validatePGPKeyURL(input: String?) -> Bool { guard let path = input, let url = URL(string: path) else { - Utils.alert(title: "Cannot Save PGP Key", message: "Please set PGP Key URL first.", controller: self, completion: nil) + Utils.alert(title: "CannotSavePgpKey".localize(), message: "SetPgpKeyUrlFirst.".localize(), controller: self, completion: nil) return false } guard let scheme = url.scheme, scheme == "https", scheme == "https" else { - Utils.alert(title: "Cannot Save PGP Key", message: "HTTP connection is not supported.", controller: self, completion: nil) + Utils.alert(title: "CannotSavePgpKey".localize(), message: "HttpNotSupported.".localize(), controller: self, completion: nil) return false } return true @@ -41,18 +41,18 @@ class PGPKeySettingTableViewController: UITableViewController { validatePGPKeyURL(input: pgpPrivateKeyURLTextField.text) == true else { return } - let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert) + let savePassphraseAlert = UIAlertController(title: "Passphrase".localize(), message: "WantToSavePassphrase?".localize(), preferredStyle: UIAlertControllerStyle.alert) // no - savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in + savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: UIAlertActionStyle.default) { _ in self.pgpPassphrase = nil SharedDefaults[.isRememberPGPPassphraseOn] = false self.performSegue(withIdentifier: "savePGPKeySegue", sender: self) }) // yes - savePassphraseAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive) {_ in + savePassphraseAlert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertActionStyle.destructive) {_ in // ask for the passphrase - let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in + let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in self.pgpPassphrase = alert.textFields?.first?.text SharedDefaults[.isRememberPGPPassphraseOn] = true self.performSegue(withIdentifier: "savePGPKeySegue", sender: self) diff --git a/pass/Controllers/PasswordDetailTableViewController.swift b/pass/Controllers/PasswordDetailTableViewController.swift index 490e2f1..b355876 100644 --- a/pass/Controllers/PasswordDetailTableViewController.swift +++ b/pass/Controllers/PasswordDetailTableViewController.swift @@ -81,8 +81,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni override func viewDidAppear(_ animated: Bool) { super.viewWillAppear(animated) if self.shouldPopCurrentView { - let alert = UIAlertController(title: "Notice", message: "All previous local changes have been discarded. Your current Password Store will be shown.", preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in + let alert = UIAlertController(title: "Notice".localize(), message: "PreviousChangesDiscarded.".localize(), preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in _ = self.navigationController?.popViewController(animated: true) })) self.present(alert, animated: true, completion: nil) @@ -93,8 +93,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni let sem = DispatchSemaphore(value: 0) var passphrase = "" DispatchQueue.main.async { - let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in + let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in passphrase = alert.textFields!.first!.text! sem.signal() })) @@ -113,7 +113,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni @objc private func decryptThenShowPassword() { guard let passwordEntity = passwordEntity else { - Utils.alert(title: "Cannot Show Password", message: "The password does not exist.", controller: self, handler: {(UIAlertAction) -> Void in + Utils.alert(title: "CannotShowPassword".localize(), message: "PasswordDoesNotExist".localize(), controller: self, handler: {(UIAlertAction) -> Void in self.navigationController!.popViewController(animated: true) }) return @@ -127,11 +127,11 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni // remove the wrong passphrase so that users could enter it next time self.passwordStore.pgpKeyPassphrase = nil // alert: cancel or try again - let alert = UIAlertController(title: "Cannot Show Password", message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.default) { _ in + let alert = UIAlertController(title: "CannotShowPassword".localize(), message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertActionStyle.default) { _ in self.navigationController!.popViewController(animated: true) }) - alert.addAction(UIAlertAction(title: "Try again", style: UIAlertActionStyle.destructive) {_ in + alert.addAction(UIAlertAction(title: "TryAgain".localize(), style: UIAlertActionStyle.destructive) {_ in self.decryptThenShowPassword() }) self.present(alert, animated: true, completion: nil) @@ -194,15 +194,15 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni @IBAction private func saveEditPassword(segue: UIStoryboardSegue) { if self.password!.changed != 0 { - SVProgressHUD.show(withStatus: "Saving") + SVProgressHUD.show(withStatus: "Saving".localize()) do { self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: self.password!) } catch { - Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) } self.setTableData() self.tableView.reloadData() - SVProgressHUD.showSuccess(withStatus: "Success") + SVProgressHUD.showSuccess(withStatus: "Success".localize()) SVProgressHUD.dismiss(withDelay: 1) } } @@ -211,7 +211,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni do { try passwordStore.delete(passwordEntity: passwordEntity!) } catch { - Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) } let _ = navigationController?.popViewController(animated: true) } @@ -242,7 +242,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni // show one time password if password.otpType != .none { if let (title, otp) = self.password?.getOtpStrings() { - section = TableSection(type: .addition, header: "One Time Password") + section = TableSection(type: .addition, header: "OneTimePassword".localize()) section.item.append(title => otp) tableData.append(section) oneTimePasswordIndexPath = IndexPath(row: 0, section: tableData.count - 1) @@ -259,7 +259,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni // misc section section = TableSection(type: .misc) - section.item.append(AdditionField(title: "Show Raw")) + section.item.append(AdditionField(title: "ShowRaw".localize())) tableData.append(section) } @@ -315,10 +315,10 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni if let tappedCell = self.tableView.cellForRow(at: tapIndexPath) as? LabelTableViewCell { tappedCell.becomeFirstResponder() let menuController = UIMenuController.shared - let revealItem = UIMenuItem(title: "Reveal", action: #selector(LabelTableViewCell.revealPassword(_:))) - let concealItem = UIMenuItem(title: "Conceal", action: #selector(LabelTableViewCell.concealPassword(_:))) - let nextHOTPItem = UIMenuItem(title: "Next Password", action: #selector(LabelTableViewCell.getNextHOTP(_:))) - let openURLItem = UIMenuItem(title: "Copy Password & Open Link", action: #selector(LabelTableViewCell.openLink(_:))) + let revealItem = UIMenuItem(title: "Reveal".localize(), action: #selector(LabelTableViewCell.revealPassword(_:))) + let concealItem = UIMenuItem(title: "Conceal".localize(), action: #selector(LabelTableViewCell.concealPassword(_:))) + let nextHOTPItem = UIMenuItem(title: "NextPassword".localize(), action: #selector(LabelTableViewCell.getNextHOTP(_:))) + let openURLItem = UIMenuItem(title: "CopyAndOpen".localize(), action: #selector(LabelTableViewCell.openLink(_:))) menuController.menuItems = [revealItem, concealItem, nextHOTPItem, openURLItem] menuController.setTargetRect(tappedCell.contentLabel.frame, in: tappedCell.contentLabel.superview!) menuController.setMenuVisible(true, animated: true) @@ -340,7 +340,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni func getNextHOTP() { guard password != nil, passwordEntity != nil, password?.otpType == .hotp else { DispatchQueue.main.async { - Utils.alert(title: "Error", message: "Get next password of a non-HOTP entry.", controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: "GetNextPasswordOfNonHotp.".localize(), controller: self, completion: nil) } return; } @@ -355,9 +355,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni do { self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: self.password!) } catch { - Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) } - SVProgressHUD.showSuccess(withStatus: "Password Copied\nCounter Updated") + SVProgressHUD.showSuccess(withStatus: "PasswordCopied".localize() + "\n" + "CounterUpdated".localize()) SVProgressHUD.dismiss(withDelay: 1) } } @@ -365,7 +365,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni func openLink(to address: String?) { guard address != nil, let url = URL(string: formActualWebAddress(from: address!)) else { return DispatchQueue.main.async { - Utils.alert(title: "Error", message: "Cannot find a valid URL", controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: "CannotFindValidUrl".localize(), controller: self, completion: nil) } } SecurePasteboard.shared.copy(textToCopy: password?.password) @@ -436,7 +436,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni detailTextLabel.textAlignment = .center detailTextLabel.textColor = .gray - detailTextLabel.text = "\(numberOfHiddenFields) hidden field\(numberOfHiddenFields > 1 ? "s" : "")" + detailTextLabel.text = "HiddenFields(%d)".localize(numberOfHiddenFields) } override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { @@ -451,7 +451,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni footerLabel.font = UIFont.preferredFont(forTextStyle: .footnote) footerLabel.textColor = UIColor.gray let dateString = self.passwordStore.getLatestUpdateInfo(filename: password!.url.path) - footerLabel.text = "Last Updated: \(dateString)" + footerLabel.text = "LastUpdated".localize(dateString) view.addSubview(footerLabel) return view } @@ -481,7 +481,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let section = tableData[indexPath.section] if section.type == .misc { - if section.item[indexPath.row].title == "Show Raw" { + if section.item[indexPath.row].title == "ShowRaw".localize() { performSegue(withIdentifier: "showRawPasswordSegue", sender: self) } } diff --git a/pass/Controllers/PasswordEditorTableViewController.swift b/pass/Controllers/PasswordEditorTableViewController.swift index 1c35821..6ac87dd 100644 --- a/pass/Controllers/PasswordEditorTableViewController.swift +++ b/pass/Controllers/PasswordEditorTableViewController.swift @@ -29,7 +29,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl private var navigationItemTitle: String? private var sectionHeaderTitles = ["name", "password", "additions",""].map {$0.uppercased()} - private var sectionFooterTitles = ["", "", "Use \"key: value\" format for additional fields.", ""] + private var sectionFooterTitles = ["", "", "UseKeyValueFormat.".localize(), ""] private let nameSection = 0 private let passwordSection = 1 private let additionsSection = 2 @@ -47,23 +47,24 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl super.loadView() deletePasswordCell = UITableViewCell(style: .default, reuseIdentifier: "default") - deletePasswordCell!.textLabel?.text = "Delete Password" + deletePasswordCell!.textLabel?.text = "DeletePassword".localize() deletePasswordCell!.textLabel?.textColor = Globals.red deletePasswordCell?.selectionStyle = .default scanQRCodeCell = UITableViewCell(style: .default, reuseIdentifier: "default") - scanQRCodeCell?.textLabel?.text = "Add One-Time Password" + scanQRCodeCell?.textLabel?.text = "AddOneTimePassword".localize() scanQRCodeCell?.textLabel?.textColor = Globals.blue scanQRCodeCell?.selectionStyle = .default scanQRCodeCell?.accessoryType = .disclosureIndicator memorablePasswordGeneratorCell = UITableViewCell(style: .default, reuseIdentifier: "default") - memorablePasswordGeneratorCell?.textLabel?.text = "Get a Memorable One: xkpasswd" + memorablePasswordGeneratorCell?.textLabel?.text = "GetMemorableOne".localize() memorablePasswordGeneratorCell?.textLabel?.textColor = Globals.blue memorablePasswordGeneratorCell?.selectionStyle = .default memorablePasswordGeneratorCell?.accessoryType = .disclosureIndicator } + override func viewDidLoad() { super.viewDidLoad() if navigationItemTitle != nil { @@ -113,7 +114,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl currentPasswordLength <= maximumLength { defaultLength = currentPasswordLength } - passwordLengthCell?.reset(title: "Length", + passwordLengthCell?.reset(title: "Length".localize(), minimumValue: minimumLength, maximumValue: maximumLength, defaultValue: defaultLength) @@ -161,11 +162,11 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedCell = tableView.cellForRow(at: indexPath) if selectedCell == deletePasswordCell { - let alert = UIAlertController(title: "Delete Password?", message: nil, preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "Delete", style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in + let alert = UIAlertController(title: "DeletePassword?".localize(), message: nil, preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "Delete".localize(), style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in self.performSegue(withIdentifier: "deletePasswordSegue", sender: self) })) - alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler:nil)) + alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertActionStyle.cancel, handler:nil)) self.present(alert, animated: true, completion: nil) } else if selectedCell == scanQRCodeCell { self.performSegue(withIdentifier: "showQRScannerSegue", sender: self) @@ -185,11 +186,11 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl // check whether the current password looks like an OTP field func generateAndCopyPassword() { if let currentPassword = fillPasswordCell?.getContent(), Constants.isOtpRelated(line: currentPassword) { - let alert = UIAlertController(title: "Overwrite?", message: "Overwrite the one-time password configuration?", preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive, handler: {_ in + let alert = UIAlertController(title: "Overwrite?".localize(), message: "OverwriteOtpConfiguration?".localize(), preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertActionStyle.destructive, handler: {_ in self.generateAndCopyPasswordNoOtpCheck() })) - alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil)) + alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertActionStyle.cancel, handler: nil)) self.present(alert, animated: true, completion: nil) } else { self.generateAndCopyPasswordNoOtpCheck() @@ -243,9 +244,9 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl // MARK: - QRScannerControllerDelegate Methods func checkScannedOutput(line: String) -> (accept: Bool, message: String) { if let url = URL(string: line), let _ = Token(url: url) { - return (accept: true, message: "Valid token URL") + return (accept: true, message: "ValidTokenUrl".localize()) } else { - return (accept: false, message: "Invalid token URL") + return (accept: false, message: "InvalidTokenUrl".localize()) } } @@ -302,20 +303,20 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl func checkName() -> Bool { // the name field should not be empty guard let name = nameCell?.getContent(), name.isEmpty == false else { - Utils.alert(title: "Cannot Save", message: "Please fill in the name.", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "FillInName.".localize(), controller: self, completion: nil) return false } // the name should not start with / guard name.hasPrefix("/") == false else { - Utils.alert(title: "Cannot Save", message: "Please remove the prefix \"/\" from your password name.", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "RemovePrefix.".localize(), controller: self, completion: nil) return false } // the name field should be a valid url guard let path = name.stringByAddingPercentEncodingForRFC3986(), var passwordURL = URL(string: path) else { - Utils.alert(title: "Cannot Save", message: "Password name is invalid.", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "PasswordNameInvalid.".localize(), controller: self, completion: nil) return false } @@ -324,7 +325,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl while passwordURL.path != "." { passwordURL = passwordURL.deletingLastPathComponent() if passwordURL.path != "." && passwordURL.path.count >= previousPathLength { - Utils.alert(title: "Cannot Save", message: "Cannot parse the filename. Please check and simplify the password name.", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "CannotParseFilename.".localize(), controller: self, completion: nil) return false } previousPathLength = passwordURL.path.count @@ -337,8 +338,8 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl let copiedLinesSplit = UIPasteboard.general.string?.components(separatedBy: CharacterSet.whitespacesAndNewlines).filter({ !$0.isEmpty }) if copiedLinesSplit?.count ?? 0 > 0 { let generatedPassword = copiedLinesSplit![0] - let alert = UIAlertController(title: "Wanna use it?", message: "", preferredStyle: UIAlertControllerStyle.alert) - let message = NSMutableAttributedString(string: "It seems like you have copied something. The first string is:\n") + let alert = UIAlertController(title: "WannaUseIt?".localize(), message: "", preferredStyle: UIAlertControllerStyle.alert) + let message = NSMutableAttributedString(string: "\("SeemsLikeYouHaveCopiedSomething.".localize()) \("FirstStringIs:".localize())\n") message.append(Utils.attributedPassword(plainPassword: generatedPassword)) alert.setValue(message, forKey: "attributedMessage") alert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.default, handler: {[unowned self] (action) -> Void in @@ -349,7 +350,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl // make sure the clipboard gets cleared in 45s SecurePasteboard.shared.copy(textToCopy: generatedPassword) })) - alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler:nil)) + alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertActionStyle.cancel, handler:nil)) self.present(alert, animated: true, completion: nil) } } diff --git a/pass/Controllers/PasswordsViewController.swift b/pass/Controllers/PasswordsViewController.swift index 6368453..7fd4b2f 100644 --- a/pass/Controllers/PasswordsViewController.swift +++ b/pass/Controllers/PasswordsViewController.swift @@ -56,7 +56,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV return nil }() private lazy var backUIBarButtonItem: UIBarButtonItem = { - let backUIBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(self.backAction(_:))) + let backUIBarButtonItem = UIBarButtonItem(title: "Back".localize(), style: .plain, target: self, action: #selector(self.backAction(_:))) return backUIBarButtonItem }() @@ -110,18 +110,18 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV if let controller = segue.source as? AddPasswordTableViewController { SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultStyle(.light) - SVProgressHUD.show(withStatus: "Saving") + SVProgressHUD.show(withStatus: "Saving".localize()) DispatchQueue.global(qos: .userInitiated).async { do { let _ = try self.passwordStore.add(password: controller.password!) DispatchQueue.main.async { // will trigger reloadTableView() by a notification - SVProgressHUD.showSuccess(withStatus: "Done") + SVProgressHUD.showSuccess(withStatus: "Done".localize()) SVProgressHUD.dismiss(withDelay: 1) } } catch { DispatchQueue.main.async { - Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) } } } @@ -131,13 +131,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV private func syncPasswords() { guard passwordStore.repositoryExisted() else { DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800)) { - Utils.alert(title: "Error", message: "There is no password store right now.", controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: "NoPasswordStore.".localize(), controller: self, completion: nil) } return } SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultStyle(.light) - SVProgressHUD.show(withStatus: "Sync Password Store") + SVProgressHUD.show(withStatus: "SyncingPasswordStore".localize()) var gitCredential: GitCredential if SharedDefaults[.gitAuthenticationMethod] == "Password" { gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: SharedDefaults[.gitUsername]!)) @@ -159,13 +159,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV if self.passwordStore.numberOfLocalCommits ?? 0 > 0 { try self.passwordStore.pushRepository(credential: gitCredential, requestGitPassword: self.requestGitPassword(credential:lastPassword:), transferProgressBlock: {(current, total, bytes, stop) in DispatchQueue.main.async { - SVProgressHUD.showProgress(Float(current)/Float(total), status: "Push Remote Repository") + SVProgressHUD.showProgress(Float(current)/Float(total), status: "PushingToRemoteRepository".localize()) } }) } DispatchQueue.main.async { self.reloadTableView(parent: nil) - SVProgressHUD.showSuccess(withStatus: "Done") + SVProgressHUD.showSuccess(withStatus: "Done".localize()) SVProgressHUD.dismiss(withDelay: 1) self.syncControl.endRefreshing() } @@ -176,14 +176,14 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV let error = error as NSError var message = error.localizedDescription if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError { - message = "\(message)\nUnderlying error: \(underlyingError.localizedDescription)" - if underlyingError.localizedDescription.contains("Wrong passphrase") { - message = "\(message)\nRecovery suggestion: Wrong credential password/passphrase has been removed, please try again." + message = "\(message)\n\("UnderlyingError".localize(underlyingError.localizedDescription))" + if underlyingError.localizedDescription.contains("WrongPassphrase".localize()) { + message = "\(message)\n\("RecoverySuggestion".localize())" gitCredential.delete() } } DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800)) { - Utils.alert(title: "Error", message: message, controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: message, controller: self, completion: nil) } } } @@ -194,7 +194,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV super.viewDidAppear(animated) if SharedDefaults[.isShowFolderOn] { - searchController.searchBar.scopeButtonTitles = ["Current", "All"] + searchController.searchBar.scopeButtonTitles = ["Current".localize(), "All".localize()] } else { searchController.searchBar.scopeButtonTitles = nil } @@ -365,8 +365,8 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV let sem = DispatchSemaphore(value: 0) var passphrase = "" DispatchQueue.main.async { - let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in + let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in passphrase = alert.textFields!.first!.text! sem.signal() })) @@ -381,7 +381,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV let _ = sem.wait(timeout: DispatchTime.distantFuture) DispatchQueue.main.async { // bring back - SVProgressHUD.show(withStatus: "Decrypting") + SVProgressHUD.show(withStatus: "Decrypting".localize()) } if SharedDefaults[.isRememberPGPPassphraseOn] { self.passwordStore.pgpKeyPassphrase = passphrase @@ -391,28 +391,28 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV private func decryptThenCopyPassword(from indexPath: IndexPath) { guard self.passwordStore.privateKey != nil else { - Utils.alert(title: "Cannot Copy Password", message: "PGP Key is not set. Please set your PGP Key first.", controller: self, completion: nil) + Utils.alert(title: "CannotCopyPassword".localize(), message: "SetPgpKey.".localize(), controller: self, completion: nil) return } let passwordEntity = getPasswordEntry(by: indexPath).passwordEntity! UIImpactFeedbackGenerator(style: .medium).impactOccurred() SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultStyle(.dark) - SVProgressHUD.show(withStatus: "Decrypting") + SVProgressHUD.show(withStatus: "Decrypting".localize()) DispatchQueue.global(qos: .userInteractive).async { var decryptedPassword: Password? do { decryptedPassword = try self.passwordStore.decrypt(passwordEntity: passwordEntity, requestPGPKeyPassphrase: self.requestPGPKeyPassphrase) DispatchQueue.main.async { SecurePasteboard.shared.copy(textToCopy: decryptedPassword?.password) - SVProgressHUD.showSuccess(withStatus: "Password copied. We will clear the pasteboard in 45 seconds.") + SVProgressHUD.showSuccess(withStatus: "PasswordCopiedToPasteboard.".localize()) SVProgressHUD.dismiss(withDelay: 0.6) } } catch { DispatchQueue.main.async { // remove the wrong passphrase so that users could enter it next time self.passwordStore.pgpKeyPassphrase = nil - Utils.alert(title: "Cannot Copy Password", message: error.localizedDescription, controller: self, completion: nil) + Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil) } } } @@ -453,7 +453,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { if identifier == "showPasswordDetail" { guard self.passwordStore.privateKey != nil else { - Utils.alert(title: "Cannot Show Password", message: "PGP Key is not set. Please set your PGP Key first.", controller: self, completion: nil) + Utils.alert(title: "CannotShowPassword".localize(), message: "SetPgpKey.".localize(), controller: self, completion: nil) if let s = sender as? UITableViewCell { let selectedIndexPath = tableView.indexPath(for: s)! tableView.deselectRow(at: selectedIndexPath, animated: true) @@ -462,7 +462,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } } else if identifier == "addPasswordSegue" { guard self.passwordStore.publicKey != nil, self.passwordStore.storeRepository != nil else { - Utils.alert(title: "Cannot Add Password", message: "Please make sure PGP Key and Git Server are properly set.", controller: self, completion: nil) + Utils.alert(title: "CannotAddPassword".localize(), message: "MakeSurePgpAndGitProperlySet.".localize(), controller: self, completion: nil) return false } } @@ -537,13 +537,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV self.tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey") // set the sync control title - let atribbutedTitle = "Last Synced: \(lastSyncedTimeString())" + let atribbutedTitle = "LastSynced".localize() + ": \(lastSyncedTimeString())" syncControl.attributedTitle = NSAttributedString(string: atribbutedTitle) } private func lastSyncedTimeString() -> String { guard let date = self.passwordStore.lastSyncedTime else { - return "Oops! Sync again?" + return "SyncAgain?".localize() } let formatter = DateFormatter() formatter.dateStyle = .medium @@ -615,23 +615,23 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV var message = "" switch credential { case .http: - message = "Please fill in the password of your Git account." + message = "FillInGitAccountPassword.".localize() case .ssh: - message = "Please fill in the password of your SSH key." + message = "FillInSshKeyPassphrase.".localize() } DispatchQueue.main.async { SVProgressHUD.dismiss() - let alert = UIAlertController(title: "Password", message: message, preferredStyle: UIAlertControllerStyle.alert) + let alert = UIAlertController(title: "Password".localize(), message: message, preferredStyle: UIAlertControllerStyle.alert) alert.addTextField(configurationHandler: {(textField: UITextField!) in textField.text = lastPassword ?? "" textField.isSecureTextEntry = true }) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in + alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in password = alert.textFields!.first!.text sem.signal() })) - alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in + alert.addAction(UIAlertAction(title: "Cancel".localize(), style: .cancel) { _ in password = nil sem.signal() }) diff --git a/pass/Controllers/QRScannerController.swift b/pass/Controllers/QRScannerController.swift index d69988e..f192861 100644 --- a/pass/Controllers/QRScannerController.swift +++ b/pass/Controllers/QRScannerController.swift @@ -66,7 +66,7 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg // Move the message label to the front scannerOutput.layer.cornerRadius = 10 - scannerOutput.text = "No QR code detected" + scannerOutput.text = "NoQrCodeDetected.".localize() view.bringSubview(toFront: scannerOutput) // Initialize QR Code Frame to highlight the QR code @@ -109,7 +109,7 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg captureSession?.stopRunning() delegate?.handleScannedOutput(line: scanned) DispatchQueue.main.async { - SVProgressHUD.showSuccess(withStatus: "Done") + SVProgressHUD.showSuccess(withStatus: "Done".localize()) SVProgressHUD.dismiss(withDelay: 1) self.navigationController?.popViewController(animated: true) } @@ -119,21 +119,21 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg scannerOutput.text = scanned } } else { - scannerOutput.text = "No string value" + scannerOutput.text = "NoStringValue".localize() } } else { qrCodeFrameView?.frame = CGRect.zero - scannerOutput.text = "No QR code detected" + scannerOutput.text = "NoQrCodeDetected.".localize() } } func presentCameraSettings() { - let alertController = UIAlertController(title: "Error", - message: "Camera access denied.\nWARNING: Toggle the camera permission resets the app! Save your changes.", + let alertController = UIAlertController(title: "Error".localize(), + message: "CameraAccessDenied.".localize() + "\n" + "WarningToggleCameraPermissionsResetsApp.".localize(), preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: "Cancel", style: .default)) - alertController.addAction(UIAlertAction(title: "Settings", style: .cancel) { _ in + alertController.addAction(UIAlertAction(title: "Cancel".localize(), style: .default)) + alertController.addAction(UIAlertAction(title: "Settings".localize(), style: .cancel) { _ in if let url = URL(string: UIApplicationOpenSettingsURLString) { UIApplication.shared.open(url, options: [:], completionHandler: { _ in // Handle diff --git a/pass/Controllers/SSHKeySettingTableViewController.swift b/pass/Controllers/SSHKeySettingTableViewController.swift index 95fe132..7fdcfd8 100644 --- a/pass/Controllers/SSHKeySettingTableViewController.swift +++ b/pass/Controllers/SSHKeySettingTableViewController.swift @@ -23,7 +23,7 @@ class SSHKeySettingTableViewController: UITableViewController { @IBAction func doneButtonTapped(_ sender: UIButton) { guard let privateKeyURL = URL(string: privateKeyURLTextField.text!.trimmed) else { - Utils.alert(title: "Cannot Save", message: "Please set Private Key URL first.", controller: self, completion: nil) + Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKeyUrl.".localize(), controller: self, completion: nil) return } @@ -32,7 +32,7 @@ class SSHKeySettingTableViewController: UITableViewController { do { try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: Globals.gitSSHPrivateKeyPath), options: .atomic) } catch { - Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) + Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) } SharedDefaults[.gitSSHKeySource] = "url" self.navigationController!.popViewController(animated: true) diff --git a/pass/Controllers/SettingsTableViewController.swift b/pass/Controllers/SettingsTableViewController.swift index 7e0b26e..48714bb 100644 --- a/pass/Controllers/SettingsTableViewController.swift +++ b/pass/Controllers/SettingsTableViewController.swift @@ -35,21 +35,21 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultStyle(.light) - SVProgressHUD.show(withStatus: "Fetching PGP Key") + SVProgressHUD.show(withStatus: "FetchingPgpKey".localize()) DispatchQueue.global(qos: .userInitiated).async { [unowned self] in do { try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPublicKeyURL]!, keyType: .public) try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPrivateKeyURL]!, keyType: .secret) DispatchQueue.main.async { self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID - SVProgressHUD.showSuccess(withStatus: "Success") + SVProgressHUD.showSuccess(withStatus: "Success".localize()) SVProgressHUD.dismiss(withDelay: 1) - Utils.alert(title: "Remember to Remove the Key", message: "Remember to remove the key from the server.", controller: self, completion: nil) + Utils.alert(title: "RememberToRemoveKey".localize(), message: "RememberToRemoveKeyFromServer.".localize(), controller: self, completion: nil) } } catch { DispatchQueue.main.async { - self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set" - Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) + self.pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize() + Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) } } } @@ -65,20 +65,20 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultStyle(.light) - SVProgressHUD.show(withStatus: "Fetching PGP Key") + SVProgressHUD.show(withStatus: "FetchingPgpKey".localize()) DispatchQueue.global(qos: .userInitiated).async { [unowned self] in do { try self.passwordStore.initPGPKey(with: SharedDefaults[.pgpPublicKeyArmor] ?? "", keyType: .public) try self.passwordStore.initPGPKey(with: SharedDefaults[.pgpPrivateKeyArmor] ?? "", keyType: .secret) DispatchQueue.main.async { self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID - SVProgressHUD.showSuccess(withStatus: "Success") + SVProgressHUD.showSuccess(withStatus: "Success".localize()) SVProgressHUD.dismiss(withDelay: 1) } } catch { DispatchQueue.main.async { - self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set" - Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) + self.pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize() + Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) } } } @@ -90,20 +90,20 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele SharedDefaults[.pgpKeySource] = "file" SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultStyle(.light) - SVProgressHUD.show(withStatus: "Fetching PGP Key") + SVProgressHUD.show(withStatus: "FetchingPgpKey".localize()) DispatchQueue.global(qos: .userInitiated).async { [unowned self] in do { try self.passwordStore.pgpKeyImportFromFileSharing() try self.passwordStore.initPGPKeys() DispatchQueue.main.async { self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID - SVProgressHUD.showSuccess(withStatus: "Imported") + SVProgressHUD.showSuccess(withStatus: "Imported".localize()) SVProgressHUD.dismiss(withDelay: 1) } } catch { DispatchQueue.main.async { - self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set" - Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) + self.pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize() + Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) } } } @@ -133,9 +133,9 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele private func setPasscodeLockCell() { if passcodeLock.hasPasscode { - self.passcodeTableViewCell.detailTextLabel?.text = "On" + self.passcodeTableViewCell.detailTextLabel?.text = "On".localize() } else { - self.passcodeTableViewCell.detailTextLabel?.text = "Off" + self.passcodeTableViewCell.detailTextLabel?.text = "Off".localize() } } @@ -143,13 +143,13 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele if let pgpKeyID = self.passwordStore.pgpKeyID { pgpKeyTableViewCell.detailTextLabel?.text = pgpKeyID } else { - pgpKeyTableViewCell.detailTextLabel?.text = "Not Set" + pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize() } } private func setPasswordRepositoryTableViewCellDetailText() { if SharedDefaults[.gitURL] == nil { - passwordRepositoryTableViewCell.detailTextLabel?.text = "Not Set" + passwordRepositoryTableViewCell.detailTextLabel?.text = "NotSet".localize() } else { passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]!.host } @@ -176,9 +176,9 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele func showPGPKeyActionSheet() { let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - var urlActionTitle = "Download from URL" - var armorActionTitle = "ASCII-Armor Encrypted Key" - var fileActionTitle = "iTunes File Sharing" + var urlActionTitle = "DownloadFromUrl".localize() + var armorActionTitle = "AsciiArmorEncryptedKey".localize() + var fileActionTitle = "ITunesFileSharing".localize() if SharedDefaults[.pgpKeySource] == "url" { urlActionTitle = "✓ \(urlActionTitle)" @@ -193,26 +193,26 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele let armorAction = UIAlertAction(title: armorActionTitle, style: .default) { _ in self.performSegue(withIdentifier: "setPGPKeyByASCIISegue", sender: self) } - let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) + let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil) optionMenu.addAction(urlAction) optionMenu.addAction(armorAction) if passwordStore.pgpKeyExists(inFileSharing: true) { - fileActionTitle.append(" (Import)") + fileActionTitle.append(" (\("Import".localize()))") let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in // passphrase related - let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert) + let savePassphraseAlert = UIAlertController(title: "Passphrase".localize(), message: "WantToSavePassphrase?".localize(), preferredStyle: UIAlertControllerStyle.alert) // no - savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in + savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: UIAlertActionStyle.default) { _ in self.passwordStore.pgpKeyPassphrase = nil SharedDefaults[.isRememberPGPPassphraseOn] = false self.saveImportedPGPKey() }) // yes - savePassphraseAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive) {_ in + savePassphraseAlert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertActionStyle.destructive) {_ in // ask for the passphrase - let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in + let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in self.passwordStore.pgpKeyPassphrase = alert.textFields?.first?.text SharedDefaults[.isRememberPGPPassphraseOn] = true self.saveImportedPGPKey() @@ -227,10 +227,10 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele } optionMenu.addAction(fileAction) } else { - fileActionTitle.append(" (Tips)") + fileActionTitle.append(" (\("Tips".localize()))") let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in - let title = "Tips" - let message = "Copy your ASCII-armored public and private keys to Pass with names \"gpg_key.pub\" and \"gpg_key\" (without quotes) via iTunes. Then come back and click \"iTunes File Sharing\" to finish." + let title = "Tips".localize() + let message = "CopyPrivateKeyToPass.".localize() Utils.alert(title: title, message: message, controller: self) } optionMenu.addAction(fileAction) @@ -238,9 +238,9 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele if SharedDefaults[.pgpKeySource] != nil { - let deleteAction = UIAlertAction(title: "Remove PGP Keys", style: .destructive) { _ in + let deleteAction = UIAlertAction(title: "RemovePgpKeys".localize(), style: .destructive) { _ in self.passwordStore.removePGPKeys() - self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set" + self.pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize() } optionMenu.addAction(deleteAction) } @@ -255,7 +255,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele let passcodeRemoveViewController = PasscodeLockViewController() - let removePasscodeAction = UIAlertAction(title: "Remove Passcode", style: .destructive) { [weak self] _ in + let removePasscodeAction = UIAlertAction(title: "RemovePasscode".localize(), style: .destructive) { [weak self] _ in passcodeRemoveViewController.successCallback = { self?.passcodeLock.delete() self?.setPasscodeLockCell() @@ -263,11 +263,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele self?.present(passcodeRemoveViewController, animated: true, completion: nil) } - let changePasscodeAction = UIAlertAction(title: "Change Passcode", style: .default) { [weak self] _ in + let changePasscodeAction = UIAlertAction(title: "ChangePasscode".localize(), style: .default) { [weak self] _ in self?.setPasscodeLock() } - let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) + let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil) optionMenu.addAction(removePasscodeAction) optionMenu.addAction(changePasscodeAction) optionMenu.addAction(cancelAction) @@ -292,20 +292,20 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele func setPasscodeLock() { // prepare the alert for setting the passcode - setPasscodeLockAlert = UIAlertController(title: "Set passcode", message: "Fill in your passcode for Pass (at least 4 characters)", preferredStyle: .alert) + setPasscodeLockAlert = UIAlertController(title: "SetPasscode".localize(), message: "FillInAppPasscode.".localize(), preferredStyle: .alert) setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in - textField.placeholder = "Password" + textField.placeholder = "Password".localize() textField.isSecureTextEntry = true textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControlEvents.editingChanged) }) setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in - textField.placeholder = "Password Confirmation" + textField.placeholder = "PasswordConfirmation".localize() textField.isSecureTextEntry = true textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControlEvents.editingChanged) }) // save action - let saveAction = UIAlertAction(title: "Save", style: .default) { (action:UIAlertAction) -> Void in + let saveAction = UIAlertAction(title: "Save".localize(), style: .default) { (action:UIAlertAction) -> Void in let passcode: String = self.setPasscodeLockAlert!.textFields![0].text! self.passcodeLock.save(passcode: passcode) // refresh the passcode lock cell ("On") @@ -314,7 +314,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele saveAction.isEnabled = false // disable the Save button by default // cancel action - let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) + let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil) // present setPasscodeLockAlert?.addAction(saveAction) diff --git a/pass/Controllers/SpecialThanksTableViewController.swift b/pass/Controllers/SpecialThanksTableViewController.swift index abd68da..baec567 100644 --- a/pass/Controllers/SpecialThanksTableViewController.swift +++ b/pass/Controllers/SpecialThanksTableViewController.swift @@ -10,7 +10,7 @@ import UIKit class SpecialThanksTableViewController: BasicStaticTableViewController { let openSourceComponents = [ - ["Contributors", + ["Contributors".localize(), "https://github.com/mssun/passforios/graphs/contributors"], ["Password Store", "https://passwordstore.org"], diff --git a/pass/Helpers/UtilsExtension.swift b/pass/Helpers/UtilsExtension.swift index 418d41e..07e0da6 100644 --- a/pass/Helpers/UtilsExtension.swift +++ b/pass/Helpers/UtilsExtension.swift @@ -14,7 +14,7 @@ extension Utils { static func alert(title: String, message: String, controller: UIViewController, handler: ((UIAlertAction) -> Void)? = nil, completion: (() -> Void)? = nil) { SVProgressHUD.dismiss() let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: handler)) + alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: handler)) controller.present(alert, animated: true, completion: completion) } } diff --git a/pass/Views/LabelTableViewCell.swift b/pass/Views/LabelTableViewCell.swift index 7f22ae3..81d3985 100644 --- a/pass/Views/LabelTableViewCell.swift +++ b/pass/Views/LabelTableViewCell.swift @@ -51,7 +51,7 @@ class LabelTableViewCell: UITableViewCell { } } contentLabel.font = Globals.passwordFont - } else if title.caseInsensitiveCompare("hmac-based") == .orderedSame { + } else if title.caseInsensitiveCompare("HmacBased".localize()) == .orderedSame { type = .HOTP if isReveal { contentLabel.text = content diff --git a/pass/en.lproj/Localizable.strings b/pass/en.lproj/Localizable.strings index f0caa01..f9b8064 100644 --- a/pass/en.lproj/Localizable.strings +++ b/pass/en.lproj/Localizable.strings @@ -6,5 +6,239 @@ Copyright © 2019 Bob Sun. All rights reserved. */ -"Apple" = "Apple"; -"Random" = "Random"; +// General +"PassForIos" = "Pass for iOS"; +"Passphrase" = "Passphrase"; +"Passwords" = "Passwords"; +"Apple" = "Apple"; +"Settings" = "Settings"; +"Contributors" = "Contributors"; + +// OTP related +"TimeBased" = "time-based"; +"HmacBased" = "HMAC-based"; +"None" = "None"; +"ExpiresIn" = "(expires in %ds)"; + +// General (error) messages +"Error" = "Error"; +"CannotSave" = "Cannot Save"; +"UnresolvedError" = "Unresolved error %@"; +"MigrationError" = "Migration error: %@"; +"UnderlyingError" = "Underlying Error: %@"; +"ErrorSaving" = "Error saving: %@"; +"CannotCopyPassword" = "Cannot copy password"; +"CannotAddPassword" = "Cannot add password"; +"WrongPassphrase" = "Wrong passphrase"; +"MakeSurePgpAndGitProperlySet." = "Please make sure PGP key and Git server are properly set."; +"RecoverySuggestion" = "Recovery suggestion: Wrong credential password/passphrase has been removed, please try again."; +"NSURLFileAllocatedSizeKeyShouldAlwaysReturnValue." = "Huh? NSURLFileAllocatedSizeKey should always return a value."; + +// Settings +"PasswordGeneratorFlavor" = "Password Generator Flavor"; +"RememberPgpKeyPassphrase" = "Remember PGP Key Passphrase"; +"RememberGitCredentialPassphrase" = "Remember Git Credential Passphrase"; +"ShowFolders" = "Show Folders"; +"HideUnknownFields" = "Hide Unknown Fields"; +"HideUnknownFieldsExplanation." = "Only \"key: value\" format in additional fields is supported. Unsupported fields will be given \"unknown\" keys. Turn on this switch to hide unsupported fields."; +"HideOtpFields" = "Hide OTP Fields"; +"HideOtpFieldsExplanation." = "Turn on this switch to hide the fields related to one time passwords (i.e., %@)."; +"Random" = "Random"; +"RandomString" = "Random String"; +"ApplesKeychainStyle" = "Apple's Keychain Style"; + +// Git +"FailedToFetchPasswords" = "Failed to fetch passwords"; +"FailedToFetchPasswordEntities" = "Failed to fetch password entities: %@"; +"FailedToInsertPasswordEntity" = "Failed to insert password entity: %@"; +"FailedToDeletePasswordEntity" = "Failed to delete password entity: %@"; +"FailedToSavePasswordEntity" = "Failed to save password entity: %@"; +"FailureToSaveContext" = "Failure to save context: %@"; +"RepositoryRemoteMasterNotFoundError." = "Cannot find remote branch origin/master."; +"KeyImportError." = "Cannot import the key."; +"PasswordDuplicatedError." = "Cannot add the password; password is duplicated."; +"GitResetError." = "Cannot identify the latest synced commit."; +"PGPPublicKeyNotExistError." = "PGP public key doesn't exist."; +"WrongPasswordFilename." = "Cannot write to the password file."; +"DecryptionError." = "Cannot decrypt password."; +"UnknownError." = "Unknown error."; +"PrepareRepository" = "Prepare Repository"; +"CheckingOutBranch" = "Checking out branch '%@'"; +"WantToSaveGitCredential?" = "Do you want to save the Git credential password/passphrase?"; + +// Repository +"RepositoryNotSetError." = "Git repository is not set."; +"SetGitRepositoryUrl" = "Please set the Git repository URL."; +"CannotFindUsername." = "Cannot find the username in the Git repository URL. Example URL: ssh://git@server/path/to/repo.git."; +"CheckEnteredUsername." = "Please check the entered username and the username in the Git repository URL. They should match."; +"UseHttps." = "Please use HTTPS instead of HTTP."; +"SpecifySchema." = "Please specify the scheme of the Git repository URL (HTTPS or SSH)."; +"Overwrite?" = "Overwrite?"; +"Overwrite" = "Overwrite"; +"OperationWillOverwriteData." = "This operation will overwrite your current password store data (repository). Data on your remote server will not be affected."; +"DownloadFromUrl" = "Download from URL"; +"AsciiArmorEncryptedKey" = "ASCII-Armor Encrypted Key"; +"ITunesFileSharing" = "iTunes File Sharing"; +"Import" = "Import"; +"Imported" = "Imported"; +"Tips" = "Tips"; +"CopyPrivateKeyToPass." = "Copy your ASCII-armored private key to Pass with the name \"ssh_key\" (without quotes) via iTunes. Then come back and click \"iTunes File Sharing\" to finish."; +"FillInGitAccountPassword." = "Please fill in the password of your Git account."; +"NoPasswordStore." = "There is no password store right now."; +"SyncingPasswordStore" = "Syncing Password Store"; +"PushingToRemoteRepository" = "Pushing to Remote Repository"; + +// SSH +"FillInSshKeyPassphrase." = "Please fill in the passphrase of your SSH key."; +"CannotSelectSshKey" = "Cannot Select SSH Key"; +"PleaseSetupSshKeyFirst." = "Please setup SSH key first."; +"RemoveSShKeys" = "Remove Git SSH Keys"; +"SetPrivateKeyUrl." = "Please set private key URL first."; + +// QR code scanning +"LookingForStartingFrame." = "Looking for the starting frame."; +"TooManyQrCodes" = "Too many QR codes"; +"ScanPrivateKeyQrCodes" = "Scan Private Key QR Codes"; +"CannotSaveSshKey" = "Cannot Save SSH Key"; +"ScanPublicKey." = "Please scan public key."; +"ScanPrivateKey." = "Please scan private key."; +"ScanPrivateKeyQrCodes" = "Scan Private Key QR codes"; +"ScanPublicKeyQrCodes" = "Scan Public Key QR codes"; +"SetPrivateKey." = "Please set private key first."; +"SetPublicKey." = "Please set public key first."; +"NoQrCodeDetected." = "No QR code detected."; +"NoStringValue" = "No string value"; +"CameraAccessDenied." = "Camera access denied."; +"WarningToggleCameraPermissionsResetsApp." = "WARNING: Toggle the camera permission resets the app! Save your changes."; + +// PGP +"Decrypting" = "Decrypting"; +"PgpKeyNotSet." = "PGP Key is not set. Please set your PGP Key first."; +"FillInPgpPassphrase." = "Please fill in the passphrase of your PGP secret key."; +"SetPgpKey." = "PGP Key is not set. Please set your PGP Key first."; +"WantToSavePassphrase?" = "Do you want to save the passphrase for later decryption?"; +"CannotSavePgpKey" = "Cannot Save PGP Key"; +"SetPgpKeyUrlFirst." = "Please set PGP key URL first."; +"FetchingPgpKey" = "Fetching PGP Key"; +"RememberToRemoveKey" = "Remember to Remove the Key"; +"RememberToRemoveKeyFromServer." = "Remember to remove the key from the server."; +"RemovePgpKeys" = "Remove PGP Keys"; + +// App passcode +"RemovePasscode" = "Remove Passcode"; +"ChangePasscode" = "Change Passcode"; +"SetPasscode" = "Set Passcode"; +"PasswordConfirmation" = "Password Confirmation"; +"FillInAppPasscode." = "Fill in your passcode for Pass (at least 4 characters)."; + +// Git signature +"NotSet" = "Not Set"; +"InvalidNameOrEmail" = "Invalid name or e-mail"; + +// Erase password store +"ErasePasswordStoreData?" = "Erase password store data?"; +"ErasePasswordStoreData" = "Erase Password Store Data"; +"EraseExplanation." = "This will delete all local data and settings. Password store data on your remote server will not be affected."; +"Erasing..." = "Erasing ..."; + +// Discard local changes +"DiscardAllLocalChanges?" = "Discard all local changes?"; +"DiscardAllLocalChanges" = "Discard All Local Changes"; +"DiscardExplanation." = "Do you want to permanently discard all changes to the local copy of your password data? You cannot undo this action."; +"Resetting..." = "Resetting ..."; + +// Time related +"Unknown" = "Unknown"; +"JustNow" = "Just now"; +"TimeAgo" = "%@ ago"; + +// Commit messages +"AddPassword." = "Add password for %@ to store using Pass for iOS."; +"RemovePassword." = "Remove %@ from store using Pass for iOS."; +"EditPassword." = "Edit password for %@ using Pass for iOS."; +"RenamePassword." = "Rename %@ to %@ using Pass for iOS."; + +// Menu buttons +"Ok" = "OK"; +"Cancel" = "Cancel"; +"Dismiss" = "Dismiss"; +"Done" = "Done"; +"Yes" = "Yes"; +"No" = "No"; +"TryAgain" = "Try Again"; +"Delete" = "Delete"; +"Back" = "Back"; +"Current" = "Current"; +"All" = "All"; +"On" = "On"; +"Off" = "Off"; +"Save" = "Save"; + +// Lock screen +"EnterPasscode" = "Enter passcode for Pass"; +"Passcode" = "Passcode"; +"TouchId" = "Touch ID"; +"FaceId" = "Face ID"; +"AuthenticationNeeded." = "Authentication is needed to access Pass."; + +// About repository +"AboutRepository" = "About Repository"; +"ValueNotAvailable" = "Value not available"; +"Size" = "Size"; +"LocalCommits" = "Local Commits"; +"LastSynced" = "Last Synced"; +"Commits" = "Commits"; +"CommitLogs" = "Commit Logs"; +"SyncAgain?" = "Oops! Sync again?"; + +// About app +"Website" = "Website"; +"Help" = "Help"; +"ContactDeveloper" = "Contact Developer"; +"OpenSourceComponents" = "Open Source Components"; +"SpecialThanks" = "Special Thanks"; +"Acknowledgements" = "Acknowledgements"; +"ValueNotAvailable" = "Value not available"; + +// External applications +"CannotOpenMail" = "Cannot open Mail app"; +"CopiedEmail" = "Copied email %@"; +"HttpNotSupported." = "HTTP connection is not supported."; + +// Password view +"Notice" = "Notice"; +"PreviousChangesDiscarded." = "All previous local changes have been discarded. Your current Password Store will be shown."; +"CannotShowPassword" = "Cannot show password"; +"PasswordDoesNotExist" = "The password does not exist."; +"Saving" = "Saving"; +"Success" = "Success"; +"OneTimePassword" = "One-Time Password"; +"ShowRaw" = "Show Raw"; +"Reveal" = "Reveal"; +"Conceal" = "Conceal"; +"NextPassword" = "Next Password"; +"CopyAndOpen" = "Copy Password & Open Link"; +"GetNextPasswordOfNonHotp." = "Get next password of a non-HOTP entry."; +"PasswordCopied" = "Password Copied"; +"CounterUpdated" = "Counter Updated"; +"CannotFindValidUrl" = "Cannot find a valid URL"; +"LastUpdated" = "Last Updated: %@"; +"PasswordCopiedToPasteboard." = "Password copied. We will clear the pasteboard in 45 seconds."; + +// Password editor +"UseKeyValueFormat." = "Use \"key: value\" format for additional fields."; +"DeletePassword" = "Delete Password"; +"AddOneTimePassword" = "Add One-Time Password"; +"GetMemorableOne" = "Get a Memorable One: xkpasswd"; +"Length" = "Length"; +"DeletePassword?" = "Delete Password?"; +"OverwriteOtpConfiguration?" = "Overwrite the one-time password configuration?"; +"ValidTokenUrl" = "Valid token URL"; +"InvalidTokenUrl" = "Invalid token URL"; +"FillInName." = "Please fill in the name."; +"RemovePrefix." = "Please remove the prefix \"/\" from your password name."; +"PasswordNameInvalid." = "Password name is invalid."; +"CannotParseFilename." = "Cannot parse the filename. Please check and simplify the password name."; +"WannaUseIt?" = "Wanna use it?"; +"SeemsLikeYouHaveCopiedSomething." = "It seems like you have copied something."; +"FirstStringIs:" = "The first string is:"; diff --git a/pass/en.lproj/Localizable.stringsdict b/pass/en.lproj/Localizable.stringsdict new file mode 100644 index 0000000..c7ffeaf --- /dev/null +++ b/pass/en.lproj/Localizable.stringsdict @@ -0,0 +1,76 @@ + + + + + ScannedQrCodes(%d) + + NSStringLocalizedFormatKey + %#@code@ + codes + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + zero + No scanned QR code + one + One scanned QR code + other + %d scanned QR codes + + + DiscardedCommits(%d) + + NSStringLocalizedFormatKey + %#@commits@ + commits + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + zero + No local commits + one + Discarded one commit + other + Discarded %d commits + + + HiddenFields(%d) + + NSStringLocalizedFormatKey + %#@fields@ + fields + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + zero + No hidden field + one + One hidden field + other + %d hidden fields + + + WrongAttempts(%d) + + NSStringLocalizedFormatKey + %#@attempts@ + attempts + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + zero + No wrong attempt + one + One wrong attempt + other + %d wrong attempts + + + + diff --git a/passAutoFillExtension/CredentialProviderViewController.swift b/passAutoFillExtension/CredentialProviderViewController.swift index 3e87a4c..fa48cc4 100644 --- a/passAutoFillExtension/CredentialProviderViewController.swift +++ b/passAutoFillExtension/CredentialProviderViewController.swift @@ -146,7 +146,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa let entry = getPasswordEntry(by: indexPath) guard self.passwordStore.privateKey != nil else { - Utils.alert(title: "Cannot Copy Password", message: "PGP Key is not set. Please set your PGP Key first.", controller: self, completion: nil) + Utils.alert(title: "CannotCopyPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self, completion: nil) return } @@ -166,7 +166,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa DispatchQueue.main.async { // remove the wrong passphrase so that users could enter it next time self.passwordStore.pgpKeyPassphrase = nil - Utils.alert(title: "Cannot Copy Password", message: error.localizedDescription, controller: self, completion: nil) + Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil) } } } @@ -187,8 +187,8 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa let sem = DispatchSemaphore(value: 0) var passphrase = "" DispatchQueue.main.async { - let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertController.Style.alert) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: {_ in + let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertController.Style.alert) + alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertAction.Style.default, handler: {_ in passphrase = alert.textFields!.first!.text! sem.signal() })) diff --git a/passExtension/ExtensionViewController.swift b/passExtension/ExtensionViewController.swift index 2e5593c..84a7a6c 100644 --- a/passExtension/ExtensionViewController.swift +++ b/passExtension/ExtensionViewController.swift @@ -154,7 +154,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV let entry = getPasswordEntry(by: indexPath) guard self.passwordStore.privateKey != nil else { - Utils.alert(title: "Cannot Copy Password", message: "PGP Key is not set. Please set your PGP Key first.", controller: self, completion: nil) + Utils.alert(title: "CannotCopyPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self, completion: nil) return } @@ -192,7 +192,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV DispatchQueue.main.async { // remove the wrong passphrase so that users could enter it next time self.passwordStore.pgpKeyPassphrase = nil - Utils.alert(title: "Cannot Copy Password", message: error.localizedDescription, controller: self, completion: nil) + Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil) } } } @@ -214,8 +214,8 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV let sem = DispatchSemaphore(value: 0) var passphrase = "" DispatchQueue.main.async { - let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in + let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: {_ in passphrase = alert.textFields!.first!.text! sem.signal() })) diff --git a/passKit/Controllers/PasscodeLockViewController.swift b/passKit/Controllers/PasscodeLockViewController.swift index f32e68c..166e7fe 100644 --- a/passKit/Controllers/PasscodeLockViewController.swift +++ b/passKit/Controllers/PasscodeLockViewController.swift @@ -30,7 +30,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { super.loadView() let passcodeLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 40)) - passcodeLabel.text = "Enter passcode for Pass" + passcodeLabel.text = "EnterPasscode".localize() passcodeLabel.font = UIFont.boldSystemFont(ofSize: 18) passcodeLabel.textColor = UIColor.black passcodeLabel.textAlignment = .center @@ -48,7 +48,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { let passcodeTextField = UITextField(frame: CGRect(x: 0, y: 0, width: 300, height: 40)) passcodeTextField.borderStyle = UITextBorderStyle.roundedRect - passcodeTextField.placeholder = "passcode" + passcodeTextField.placeholder = "Passcode".localize() passcodeTextField.isSecureTextEntry = true passcodeTextField.clearButtonMode = UITextFieldViewMode.whileEditing passcodeTextField.delegate = self @@ -71,10 +71,10 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { var authError: NSError? if #available(iOS 8.0, macOS 10.12.1, *) { if myContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) { - var biometryType = "Touch ID" + var biometryType = "TouchId".localize() if #available(iOS 11.0, *) { if myContext.biometryType == LABiometryType.faceID { - biometryType = "Face ID" + biometryType = "FaceId".localize() } } biometryAuthButton.setTitle(biometryType, for: .normal) @@ -83,7 +83,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { } let cancelButton = UIButton(type: .custom) - cancelButton.setTitle("Cancel", for: .normal) + cancelButton.setTitle("Cancel".localize(), for: .normal) cancelButton.setTitleColor(Globals.blue, for: .normal) cancelButton.addTarget(self, action: #selector(passcodeLockDidCancel), for: .touchUpInside) cancelButton.isHidden = !self.isCancellable @@ -167,7 +167,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { @objc func bioButtonPressedAction(_ uiButton: UIButton) { let myContext = LAContext() - let myLocalizedReasonString = "Authentication is needed to access Pass." + let myLocalizedReasonString = "AuthenticationNeeded.".localize() var authError: NSError? if #available(iOS 8.0, *) { @@ -188,11 +188,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { if textField == passcodeTextField { if !PasscodeLock.shared.check(passcode: textField.text ?? "") { passcodeFailedAttempts = passcodeFailedAttempts + 1 - if passcodeFailedAttempts == 1 { - passcodeWrongAttemptsLabel?.text = "1 wrong attempt" - } else { - passcodeWrongAttemptsLabel?.text = "\(passcodeFailedAttempts) wrong attempts" - } + passcodeWrongAttemptsLabel?.text = "WrongAttempts(%d)".localize(passcodeFailedAttempts) } } textField.resignFirstResponder() diff --git a/passKit/Helpers/AppError.swift b/passKit/Helpers/AppError.swift index c185ea8..266ecc2 100644 --- a/passKit/Helpers/AppError.swift +++ b/passKit/Helpers/AppError.swift @@ -23,27 +23,6 @@ public enum AppError: Error { extension AppError: LocalizedError { public var errorDescription: String? { - switch self { - case .RepositoryNotSetError: - return "Git repository is not set." - case let .RepositoryRemoteBranchNotFoundError(remoteBranchName): - return "Cannot find remote branch 'origin/\(remoteBranchName)'." - case let .RepositoryBranchNotFound(branchName): - return "Branch with name '\(branchName)' not found in repository." - case .KeyImportError: - return "Cannot import the key." - case .PasswordDuplicatedError: - return "Cannot add the password: password duplicated." - case .GitResetError: - return "Cannot identify the latest synced commit." - case .PGPPublicKeyNotExistError: - return "PGP public key doesn't exist." - case .WrongPasswordFilename: - return "Cannot write to the password file." - case .DecryptionError: - return "Cannot decrypt password." - case .UnknownError: - return "Unknown error." - } + return String(describing: self).localize() } } diff --git a/passKit/Helpers/FileManagerExtension.swift b/passKit/Helpers/FileManagerExtension.swift index c1bfa16..74373d5 100644 --- a/passKit/Helpers/FileManagerExtension.swift +++ b/passKit/Helpers/FileManagerExtension.swift @@ -77,7 +77,7 @@ public extension FileManager { fileSize = try fileSize ?? resourceValueForKey(URLResourceKey.fileAllocatedSizeKey) guard let size = fileSize else { - preconditionFailure("huh? NSURLFileAllocatedSizeKey should always return a value") + preconditionFailure("NSURLFileAllocatedSizeKeyShouldAlwaysReturnValue.".localize()) } // We're good, add up the value. diff --git a/passKit/Helpers/Utils.swift b/passKit/Helpers/Utils.swift index 614de74..f764d6e 100644 --- a/passKit/Helpers/Utils.swift +++ b/passKit/Helpers/Utils.swift @@ -56,7 +56,7 @@ public class Utils { public static func alert(title: String, message: String, controller: UIViewController, handler: ((UIAlertAction) -> Void)? = nil, completion: (() -> Void)? = nil) { let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert) - alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: handler)) + alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertActionStyle.default, handler: handler)) controller.present(alert, animated: true, completion: completion) } } diff --git a/passKit/Models/Password.swift b/passKit/Models/Password.swift index 2eab7d9..fecdb33 100644 --- a/passKit/Models/Password.swift +++ b/passKit/Models/Password.swift @@ -175,9 +175,9 @@ public class Password { if case let .timer(period) = otpToken!.generator.factor { let timeSinceEpoch = Date().timeIntervalSince1970 let validTime = Int(period - timeSinceEpoch.truncatingRemainder(dividingBy: period)) - description += " (expires in \(validTime)s)" + description += " " + "ExpiresIn".localize(validTime) } - return (description, otpToken!.currentPassword ?? "error") + return (description, otpToken!.currentPassword ?? "Error".localize()) } // return the password strings diff --git a/passKit/Models/PasswordStore.swift b/passKit/Models/PasswordStore.swift index 5f9e381..9196d12 100644 --- a/passKit/Models/PasswordStore.swift +++ b/passKit/Models/PasswordStore.swift @@ -91,7 +91,7 @@ public class PasswordStore { * The store could not be migrated to the current model version. Check the error message to determine what the actual problem was. */ - fatalError("Unresolved error \(error), \(error.userInfo)") + fatalError("UnresolvedError".localize("\(error.localizedDescription), \(error.userInfo)")) } }) return container.viewContext @@ -162,7 +162,7 @@ public class PasswordStore { } try fm.moveItem(atPath: Globals.repositoryPathLegacy, toPath: Globals.repositoryPath) } catch { - print("Migration error: \(error)") + print("MigrationError".localize(error)) } updatePasswordEntityCoreData() } @@ -266,7 +266,7 @@ public class PasswordStore { return false } } catch { - fatalError("Failed to fetch password entities: \(error)") + fatalError("FailedToFetchPasswordEntities".localize(error)) } return true } @@ -282,7 +282,7 @@ public class PasswordStore { return false } } catch { - fatalError("Failed to fetch password entities: \(error)") + fatalError("FailedToFetchPasswordEntities".localize(error)) } return true } @@ -293,7 +293,7 @@ public class PasswordStore { passwordEntityFetchRequest.predicate = NSPredicate(format: "path = %@ and isDir = %@", path, isDir as NSNumber) return try context.fetch(passwordEntityFetchRequest).first as? PasswordEntity } catch { - fatalError("Failed to fetch password entities: \(error)") + fatalError("FailedToFetchPasswordEntities".localize(error)) } } @@ -417,7 +417,7 @@ public class PasswordStore { do { try context.save() } catch { - print("Error with save: \(error)") + print("ErrorSaving".localize(error)) } } @@ -445,7 +445,7 @@ public class PasswordStore { let fetchedPasswordEntities = try context.fetch(passwordEntityFetch) as! [PasswordEntity] return fetchedPasswordEntities.sorted { $0.name!.caseInsensitiveCompare($1.name!) == .orderedAscending } } catch { - fatalError("Failed to fetch passwords: \(error)") + fatalError("FailedToFetchPasswords".localize(error)) } } @@ -458,7 +458,7 @@ public class PasswordStore { let fetchedPasswordEntities = try context.fetch(passwordEntityFetch) as! [PasswordEntity] return fetchedPasswordEntities.sorted { $0.name!.caseInsensitiveCompare($1.name!) == .orderedAscending } } catch { - fatalError("Failed to fetch passwords: \(error)") + fatalError("FailedToFetchPasswords".localize(error)) } } @@ -470,7 +470,7 @@ public class PasswordStore { let passwordEntities = try context.fetch(passwordEntityFetchRequest) as! [PasswordEntity] return passwordEntities } catch { - fatalError("Failed to fetch passwords: \(error)") + fatalError("FailedToFetchPasswords".localize(error)) } } @@ -484,32 +484,32 @@ public class PasswordStore { try context.save() } } catch { - fatalError("Failed to save: \(error)") + fatalError("ErrorSaving".localize(error)) } } public func getLatestUpdateInfo(filename: String) -> String { guard let storeRepository = storeRepository else { - return "Unknown" + return "Unknown".localize() } guard let blameHunks = try? storeRepository.blame(withFile: filename, options: nil).hunks, let latestCommitTime = blameHunks.map({ $0.finalSignature?.time?.timeIntervalSince1970 ?? 0 }).max() else { - return "Unknown" + return "Unknown".localize() } let lastCommitDate = Date(timeIntervalSince1970: latestCommitTime) let currentDate = Date() var autoFormattedDifference: String if currentDate.timeIntervalSince(lastCommitDate) <= 60 { - autoFormattedDifference = "Just now" + autoFormattedDifference = "JustNow".localize() } else { let diffDate = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: lastCommitDate, to: currentDate) let dateComponentsFormatter = DateComponentsFormatter() dateComponentsFormatter.unitsStyle = .full dateComponentsFormatter.maximumUnitCount = 2 dateComponentsFormatter.includesApproximationPhrase = true - autoFormattedDifference = dateComponentsFormatter.string(from: diffDate)!.appending(" ago") + autoFormattedDifference = "TimeAgo".localize(dateComponentsFormatter.string(from: diffDate)!) } return autoFormattedDifference } @@ -646,7 +646,7 @@ public class PasswordStore { try self.context.save() ret = passwordEntity } catch { - fatalError("Failed to insert a PasswordEntity: \(error)") + fatalError("FailedToInsertPasswordEntity".localize(error)) } } return ret @@ -658,7 +658,7 @@ public class PasswordStore { let saveURL = storeURL.appendingPathComponent(password.url.path) try self.encrypt(password: password).write(to: saveURL) try gitAdd(path: password.url.path) - let _ = try gitCommit(message: "Add password for \(password.url.deletingPathExtension().path) to store using Pass for iOS.") + let _ = try gitCommit(message: "AddPassword.".localize(password.url.deletingPathExtension().path)) NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) return newPasswordEntity } @@ -668,7 +668,7 @@ public class PasswordStore { try gitRm(path: deletedFileURL.path) try deletePasswordEntities(passwordEntity: passwordEntity) try deleteDirectoryTree(at: deletedFileURL) - let _ = try gitCommit(message: "Remove \(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!) from store using Pass for iOS.") + let _ = try gitCommit(message: "RemovePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!)) NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) } @@ -679,7 +679,7 @@ public class PasswordStore { let saveURL = storeURL.appendingPathComponent(passwordEntity.getURL()!.path) try self.encrypt(password: password).write(to: saveURL) try gitAdd(path: passwordEntity.getURL()!.path) - let _ = try gitCommit(message: "Edit password for \(passwordEntity.getURL()!.deletingPathExtension().path.removingPercentEncoding!) using Pass for iOS.") + let _ = try gitCommit(message: "EditPassword.".localize(passwordEntity.getURL()!.deletingPathExtension().path.removingPercentEncoding!)) newPasswordEntity = passwordEntity newPasswordEntity?.synced = false } @@ -696,8 +696,7 @@ public class PasswordStore { // delete try deleteDirectoryTree(at: deletedFileURL) try deletePasswordEntities(passwordEntity: passwordEntity) - let _ = try gitCommit(message: "Rename \(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!) to \(password.url.deletingPathExtension().path.removingPercentEncoding!) using Pass for iOS.") - + let _ = try gitCommit(message: "RenamePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!, password.url.deletingPathExtension().path.removingPercentEncoding!)) } NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) return newPasswordEntity @@ -712,7 +711,7 @@ public class PasswordStore { do { try self.context.save() } catch { - fatalError("Failed to delete a PasswordEntity: \(error)") + fatalError("FailedToDeletePasswordEntity".localize(error)) } } } @@ -721,7 +720,7 @@ public class PasswordStore { do { try context.save() } catch { - fatalError("Failed to save a PasswordEntity: \(error)") + fatalError("FailedToSavePasswordEntity".localize(error)) } } @@ -752,11 +751,11 @@ public class PasswordStore { do { try self.context.save() } catch { - fatalError("Failure to save context: \(error)") + fatalError("FailureToSaveContext".localize(error)) } } } catch { - fatalError("Failure to save context: \(error)") + fatalError("FailureToSaveContext".localize(error)) } } } diff --git a/passKit/Parser/OtpType.swift b/passKit/Parser/OtpType.swift index 032c2dc..4c277d0 100644 --- a/passKit/Parser/OtpType.swift +++ b/passKit/Parser/OtpType.swift @@ -9,12 +9,12 @@ import OneTimePassword public enum OtpType: String { - case totp = "time-based" - case hotp = "HMAC-based" - case none + case totp = "TimeBased" + case hotp = "HmacBased" + case none = "None" var description: String { - return rawValue + return rawValue.localize() } init(token: Token?) { diff --git a/passKitTests/Models/PasswordTest.swift b/passKitTests/Models/PasswordTest.swift index 38088ad..ced64ee 100644 --- a/passKitTests/Models/PasswordTest.swift +++ b/passKitTests/Models/PasswordTest.swift @@ -304,9 +304,11 @@ class PasswordTest: XCTestCase { func testOtpStringsTotpToken() { let password = getPasswordObjectWith(content: TOTP_URL) let otpStrings = password.getOtpStrings() + let otpDescription = otpStrings!.description XCTAssertNotNil(otpStrings) - XCTAssert(otpStrings!.description.hasPrefix("time-based (expires in")) + XCTAssert(otpDescription.hasPrefix("TimeBased".localize() + " (")) + XCTAssert(otpDescription.hasSuffix(")")) } func testOtpStringsHotpToken() { @@ -314,6 +316,6 @@ class PasswordTest: XCTestCase { let otpStrings = password.getOtpStrings() XCTAssertNotNil(otpStrings) - XCTAssertEqual(otpStrings!.description, "HMAC-based") + XCTAssertEqual(otpStrings!.description, "HmacBased".localize()) } } diff --git a/passKitTests/Parser/OtpTypeTest.swift b/passKitTests/Parser/OtpTypeTest.swift index 50a4aee..c1bdb36 100644 --- a/passKitTests/Parser/OtpTypeTest.swift +++ b/passKitTests/Parser/OtpTypeTest.swift @@ -38,8 +38,8 @@ class OtpTypeTest: XCTestCase { } func testDescription() { - XCTAssertEqual(OtpType(name: "totp").description, "time-based") - XCTAssertEqual(OtpType(name: "hotp").description, "HMAC-based") - XCTAssertEqual(OtpType(name: nil).description, "none") + XCTAssertEqual(OtpType(name: "totp").description, "TimeBased".localize()) + XCTAssertEqual(OtpType(name: "hotp").description, "HmacBased".localize()) + XCTAssertEqual(OtpType(name: nil).description, "None".localize()) } }