Localize strings in code

This commit is contained in:
Danny Moesch 2019-01-14 20:57:45 +01:00 committed by Mingshen Sun
parent 2d5ca58bd9
commit 1b4040135e
36 changed files with 626 additions and 334 deletions

View file

@ -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 = "<group>"; };
30BF5EC921EA8FB5000E4154 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
30BF5ECE21EA90D1000E4154 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = String.swift; path = Localization/String.swift; sourceTree = "<group>"; };
30BF5ED621ED2434000E4154 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
30FD2F77214D9E0E005E0A92 /* ParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParserTest.swift; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>";
@ -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 = "<group>";
};
30BF5ED521ED2434000E4154 /* Localizable.stringsdict */ = {
isa = PBXVariantGroup;
children = (
30BF5ED621ED2434000E4154 /* en */,
);
name = Localizable.stringsdict;
sourceTree = "<group>";
};
A239F59A2158C08C00576CBF /* MainInterface.storyboard */ = {
isa = PBXVariantGroup;
children = (

View file

@ -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)"))
}
}
}

View file

@ -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

View file

@ -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
}

View file

@ -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
}

View file

@ -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)
}
}

View file

@ -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)
}

View file

@ -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 []
}
}

View file

@ -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)
}

View file

@ -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
}
}

View file

@ -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)
}

View file

@ -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()
})

View file

@ -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)
}

View file

@ -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)

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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()
})

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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"],

View file

@ -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)
}
}

View file

@ -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

View file

@ -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:";

View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ScannedQrCodes(%d)</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@code@</string>
<key>codes</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>zero</key>
<string>No scanned QR code</string>
<key>one</key>
<string>One scanned QR code</string>
<key>other</key>
<string>%d scanned QR codes</string>
</dict>
</dict>
<key>DiscardedCommits(%d)</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@commits@</string>
<key>commits</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string>No local commits</string>
<key>one</key>
<string>Discarded one commit</string>
<key>other</key>
<string>Discarded %d commits</string>
</dict>
</dict>
<key>HiddenFields(%d)</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@fields@</string>
<key>fields</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string>No hidden field</string>
<key>one</key>
<string>One hidden field</string>
<key>other</key>
<string>%d hidden fields</string>
</dict>
</dict>
<key>WrongAttempts(%d)</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@attempts@</string>
<key>attempts</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string>No wrong attempt</string>
<key>one</key>
<string>One wrong attempt</string>
<key>other</key>
<string>%d wrong attempts</string>
</dict>
</dict>
</dict>
</plist>

View file

@ -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()
}))

View file

@ -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()
}))

View file

@ -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()

View file

@ -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()
}
}

View file

@ -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.

View file

@ -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)
}
}

View file

@ -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

View file

@ -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))
}
}
}

View file

@ -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?) {

View file

@ -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())
}
}

View file

@ -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())
}
}