summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2021-07-07 14:16:08 +0200
committerAndrej Mihajlov <and@mullvad.net>2021-07-22 13:07:43 +0200
commit1d31f34f23a889b7810d75de20883e80bdb9e7fc (patch)
tree9fe4743d3dc82bd4efbef5f99a7c6b1736127a64
parentfc34d04f9b7ca18267230be55267f04c82c9c96a (diff)
downloadmullvadvpn-1d31f34f23a889b7810d75de20883e80bdb9e7fc.tar.xz
mullvadvpn-1d31f34f23a889b7810d75de20883e80bdb9e7fc.zip
Localize MullvadRest, StoreKit, AppStorePaymentManager, TunnelManager errors
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj48
-rw-r--r--ios/MullvadVPN/DisplayChainedError.swift282
-rw-r--r--ios/MullvadVPN/MullvadRest.swift21
-rw-r--r--ios/MullvadVPN/en.lproj/AppStorePaymentManager.strings17
-rw-r--r--ios/MullvadVPN/en.lproj/MullvadRest.strings23
-rw-r--r--ios/MullvadVPN/en.lproj/StoreKitErrors.strings14
-rw-r--r--ios/MullvadVPN/en.lproj/TunnelManager.strings53
7 files changed, 416 insertions, 42 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index e3c651d6c4..41dfd4d62f 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -227,7 +227,11 @@
58F558E32695D1D800F630D0 /* Preferences.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F558E12695D1D800F630D0 /* Preferences.strings */; };
58F558E62695D1F200F630D0 /* ProblemReport.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F558E42695D1F200F630D0 /* ProblemReport.strings */; };
58F558E92695D20F00F630D0 /* SelectLocation.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F558E72695D20F00F630D0 /* SelectLocation.strings */; };
+ 58F558EC2695D26A00F630D0 /* MullvadRest.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F558EA2695D26A00F630D0 /* MullvadRest.strings */; };
58F558EF2695D50D00F630D0 /* ProblemReportReview.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F558ED2695D50D00F630D0 /* ProblemReportReview.strings */; };
+ 58F558F92696EB1C00F630D0 /* StoreKitErrors.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F558F32696EB1C00F630D0 /* StoreKitErrors.strings */; };
+ 58F558FA2696EB1C00F630D0 /* TunnelManager.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F558F52696EB1C00F630D0 /* TunnelManager.strings */; };
+ 58F558FB2696EB1C00F630D0 /* AppStorePaymentManager.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F558F72696EB1C00F630D0 /* AppStorePaymentManager.strings */; };
58F5590E2697002100F630D0 /* Main.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F559052697002000F630D0 /* Main.strings */; };
58F5590F2697002100F630D0 /* ConnectionPanel.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F559072697002100F630D0 /* ConnectionPanel.strings */; };
58F61F4F2692F21C00DCFC2B /* WireguardKeys.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F61F4D2692F21C00DCFC2B /* WireguardKeys.strings */; };
@@ -451,7 +455,11 @@
58F558E22695D1D800F630D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Preferences.strings; sourceTree = "<group>"; };
58F558E52695D1F200F630D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ProblemReport.strings; sourceTree = "<group>"; };
58F558E82695D20F00F630D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/SelectLocation.strings; sourceTree = "<group>"; };
+ 58F558EB2695D26A00F630D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MullvadRest.strings; sourceTree = "<group>"; };
58F558EE2695D50D00F630D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ProblemReportReview.strings; sourceTree = "<group>"; };
+ 58F558F42696EB1C00F630D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/StoreKitErrors.strings; sourceTree = "<group>"; };
+ 58F558F62696EB1C00F630D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TunnelManager.strings; sourceTree = "<group>"; };
+ 58F558F82696EB1C00F630D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/AppStorePaymentManager.strings; sourceTree = "<group>"; };
58F559062697002000F630D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Main.strings; sourceTree = "<group>"; };
58F559082697002100F630D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ConnectionPanel.strings; sourceTree = "<group>"; };
58F61F4E2692F21C00DCFC2B /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/WireguardKeys.strings; sourceTree = "<group>"; };
@@ -559,17 +567,21 @@
isa = PBXGroup;
children = (
581FC4F82695ACE100AA97BA /* Account.strings */,
+ 58F558F72696EB1C00F630D0 /* AppStorePaymentManager.strings */,
582CFEE526945FC30072883A /* AppStoreSubscriptions.strings */,
58F559072697002100F630D0 /* ConnectionPanel.strings */,
58F558DB2695B85E00F630D0 /* Consent.strings */,
587B7543266922BF00DEF7E9 /* Localizable.strings */,
58F558DE2695BD3E00F630D0 /* Login.strings */,
58F559052697002000F630D0 /* Main.strings */,
+ 58F558EA2695D26A00F630D0 /* MullvadRest.strings */,
58F558E12695D1D800F630D0 /* Preferences.strings */,
58F558E42695D1F200F630D0 /* ProblemReport.strings */,
58F558ED2695D50D00F630D0 /* ProblemReportReview.strings */,
58F558E72695D20F00F630D0 /* SelectLocation.strings */,
582CFEE8269463B80072883A /* Settings.strings */,
+ 58F558F32696EB1C00F630D0 /* StoreKitErrors.strings */,
+ 58F558F52696EB1C00F630D0 /* TunnelManager.strings */,
58F61F4D2692F21C00DCFC2B /* WireguardKeys.strings */,
);
name = Localizations;
@@ -978,8 +990,10 @@
58F3C0A624A50157003E76BE /* relays.json in Resources */,
58F558DD2695B85E00F630D0 /* Consent.strings in Resources */,
58727283265D173C00F315B2 /* LaunchScreen.storyboard in Resources */,
+ 58F558FB2696EB1C00F630D0 /* AppStorePaymentManager.strings in Resources */,
586ADD4723FC13F400CE9E87 /* countries.geo.json in Resources */,
58F5590F2697002100F630D0 /* ConnectionPanel.strings in Resources */,
+ 58F558FA2696EB1C00F630D0 /* TunnelManager.strings in Resources */,
58F558E02695BD3E00F630D0 /* Login.strings in Resources */,
58CE5E6B224146210008646E /* Assets.xcassets in Resources */,
58F558E92695D20F00F630D0 /* SelectLocation.strings in Resources */,
@@ -989,10 +1003,12 @@
58F558EF2695D50D00F630D0 /* ProblemReportReview.strings in Resources */,
584789B8264D4A2A000E45FB /* old_le_root_cert.cer in Resources */,
58F558E62695D1F200F630D0 /* ProblemReport.strings in Resources */,
+ 58F558F92696EB1C00F630D0 /* StoreKitErrors.strings in Resources */,
584789BE264D4A2A000E45FB /* new_le_root_cert.cer in Resources */,
58F61F4F2692F21C00DCFC2B /* WireguardKeys.strings in Resources */,
58F5590E2697002100F630D0 /* Main.strings in Resources */,
581FC4FA2695ACE100AA97BA /* Account.strings in Resources */,
+ 58F558EC2695D26A00F630D0 /* MullvadRest.strings in Resources */,
582CFEEA269463B80072883A /* Settings.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1361,6 +1377,14 @@
name = SelectLocation.strings;
sourceTree = "<group>";
};
+ 58F558EA2695D26A00F630D0 /* MullvadRest.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 58F558EB2695D26A00F630D0 /* en */,
+ );
+ name = MullvadRest.strings;
+ sourceTree = "<group>";
+ };
58F558ED2695D50D00F630D0 /* ProblemReportReview.strings */ = {
isa = PBXVariantGroup;
children = (
@@ -1369,6 +1393,30 @@
name = ProblemReportReview.strings;
sourceTree = "<group>";
};
+ 58F558F32696EB1C00F630D0 /* StoreKitErrors.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 58F558F42696EB1C00F630D0 /* en */,
+ );
+ name = StoreKitErrors.strings;
+ sourceTree = "<group>";
+ };
+ 58F558F52696EB1C00F630D0 /* TunnelManager.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 58F558F62696EB1C00F630D0 /* en */,
+ );
+ name = TunnelManager.strings;
+ sourceTree = "<group>";
+ };
+ 58F558F72696EB1C00F630D0 /* AppStorePaymentManager.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 58F558F82696EB1C00F630D0 /* en */,
+ );
+ name = AppStorePaymentManager.strings;
+ sourceTree = "<group>";
+ };
58F559052697002000F630D0 /* Main.strings */ = {
isa = PBXVariantGroup;
children = (
diff --git a/ios/MullvadVPN/DisplayChainedError.swift b/ios/MullvadVPN/DisplayChainedError.swift
index c27658b6ce..aeb10a80ef 100644
--- a/ios/MullvadVPN/DisplayChainedError.swift
+++ b/ios/MullvadVPN/DisplayChainedError.swift
@@ -18,7 +18,12 @@ extension RestError: DisplayChainedError {
switch self {
case .network(let urlError):
return String(
- format: NSLocalizedString("Network error: %@", comment: ""),
+ format: NSLocalizedString(
+ "NETWORK_ERROR",
+ tableName: "MullvadRest",
+ value: "Network error: %@",
+ comment: "Network error. Use %@ placeholder to place localized failure description."
+ ),
urlError.localizedDescription
)
case .server(let serverError):
@@ -26,16 +31,36 @@ extension RestError: DisplayChainedError {
return knownErrorDescription
} else {
return String(
- format: NSLocalizedString("Server error: %@", comment: ""),
+ format: NSLocalizedString(
+ "SERVER_ERROR",
+ tableName: "MullvadRest",
+ value: "Server error: %@",
+ comment: "Server error. Use %@ placeholder to place localized failure description."
+ ),
serverError.error ?? "(empty)"
)
}
case .encodePayload:
- return NSLocalizedString("Server request encoding error", comment: "")
+ return NSLocalizedString(
+ "SERVER_REQUEST_ENCODING_ERROR",
+ tableName: "MullvadRest",
+ value: "Server request encoding error",
+ comment: "Failure to encode the server request."
+ )
case .decodeSuccessResponse:
- return NSLocalizedString("Server success response decoding error", comment: "")
+ return NSLocalizedString(
+ "SERVER_SUCCESS_RESPONSE_DECODING_ERROR",
+ tableName: "MullvadRest",
+ value: "Server success response decoding error",
+ comment: "Failure to decode the server success response."
+ )
case .decodeErrorResponse:
- return NSLocalizedString("Server error response decoding error", comment: "")
+ return NSLocalizedString(
+ "SERVER_FAILURE_RESPONSE_DECODING_ERROR",
+ tableName: "MullvadRest",
+ value: "Server error response decoding error",
+ comment: "Failure to decode the server failure response."
+ )
}
}
}
@@ -44,59 +69,165 @@ extension TunnelManager.Error: DisplayChainedError {
var errorChainDescription: String? {
switch self {
case .loadAllVPNConfigurations(let systemError):
- return String(format: NSLocalizedString("Failed to load system VPN configurations: %@", comment: ""), systemError.localizedDescription)
+ return String(
+ format: NSLocalizedString(
+ "LOAD_ALL_VPN_CONFIGURATIONS_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to load system VPN configurations: %@",
+ comment: ""
+ ),
+ systemError.localizedDescription
+ )
case .reloadVPNConfiguration(let systemError):
- return String(format: NSLocalizedString("Failed to reload a VPN configuration: %@", comment: ""), systemError.localizedDescription)
+ return String(
+ format: NSLocalizedString(
+ "RELOAD_VPN_CONFIGURATIONS_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to reload a VPN configuration: %@",
+ comment: ""
+ ),
+ systemError.localizedDescription
+ )
case .saveVPNConfiguration(let systemError):
- return String(format: NSLocalizedString("Failed to save a VPN tunnel configuration: %@", comment: ""), systemError.localizedDescription)
+ return String(
+ format: NSLocalizedString(
+ "SAVE_VPN_CONFIGURATION_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to save a VPN tunnel configuration: %@",
+ comment: ""
+ ),
+ systemError.localizedDescription
+ )
case .obtainPersistentKeychainReference(_):
- return NSLocalizedString("Failed to obtain the persistent keychain reference for the VPN configuration", comment: "")
+ return NSLocalizedString(
+ "OBTAIN_PERSISTENT_KEYCHAIN_REFERENCE_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to obtain the persistent keychain reference for the VPN configuration",
+ comment: ""
+ )
case .startVPNTunnel(let systemError):
- return String(format: NSLocalizedString("System error when starting the VPN tunnel: %@", comment: ""), systemError.localizedDescription)
+ return String(
+ format: NSLocalizedString(
+ "START_VPN_TUNNEL_ERROR",
+ tableName: "TunnelManager",
+ value: "System error when starting the VPN tunnel: %@",
+ comment: ""
+ ),
+ systemError.localizedDescription
+ )
case .removeVPNConfiguration(let systemError):
- return String(format: NSLocalizedString("Failed to remove the system VPN configuration: %@", comment: ""), systemError.localizedDescription)
+ return String(
+ format: NSLocalizedString(
+ "REMOVE_VPN_CONFIGURATION_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to remove the system VPN configuration: %@",
+ comment: ""
+ ),
+ systemError.localizedDescription
+ )
case .removeInconsistentVPNConfiguration(let systemError):
- return String(format: NSLocalizedString("Failed to remove the outdated system VPN configuration: %@", comment: ""), systemError.localizedDescription)
+ return String(
+ format: NSLocalizedString(
+ "REMOVE_INCONSISTENT_VPN_CONFIGURATION",
+ tableName: "TunnelManager",
+ value: "Failed to remove the outdated system VPN configuration: %@",
+ comment: ""
+ ),
+ systemError.localizedDescription
+ )
case .readTunnelSettings(_):
- return NSLocalizedString("Failed to read tunnel settings", comment: "")
+ return NSLocalizedString(
+ "READ_TUNNEL_SETTINGS_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to read tunnel settings",
+ comment: ""
+ )
case .addTunnelSettings(_):
- return NSLocalizedString("Failed to add tunnel settings", comment: "")
+ return NSLocalizedString(
+ "ADD_TUNNEL_SETTINGS_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to add tunnel settings",
+ comment: ""
+ )
case .updateTunnelSettings(_):
- return NSLocalizedString("Failed to update tunnel settings", comment: "")
+ return NSLocalizedString(
+ "UPDATE_TUNNEL_SETTINGS_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to update tunnel settings",
+ comment: ""
+ )
case .removeTunnelSettings(_):
- return NSLocalizedString("Failed to remove tunnel settings", comment: "")
+ return NSLocalizedString(
+ "REMOVE_TUNNEL_SETTINGS_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to remove tunnel settings",
+ comment: ""
+ )
case .migrateTunnelSettings(_):
- return NSLocalizedString("Failed to migrate tunnel settings", comment: "")
+ return NSLocalizedString(
+ "MIGRATE_TUNNEL_SETTINGS_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to migrate tunnel settings",
+ comment: ""
+ )
case .pushWireguardKey(let restError):
let reason = restError.errorChainDescription ?? ""
- var message = String(format: NSLocalizedString("Failed to send the WireGuard key to server: %@", comment: ""), reason)
+ var message = String(
+ format: NSLocalizedString(
+ "PUSH_WIREGUARD_KEY_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to send the WireGuard key to server: %@",
+ comment: ""
+ ),
+ reason
+ )
if case .server(.keyLimitReached) = restError {
+ // TODO: maybe use `restError.recoverySuggestion` instead?
message.append("\n\n")
- message.append(NSLocalizedString("Remove unused WireGuard keys and try again", comment: ""))
+ message.append(NSLocalizedString(
+ "PUSH_WIREGUARD_KEY_RECOVERY_SUGGESTION",
+ tableName: "TunnelManager",
+ value: "Remove unused WireGuard keys and try again",
+ comment: ""
+ ))
}
return message
case .replaceWireguardKey(let restError):
let reason = restError.errorChainDescription ?? ""
- var message = String(format: NSLocalizedString("Failed to replace the WireGuard key on server: %@", comment: ""), reason)
+ var message = String(
+ format: NSLocalizedString(
+ "REPLACE_WIREGUARD_KEY_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to replace the WireGuard key on server: %@",
+ comment: ""
+ ),
+ reason
+ )
if case .server(.keyLimitReached) = restError {
+ // TODO: maybe use `restError.recoverySuggestion` instead?
message.append("\n\n")
- message.append(NSLocalizedString("Remove unused WireGuard keys and try again", comment: ""))
+ message.append(NSLocalizedString(
+ "REPLACE_WIREGUARD_KEY_RECOVERY_SUGGESTION",
+ tableName: "TunnelManager",
+ value: "Remove unused WireGuard keys and try again",
+ comment: "")
+ )
}
return message
@@ -108,10 +239,23 @@ extension TunnelManager.Error: DisplayChainedError {
case .verifyWireguardKey(let restError):
let reason = restError.errorChainDescription ?? ""
- return String(format: NSLocalizedString("Failed to verify the WireGuard key on server: %@", comment: ""), reason)
+ return String(
+ format: NSLocalizedString(
+ "VERIFY_WIREGUARD_KEY_ERROR",
+ tableName: "TunnelManager",
+ value: "Failed to verify the WireGuard key on server: %@",
+ comment: ""
+ ),
+ reason
+ )
case .missingAccount:
- return NSLocalizedString("Internal error: missing account", comment: "")
+ return NSLocalizedString(
+ "MISSING_ACCOUNT_INTERNAL_ERROR",
+ tableName: "TunnelManager",
+ value: "Internal error: missing account",
+ comment: ""
+ )
}
}
}
@@ -132,15 +276,40 @@ extension SKError: LocalizedError {
public var errorDescription: String? {
switch self.code {
case .unknown:
- return NSLocalizedString("Unknown error", comment: "")
+ return NSLocalizedString(
+ "UNKNOWN_ERROR",
+ tableName: "StoreKitErrors",
+ value: "Unknown error",
+ comment: ""
+ )
case .clientInvalid:
- return NSLocalizedString("Client is not allowed to issue the request", comment: "")
+ return NSLocalizedString(
+ "CLIENT_INVALID",
+ tableName: "StoreKitErrors",
+ value: "Client is not allowed to issue the request",
+ comment: ""
+ )
case .paymentCancelled:
- return NSLocalizedString("User cancelled the request", comment: "")
+ return NSLocalizedString(
+ "PAYMENT_CANCELLED",
+ tableName: "StoreKitErrors",
+ value: "User cancelled the request",
+ comment: ""
+ )
case .paymentInvalid:
- return NSLocalizedString("Invalid purchase identifier", comment: "")
+ return NSLocalizedString(
+ "PAYMENT_INVALID",
+ tableName: "StoreKitErrors",
+ value: "Invalid purchase identifier",
+ comment: ""
+ )
case .paymentNotAllowed:
- return NSLocalizedString("This device is not allowed to make the payment", comment: "")
+ return NSLocalizedString(
+ "PAYMENT_NOT_ALLOWED",
+ tableName: "StoreKitErrors",
+ value: "This device is not allowed to make the payment",
+ comment: ""
+ )
default:
return self.localizedDescription
}
@@ -151,29 +320,64 @@ extension AppStorePaymentManager.Error: DisplayChainedError {
var errorChainDescription: String? {
switch self {
case .noAccountSet:
- return NSLocalizedString("Internal error: account is not set", comment: "")
+ return NSLocalizedString(
+ "NO_ACCOUNT_SET_ERROR",
+ tableName: "AppStorePaymentManager",
+ value: "Internal error: account is not set",
+ comment: ""
+ )
case .readReceipt(let readReceiptError):
switch readReceiptError {
case .refresh(let storeError):
let skErrorMessage = (storeError as? SKError)?.errorDescription ?? storeError.localizedDescription
- return String(format: NSLocalizedString("Cannot refresh the AppStore receipt: %@", comment: ""), skErrorMessage)
+ return String(
+ format: NSLocalizedString(
+ "REFRESH_RECEIPT_ERROR",
+ tableName: "AppStorePaymentManager",
+ value: "Cannot refresh the AppStore receipt: %@",
+ comment: ""
+ ),
+ skErrorMessage
+ )
case .io(let ioError):
- return String(format: NSLocalizedString("Cannot read the AppStore receipt from disk: %@", comment: ""), ioError.localizedDescription)
+ return String(
+ format: NSLocalizedString(
+ "READ_RECEIPT_ERROR",
+ tableName: "AppStorePaymentManager",
+ value: "Cannot read the AppStore receipt from disk: %@",
+ comment: ""
+ ),
+ ioError.localizedDescription
+ )
case .doesNotExist:
- return NSLocalizedString("AppStore receipt is not found on disk.", comment: "")
+ return NSLocalizedString(
+ "RECEIPT_NOT_FOUND_ERROR",
+ tableName: "AppStorePaymentManager",
+ value: "AppStore receipt is not found on disk.",
+ comment: ""
+ )
}
case .sendReceipt(let restError):
let reason = restError.errorChainDescription ?? ""
- let format = NSLocalizedString(#"""
-Failed to send the receipt to server: %@
-
-Please retry by using the "Restore purchases" button.
-"""#, comment: "")
-
- return String(format: format, reason)
+ let errorFormat = NSLocalizedString(
+ "SEND_RECEIPT_ERROR",
+ tableName: "AppStorePaymentManager",
+ value: "Failed to send the receipt to server: %@",
+ comment: ""
+ )
+ let recoverySuggestion = NSLocalizedString(
+ "SEND_RECEIPT_RECOVERY_SUGGESTION",
+ tableName: "AppStorePaymentManager",
+ value: "Please retry by using the \"Restore purchases\" button.",
+ comment: ""
+ )
+ var errorString = String(format: errorFormat, reason)
+ errorString.append("\n\n")
+ errorString.append(recoverySuggestion)
+ return errorString
case .storePayment(let storeError):
return (storeError as? SKError)?.errorDescription ?? storeError.localizedDescription
diff --git a/ios/MullvadVPN/MullvadRest.swift b/ios/MullvadVPN/MullvadRest.swift
index 2fc99b4d64..0e7abdc239 100644
--- a/ios/MullvadVPN/MullvadRest.swift
+++ b/ios/MullvadVPN/MullvadRest.swift
@@ -69,9 +69,19 @@ struct ServerErrorResponse: LocalizedError, Decodable, Equatable {
var errorDescription: String? {
switch code {
case Code.keyLimitReached.rawValue:
- return NSLocalizedString("Too many WireGuard keys in use.", comment: "")
+ return NSLocalizedString(
+ "KEY_LIMIT_REACHED_ERROR_DESCRIPTION",
+ tableName: "MullvadRest",
+ value: "Too many WireGuard keys in use.",
+ comment: ""
+ )
case Code.invalidAccount.rawValue:
- return NSLocalizedString("Invalid account.", comment: "")
+ return NSLocalizedString(
+ "INVALID_ACCOUNT_ERROR_DESCRIPTION",
+ tableName: "MullvadRest",
+ value: "Invalid account.",
+ comment: ""
+ )
default:
return nil
}
@@ -80,7 +90,12 @@ struct ServerErrorResponse: LocalizedError, Decodable, Equatable {
var recoverySuggestion: String? {
switch code {
case Code.keyLimitReached.rawValue:
- return NSLocalizedString("Please visit the website to revoke a key before login is possible.", comment: "")
+ return NSLocalizedString(
+ "KEY_LIMIT_REACHED_ERROR_RECOVERY_SUGGESTION",
+ tableName: "MullvadRest",
+ value: "Please visit the website to revoke a key before login is possible.",
+ comment: ""
+ )
default:
return nil
}
diff --git a/ios/MullvadVPN/en.lproj/AppStorePaymentManager.strings b/ios/MullvadVPN/en.lproj/AppStorePaymentManager.strings
new file mode 100644
index 0000000000..54c9c348c4
--- /dev/null
+++ b/ios/MullvadVPN/en.lproj/AppStorePaymentManager.strings
@@ -0,0 +1,17 @@
+/* No comment provided by engineer. */
+"NO_ACCOUNT_SET_ERROR" = "Internal error: account is not set";
+
+/* No comment provided by engineer. */
+"READ_RECEIPT_ERROR" = "Cannot read the AppStore receipt from disk: %@";
+
+/* No comment provided by engineer. */
+"RECEIPT_NOT_FOUND_ERROR" = "AppStore receipt is not found on disk.";
+
+/* No comment provided by engineer. */
+"REFRESH_RECEIPT_ERROR" = "Cannot refresh the AppStore receipt: %@";
+
+/* No comment provided by engineer. */
+"SEND_RECEIPT_ERROR" = "Failed to send the receipt to server: %@";
+
+/* No comment provided by engineer. */
+"SEND_RECEIPT_RECOVERY_SUGGESTION" = "Please retry by using the \"Restore purchases\" button.";
diff --git a/ios/MullvadVPN/en.lproj/MullvadRest.strings b/ios/MullvadVPN/en.lproj/MullvadRest.strings
new file mode 100644
index 0000000000..f5a83c67a3
--- /dev/null
+++ b/ios/MullvadVPN/en.lproj/MullvadRest.strings
@@ -0,0 +1,23 @@
+/* No comment provided by engineer. */
+"INVALID_ACCOUNT_ERROR_DESCRIPTION" = "Invalid account.";
+
+/* No comment provided by engineer. */
+"KEY_LIMIT_REACHED_ERROR_DESCRIPTION" = "Too many WireGuard keys in use.";
+
+/* No comment provided by engineer. */
+"KEY_LIMIT_REACHED_ERROR_RECOVERY_SUGGESTION" = "Please visit the website to revoke a key before login is possible.";
+
+/* Network error. Use %@ placeholder to place localized failure description. */
+"NETWORK_ERROR" = "Network error: %@";
+
+/* Server error. Use %@ placeholder to place localized failure description. */
+"SERVER_ERROR" = "Server error: %@";
+
+/* Failure to decode the server failure response. */
+"SERVER_FAILURE_RESPONSE_DECODING_ERROR" = "Server error response decoding error";
+
+/* Failure to encode the server request. */
+"SERVER_REQUEST_ENCODING_ERROR" = "Server request encoding error";
+
+/* Failure to decode the server success response. */
+"SERVER_SUCCESS_RESPONSE_DECODING_ERROR" = "Server success response decoding error";
diff --git a/ios/MullvadVPN/en.lproj/StoreKitErrors.strings b/ios/MullvadVPN/en.lproj/StoreKitErrors.strings
new file mode 100644
index 0000000000..99ac40881a
--- /dev/null
+++ b/ios/MullvadVPN/en.lproj/StoreKitErrors.strings
@@ -0,0 +1,14 @@
+/* No comment provided by engineer. */
+"CLIENT_INVALID" = "Client is not allowed to issue the request";
+
+/* No comment provided by engineer. */
+"PAYMENT_CANCELLED" = "User cancelled the request";
+
+/* No comment provided by engineer. */
+"PAYMENT_INVALID" = "Invalid purchase identifier";
+
+/* No comment provided by engineer. */
+"PAYMENT_NOT_ALLOWED" = "This device is not allowed to make the payment";
+
+/* No comment provided by engineer. */
+"UNKNOWN_ERROR" = "Unknown error";
diff --git a/ios/MullvadVPN/en.lproj/TunnelManager.strings b/ios/MullvadVPN/en.lproj/TunnelManager.strings
new file mode 100644
index 0000000000..93ce286a33
--- /dev/null
+++ b/ios/MullvadVPN/en.lproj/TunnelManager.strings
@@ -0,0 +1,53 @@
+/* No comment provided by engineer. */
+"ADD_TUNNEL_SETTINGS_ERROR" = "Failed to add tunnel settings";
+
+/* No comment provided by engineer. */
+"LOAD_ALL_VPN_CONFIGURATIONS_ERROR" = "Failed to load system VPN configurations: %@";
+
+/* No comment provided by engineer. */
+"MIGRATE_TUNNEL_SETTINGS_ERROR" = "Failed to migrate tunnel settings";
+
+/* No comment provided by engineer. */
+"MISSING_ACCOUNT_INTERNAL_ERROR" = "Internal error: missing account";
+
+/* No comment provided by engineer. */
+"OBTAIN_PERSISTENT_KEYCHAIN_REFERENCE_ERROR" = "Failed to obtain the persistent keychain reference for the VPN configuration";
+
+/* No comment provided by engineer. */
+"PUSH_WIREGUARD_KEY_ERROR" = "Failed to send the WireGuard key to server: %@";
+
+/* No comment provided by engineer. */
+"PUSH_WIREGUARD_KEY_RECOVERY_SUGGESTION" = "Remove unused WireGuard keys and try again";
+
+/* No comment provided by engineer. */
+"READ_TUNNEL_SETTINGS_ERROR" = "Failed to read tunnel settings";
+
+/* No comment provided by engineer. */
+"RELOAD_VPN_CONFIGURATIONS_ERROR" = "Failed to reload a VPN configuration: %@";
+
+/* No comment provided by engineer. */
+"REMOVE_INCONSISTENT_VPN_CONFIGURATION" = "Failed to remove the outdated system VPN configuration: %@";
+
+/* No comment provided by engineer. */
+"REMOVE_TUNNEL_SETTINGS_ERROR" = "Failed to remove tunnel settings";
+
+/* No comment provided by engineer. */
+"REMOVE_VPN_CONFIGURATION_ERROR" = "Failed to remove the system VPN configuration: %@";
+
+/* No comment provided by engineer. */
+"REPLACE_WIREGUARD_KEY_ERROR" = "Failed to replace the WireGuard key on server: %@";
+
+/* No comment provided by engineer. */
+"REPLACE_WIREGUARD_KEY_RECOVERY_SUGGESTION" = "Remove unused WireGuard keys and try again";
+
+/* No comment provided by engineer. */
+"SAVE_VPN_CONFIGURATION_ERROR" = "Failed to save a VPN tunnel configuration: %@";
+
+/* No comment provided by engineer. */
+"START_VPN_TUNNEL_ERROR" = "System error when starting the VPN tunnel: %@";
+
+/* No comment provided by engineer. */
+"UPDATE_TUNNEL_SETTINGS_ERROR" = "Failed to update tunnel settings";
+
+/* No comment provided by engineer. */
+"VERIFY_WIREGUARD_KEY_ERROR" = "Failed to verify the WireGuard key on server: %@";