diff options
| author | Jon Petersson <jon.petersson@mullvad.net> | 2025-08-08 13:02:04 +0200 |
|---|---|---|
| committer | Jon Petersson <jon.petersson@mullvad.net> | 2025-08-08 13:02:04 +0200 |
| commit | 6dee63b6cb3e7dbf9e0d6c77d20a3a6e0dba0de1 (patch) | |
| tree | 1706c2324e68ced144281d83c03ac18dcea5add0 | |
| parent | 40db8f24fc66cb72f35e13eb1154479e50f55206 (diff) | |
| parent | 1926fe29fb6f2165fe232481076771d805a12a81 (diff) | |
| download | mullvadvpn-6dee63b6cb3e7dbf9e0d6c77d20a3a6e0dba0de1.tar.xz mullvadvpn-6dee63b6cb3e7dbf9e0d6c77d20a3a6e0dba0de1.zip | |
Merge branch 'extract-ios-strings-to-translate-ios-1223'
148 files changed, 3991 insertions, 2666 deletions
diff --git a/ios/Assets/Localizable.xcstrings b/ios/Assets/Localizable.xcstrings new file mode 100644 index 0000000000..a304340507 --- /dev/null +++ b/ios/Assets/Localizable.xcstrings @@ -0,0 +1,1162 @@ +{ + "sourceLanguage" : "en", + "strings" : { + "“%@ Local network sharing” requires restarting the VPN connection, which will disconnect you and briefly expose your traffic.\nTo prevent this, manually enable Airplane Mode and turn off Wi-Fi before continuing.\nWould you like to continue to enable “Local network sharing”?" : { + + }, + "**Attention: This increases network traffic and will also negatively affect speed, latency, and battery usage. Use with caution on limited plans.**\n\nDAITA (Defense against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic.\n\nBy using sophisticated AI it’s possible to analyze the traffic of data packets going in and out of your device (even if the traffic is encrypted)." : { + + }, + "**Tap here** to see what’s new." : { + + }, + "%@" : { + + }, + "%@ have been added to your account" : { + + }, + "%@ left on this account" : { + + }, + "%@ via %@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@ via %2$@" + } + } + } + }, + "%@ were added to your account." : { + + }, + "%@, %@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@, %2$@" + } + } + } + }, + "%d more..." : { + + }, + "%lld more..." : { + + }, + "About API access…" : { + + }, + "About Direct method..." : { + + }, + "About Encrypted DNS proxy method..." : { + + }, + "About Mullvad bridges method..." : { + + }, + "About Server IP override..." : { + + }, + "Account" : { + + }, + "Account created" : { + + }, + "Account credit expires soon" : { + + }, + "Account credit has expired" : { + + }, + "Account deletion" : { + + }, + "Account number" : { + + }, + "Active features" : { + + }, + "Add" : { + + }, + "Add 30 days" : { + + }, + "Add 90 days" : { + + }, + "Add a server" : { + + }, + "Add access method" : { + + }, + "Add locations" : { + + }, + "Add new list" : { + + }, + "Add time" : { + + }, + "Add Time" : { + + }, + "Ads" : { + + }, + "Adult content" : { + + }, + "Agree and continue" : { + + }, + "All" : { + + }, + "All locations" : { + + }, + "All Providers" : { + + }, + "Any" : { + + }, + "API access" : { + + }, + "API could not be reached, save anyway?" : { + + }, + "API reachable" : { + + }, + "API unreachable" : { + + }, + "App logs" : { + + }, + "AppStore receipt is not found on disk." : { + + }, + "Are you sure you want to log %@ out?" : { + + }, + "At least one method needs to be enabled." : { + + }, + "Authentication" : { + + }, + "Automatic" : { + + }, + "Back to editing" : { + + }, + "Blocked connection" : { + + }, + "BLOCKING INTERNET" : { + + }, + "Blocking internet: Your time on this account has expired. To continue using the internet, please add more time or disconnect the VPN." : { + + }, + "By enabling \"Direct only\" you will have to manually select a server that is DAITA-enabled. Multihop won't automatically be used to enable DAITA with any server." : { + + }, + "By enabling \"Direct only\" you will have to manually select a server that is DAITA-enabled. This can cause you to end up in a blocked state until you have selected a compatible server in the \"Select location\" view." : { + + }, + "Cancel" : { + + }, + "Cannot complete the purchase" : { + + }, + "Cannot read the AppStore receipt from disk" : { + + }, + "Cannot refresh the AppStore receipt: %@" : { + + }, + "Cannot restore purchases" : { + + }, + "Checking account number" : { + + }, + "Cipher" : { + + }, + "Clear" : { + + }, + "Clear all overrides" : { + + }, + "Clear all overrides?" : { + + }, + "Clearing the imported overrides changes the server IPs, in the Select location view, back to default." : { + + }, + "Client is not allowed to issue the request." : { + + }, + "Collapses this location." : { + + }, + "Congrats!" : { + + }, + "Connect" : { + + }, + "Connected" : { + + }, + "Connected to %@, %@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Connected to %1$@, %2$@" + } + } + } + }, + "Connecting to %@, %@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Connecting to %1$@, %2$@" + } + } + } + }, + "Connecting..." : { + + }, + "Connection details" : { + + }, + "Continue with login" : { + + }, + "Copy to pasteboard" : { + + }, + "Correct account number" : { + + }, + "Create" : { + + }, + "Create account" : { + + }, + "Created: %@" : { + + }, + "Creating new account" : { + + }, + "Creating quantum secure connection" : { + + }, + "Creating secure connection" : { + + }, + "Current device" : { + + }, + "Custom" : { + + }, + "Custom DNS" : { + + }, + "Custom lists" : { + + }, + "DAITA" : { + + }, + "DAITA (Defence against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic. If anyone is monitoring your connection, this makes it significantly harder for them to identify what websites you are visiting.\nIt does this by carefully adding network noise and making all network packets the same size.\nNot all our servers are DAITA-enabled. Therefore, we use multihop automatically to enable DAITA with any server.\nAttention: Be cautious if you have a limited data plan as this feature will increase your network traffic." : { + + }, + "DAITA isn't available at the currently selected location. After enabling, please go to the \"Select location\" view and select a location that supports DAITA." : { + + }, + "DAITA isn't available on the current entry server. After enabling, please go to the \"Select location\" view and select an entry location that supports DAITA." : { + + }, + "DAITA-enabled" : { + + }, + "DAITA: Multihop" : { + + }, + "Delete" : { + + }, + "Delete account" : { + + }, + "Delete Account" : { + + }, + "Delete list" : { + + }, + "Delete method" : { + + }, + "Deleting account..." : { + + }, + "Device is inactive" : { + + }, + "Device name" : { + + }, + "Device name: %@" : { + + }, + "Direct" : { + + }, + "Direct only" : { + + }, + "Disable all content blockers to activate this setting." : { + + }, + "Disabled" : { + + }, + "Disabling" : { + + }, + "Discard changes" : { + + }, + "Disconnect" : { + + }, + "Disconnected" : { + + }, + "Disconnecting" : { + + }, + "Disconnecting..." : { + + }, + "DNS content blockers" : { + + }, + "DNS settings" : { + + }, + "Do you agree to remaining anonymous?" : { + + }, + "Don’t have an account number?" : { + + }, + "Done" : { + + }, + "Edit custom list" : { + + }, + "Edit lists" : { + + }, + "Edit locations" : { + + }, + "Edit message" : { + + }, + "Enable" : { + + }, + "Enable \"%@\"" : { + + }, + "Enable method" : { + + }, + "Enabling" : { + + }, + "Encrypted DNS proxy" : { + + }, + "Enter IP" : { + + }, + "Enter voucher code" : { + + }, + "Enter your account number" : { + + }, + "Entry" : { + + }, + "Exit" : { + + }, + "Expands this location." : { + + }, + "Failed to connect to App store, please try again later." : { + + }, + "Failed to send" : { + + }, + "Failed to send the receipt to server: %@" : { + + }, + "Failed to start the tunnel: %@." : { + + }, + "Failed to start the tunnel." : { + + }, + "Failed to stop the tunnel: %@." : { + + }, + "Failed to stop the tunnel." : { + + }, + "Failed to validate account number: %@" : { + + }, + "FAQs & Guides" : { + + }, + "Fetching devices..." : { + + }, + "Filter" : { + + }, + "Filtered:" : { + + }, + "Gambling" : { + + }, + "Go ahead and start using the app to begin reclaiming your online privacy.\nTo continue your journey as a privacy ninja, visit our website to pick up other privacy-friendly habits and tools." : { + + }, + "Go to login" : { + + }, + "Going to login will unblock the Internet on this device." : { + + }, + "Got it!" : { + + }, + "Here’s your account number. Save it!" : { + + }, + "Hide account number" : { + + }, + "If an observer monitors these data packets, DAITA makes it significantly harder for them to identify which websites you are visiting or with whom you are communicating.\n\nDAITA does this by carefully adding network noise and making all network packets the same size.\n\nNot all our servers are DAITA-enabled. Therefore, we use multihop automatically to enable DAITA with any server.\n" : { + + }, + "If needed we will contact you at %@" : { + + }, + "If you are having issues connecting to VPN servers, please contact support." : { + + }, + "If you are not connected to our VPN, then the Encrypted DNS proxy will use your own non-VPN IP when connecting.\nThe DoH servers are hosted by one of the following providers: Quad9 or Cloudflare." : { + + }, + "If you disconnect now, you won’t be able to secure your connection until the device is online." : { + + }, + "If you exit the form and try again later, the information you already entered will still be here." : { + + }, + "If you haven’t received additional VPN time after purchasing" : { + + }, + "If you still experience issues you can email our support directly at **%@**. Please attach your app log to your email." : { + + }, + "Import" : { + + }, + "Import %@ was successful, overrides are now active." : { + + }, + "Import %@ was unsuccessful, please try again." : { + + }, + "Import file" : { + + }, + "Import files or text with the new IP addresses for the servers in the Select location view." : { + + }, + "Import successful" : { + + }, + "Import via text" : { + + }, + "In" : { + + }, + "In use" : { + + }, + "Include all networks" : { + + }, + "Internal error occurred. Settings will be reset to defaults and device logged out." : { + + }, + "Internal error." : { + + }, + "Invalid account" : { + + }, + "Invalid device state." : { + + }, + "Invalid purchase identifier." : { + + }, + "It looks like you have entered a Mullvad account number instead of a voucher code. Do you want to log in to an existing account?\nIf so, click log out below to log in with the other account number." : { + + }, + "Language" : { + + }, + "Last four digits of the account number are incorrect" : { + + }, + "Last used account" : { + + }, + "Learn about privacy" : { + + }, + "Less than a day" : { + + }, + "Local network sharing" : { + + }, + "Log in" : { + + }, + "Log out" : { + + }, + "Logged in" : { + + }, + "Logging in..." : { + + }, + "Logging out..." : { + + }, + "Login" : { + + }, + "Login failed" : { + + }, + "Make a purchase with StoreKit2" : { + + }, + "Malware" : { + + }, + "Manage default and setup custom methods to access the Mullvad API." : { + + }, + "Manage default and setup custom methods to access the Mullvad API. " : { + + }, + "Manage devices" : { + + }, + "method" : { + + }, + "Method settings" : { + + }, + "Mullvad bridges" : { + + }, + "Multihop" : { + + }, + "Multihop is being used to enable DAITA for your selected location." : { + + }, + "Multihop routes your traffic into one WireGuard server and out another, making it harder to trace.\nThis results in increased latency but increases anonymity online." : { + + }, + "Multihop routes your traffic into one WireGuard server and out another, making it harder to trace. This results in increased latency but increases anonymity online." : { + + }, + "Multiple validation errors occurred." : { + + }, + "Name" : { + + }, + "Name should be no longer than %i characters." : { + + }, + "Network error: %@" : { + + }, + "NETWORK ISSUES" : { + + }, + "New custom list" : { + + }, + "NEW DEVICE CREATED" : { + + }, + "NEW VERSION INSTALLED" : { + + }, + "Next" : { + + }, + "No matching relays found, check your filter settings." : { + + }, + "No matching servers" : { + + }, + "No network" : { + + }, + "No overrides imported" : { + + }, + "Obfuscation" : { + + }, + "Obfuscation hides the WireGuard traffic inside another protocol. It can be used to help circumvent censorship and other types of filtering, where a plain WireGuard connection would be blocked." : { + + }, + "Obscured" : { + + }, + "Off" : { + + }, + "On" : { + + }, + "On some networks, where various types of censorship are being used, our server IP addresses are sometimes blocked." : { + + }, + "On some networks, where various types of censorship are being used, the API servers might not be directly reachable." : { + + }, + "Open DAITA settings" : { + + }, + "Optional" : { + + }, + "Out IPv4" : { + + }, + "Out IPv6" : { + + }, + "Out of time" : { + + }, + "OUT OF TIME" : { + + }, + "Overrides active" : { + + }, + "Owned" : { + + }, + "Ownership" : { + + }, + "Paid until" : { + + }, + "Password" : { + + }, + "Performs a connection test to a Mullvad API server via this access method." : { + + }, + "Please enter a valid IPv4 or IPv6 address." : { + + }, + "Please enter a valid port." : { + + }, + "Please log out of at least one by removing it from the list below. You can find the corresponding device name under the device’s Account settings." : { + + }, + "Please retry by using the \"Restore purchases\" button." : { + + }, + "Port" : { + + }, + "Port: %@" : { + + }, + "Previous" : { + + }, + "Providers" : { + + }, + "Providers: %d" : { + + }, + "Quantum resistance" : { + + }, + "Quantum secure connection" : { + + }, + "Quantum secure connection. Connected to %@, %@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Quantum secure connection. Connected to %1$@, %2$@" + } + } + } + }, + "Quantum-resistant tunnel" : { + + }, + "QUIC" : { + + }, + "Reconnecting" : { + + }, + "Reconnecting to %@, %@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Reconnecting to %1$@, %2$@" + } + } + } + }, + "Redeem" : { + + }, + "Redeem voucher" : { + + }, + "Refund last purchase with StoreKit2" : { + + }, + "Refund successful" : { + + }, + "Remove" : { + + }, + "Remove %@?\nThe device will be removed from the list and logged out." : { + + }, + "Remove last used account" : { + + }, + "Rented" : { + + }, + "Report a problem" : { + + }, + "Required" : { + + }, + "Restore purchases" : { + + }, + "Save" : { + + }, + "Save anyway" : { + + }, + "Saving changes..." : { + + }, + "Search for..." : { + + }, + "Secure connection. Connected to %@, %@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Secure connection. Connected to %1$@, %2$@" + } + } + } + }, + "Select location" : { + + }, + "Selected" : { + + }, + "Send" : { + + }, + "Send anyway" : { + + }, + "Sending..." : { + + }, + "Sent" : { + + }, + "Server" : { + + }, + "Server details" : { + + }, + "Server IP override" : { + + }, + "Server IP Override" : { + + }, + "Setting: DAITA" : { + + }, + "Setting: Obfuscation" : { + + }, + "Settings" : { + + }, + "Settings migration error" : { + + }, + "Shadowsocks" : { + + }, + "Show account number" : { + + }, + "Social media" : { + + }, + "Start using the app" : { + + }, + "Super!" : { + + }, + "Switch location" : { + + }, + "Tap **Edit** to add at least one DNS server." : { + "comment" : "Foot note displayed if there are no DNS entries, but table view is not in editing mode." + }, + "Test method" : { + + }, + "Testing..." : { + + }, + "Thanks for your purchase" : { + + }, + "Thanks!" : { + + }, + "The app communicates with a Mullvad API server directly." : { + + }, + "The app communicates with a Mullvad API server via a Mullvad bridge server." : { + + }, + "The app communicates with a Mullvad API server via a proxy address." : { + + }, + "The app needs to communicate with a Mullvad API server to log you in, fetch server lists, and other critical operations." : { + + }, + "The app will test the method before saving." : { + + }, + "The automatic setting will randomly choose from the valid port ranges shown below.\nThe custom port can be any value inside the valid ranges:\n%@" : { + + }, + "The entry server for multihop is currently overridden by DAITA. To select an entry server, please first enable “Direct only” or disable “DAITA” in the settings." : { + + }, + "The payment request was cancelled." : { + + }, + "The version of settings stored on device is unrecognized.Settings will be reset to defaults and the device will be logged out." : { + + }, + "This can be useful if the API is censored but Mullvad’s bridge servers are not." : { + + }, + "This can be useful when you are not affected by censorship." : { + + }, + "This device is not allowed to make the payment." : { + + }, + "This feature allows access to other devices on the local network, such as for sharing, printing, streaming, etc.\nAttention: toggling “Local network sharing” requires restarting the VPN connection." : { + + }, + "This feature allows you to circumvent that censorship by adding custom ways to access the API via proxies and similar methods." : { + + }, + "This feature makes the WireGuard tunnel resistant to potential attacks from quantum computers.\nIt does this by performing an extra key exchange using a quantum safe algorithm and mixing the result into WireGuard’s regular encryption.\nThis extra step uses approximately 500 kiB of traffic every time a new tunnel is established." : { + + }, + "This is the name assigned to the device. Each device logged in on a Mullvad account gets a unique name that helps you identify it when you manage your devices in the app or on the website.\nYou can have up to 5 devices logged in on one Mullvad account.\nIf you log out, the device and the device name is removed. When you log back in again, the device will get a new name." : { + + }, + "This logs out all devices using this account and all VPN access will be denied even if there is time left on the account. Enter the last 4 digits of the account number and hit \"Delete account\" if you really want to delete the account:" : { + + }, + "This voucher code has already been used." : { + + }, + "Time left: %@" : { + + }, + "To assist you better, please write in English or Swedish and include which country you are connecting from." : { + + }, + "To circumvent this you can import a file or a text, provided by our support team, with new IP addresses that override the default addresses of the servers in the Select location view." : { + + }, + "To create a custom list, tap on \"...\" " : { + + }, + "To enable this setting, add at least one server." : { + "comment" : "Foot note displayed if there are no DNS entries and table view is in editing mode." + }, + "To help you more effectively, your app’s log file will be attached to this message. Your data will remain secure and private, as it is anonymised before being sent over an encrypted channel." : { + + }, + "To start using the app, you first need to add time to your account. Either buy credit on our website or redeem a voucher." : { + + }, + "Too many devices" : { + + }, + "Too many devices registered with account" : { + + }, + "Trackers" : { + + }, + "Try again" : { + + }, + "TUNNEL ERROR" : { + + }, + "Tunnel is unset." : { + + }, + "Type" : { + + }, + "UDP-over-TCP" : { + + }, + "Unexpected server response: %1$@ (HTTP status: %2$d)" : { + + }, + "Unexpected server response: %d" : { + + }, + "Unknown error." : { + + }, + "Unsecured connection" : { + + }, + "Use custom DNS server" : { + + }, + "Username" : { + + }, + "Valid range: 1 - 65535" : { + + }, + "value" : { + + }, + "Verifying voucher..." : { + + }, + "View and manage all your logged in devices. You can have up to 5 devices on one account at a time. Each device gets a name when logged in to help you tell them apart easily." : { + + }, + "View app logs" : { + + }, + "Voucher code is invalid." : { + + }, + "Voucher was successfully redeemed." : { + + }, + "VPN settings" : { + + }, + "Warning: The malware blocker is not an anti-virus and should not be treated as such, this is just an extra layer of protection." : { + + }, + "We are having some issues, please try again later" : { + + }, + "We will look into this." : { + + }, + "Welcome, this device is now called **%@**. For more details see the info button in Account." : { + + }, + "What's new" : { + + }, + "When this feature is enabled it stops the device from contacting certain domains or websites known for distributing ads, malware, trackers and more. \nThis might cause issues on certain websites, services, and apps.\nAttention: this setting cannot be used in combination with **Use custom DNS server**." : { + + }, + "When using DAITA, one provider with DAITA-enabled servers is required." : { + + }, + "Which TCP port the UDP-over-TCP obfuscation protocol should connect to on the VPN server." : { + + }, + "WireGuard Obfuscation" : { + + }, + "WireGuard ports" : { + + }, + "With the \"Direct\" method, the app communicates with a Mullvad API server directly without any intermediate proxies." : { + + }, + "With the \"Encrypted DNS proxy\" method, the app will communicate with our Mullvad API through a proxy address.\nIt does this by retrieving an address from a DNS over HTTPS (DoH) server and then using that to reach our API servers." : { + + }, + "With the \"Mullvad bridges\" method, the app communicates with a Mullvad API server via a Mullvad bridge server. It does this by sending the traffic obfuscated by Shadowsocks." : { + + }, + "Yes, continue" : { + + }, + "Yes, log out device" : { + + }, + "You are about to send the problem report without a way for us to get back to you. If you want an answer to your report you will have to enter an email address." : { + + }, + "You can add more time via the account view or website to continue using the VPN." : { + + }, + "You can now continue logging in on this device." : { + + }, + "You can use the \"restore purchases\" function to check for any in-app payments made via Apple services. If there is a payment that has not been credited, it will add the time to the currently logged in Mullvad account." : { + + }, + "You have %@ left on this account." : { + + }, + "You have a right to privacy. That’s why we never store activity logs, don’t ask for personal information, and encourage anonymous payments.\n\nIn some situations, as outlined in our privacy policy, we might process personal data that you choose to send, for example if you email us.\n\nWe strongly believe in retaining as little data as possible because we want you to remain anonymous." : { + + }, + "You have no more VPN time left on this account. Either buy credit on our website or make an in-app purchase via the **Add time** button below." : { + + }, + "You have no more VPN time left on this account. To add more, you will need to disconnect and access the Internet with an unsecure connection." : { + + }, + "You have one day left on this account. Please add more time to continue using the VPN." : { + + }, + "You have removed this device. To connect again, you will need to log back in." : { + + }, + "You have unsaved changes." : { + + }, + "You’re all set!!" : { + + }, + "Your device is offline. The tunnel will automatically connect once your device is back online." : { + + }, + "Your device is offline. Try connecting again when the device has access to Internet." : { + + }, + "Your email (optional)" : { + + }, + "Your previous purchases have already been added to this account." : { + + }, + "Your purchase was successfully refunded." : { + + } + }, + "version" : "1.0" +}
\ No newline at end of file diff --git a/ios/Localizations/da.lproj/Localizable.strings b/ios/Localizations/da.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/da.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/de.lproj/Localizable.strings b/ios/Localizations/de.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/de.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/en.lproj/Localizable.strings b/ios/Localizations/en.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/en.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/es.lproj/Localizable.strings b/ios/Localizations/es.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/es.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/fi.lproj/Localizable.strings b/ios/Localizations/fi.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/fi.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/fr.lproj/Localizable.strings b/ios/Localizations/fr.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/fr.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/it.lproj/Localizable.strings b/ios/Localizations/it.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/it.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/ja.lproj/Localizable.strings b/ios/Localizations/ja.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/ja.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/ko.lproj/Localizable.strings b/ios/Localizations/ko.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/ko.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/my.lproj/Localizable.strings b/ios/Localizations/my.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/my.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/nb.lproj/Localizable.strings b/ios/Localizations/nb.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/nb.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/nl.lproj/Localizable.strings b/ios/Localizations/nl.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/nl.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/pl.lproj/Localizable.strings b/ios/Localizations/pl.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/pl.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/pt-PT.lproj/Localizable.strings b/ios/Localizations/pt-PT.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/pt-PT.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/ru.lproj/Localizable.strings b/ios/Localizations/ru.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/ru.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/sv.lproj/Localizable.strings b/ios/Localizations/sv.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/sv.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/th.lproj/Localizable.strings b/ios/Localizations/th.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/th.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/tr.lproj/Localizable.strings b/ios/Localizations/tr.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/tr.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/zh-Hans.lproj/Localizable.strings b/ios/Localizations/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/Localizations/zh-Hant.lproj/Localizable.strings b/ios/Localizations/zh-Hant.lproj/Localizable.strings deleted file mode 100644 index f40aa19b9a..0000000000 --- a/ios/Localizations/zh-Hant.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - MullvadVPN - - Created by Mojgan on 2025-07-16. - Copyright © 2025 Mullvad VPN AB. All rights reserved. -*/ diff --git a/ios/MullvadSettings/CustomListRepository.swift b/ios/MullvadSettings/CustomListRepository.swift index 8ec36c6f50..5697e3ebf1 100644 --- a/ios/MullvadSettings/CustomListRepository.swift +++ b/ios/MullvadSettings/CustomListRepository.swift @@ -18,20 +18,10 @@ public enum CustomRelayListError: LocalizedError, Hashable { public var errorDescription: String? { switch self { case .duplicateName: - NSLocalizedString( - "DUPLICATE_CUSTOM_LISTS_ERROR", - tableName: "CustomLists", - value: "A custom list with this name exists, please choose a unique name.", - comment: "" - ) + NSLocalizedString("A custom list with this name exists, please choose a unique name.", comment: "") case .nameTooLong: String( - format: NSLocalizedString( - "CUSTOM_LIST_NAME_TOO_LONG_ERROR", - tableName: "CustomLists", - value: "Name should be no longer than %i characters.", - comment: "" - ), + format: NSLocalizedString("Name should be no longer than %i characters.", comment: ""), NameInputFormatter.maxLength ) } diff --git a/ios/MullvadSettings/WireGuardObfuscationSettings.swift b/ios/MullvadSettings/WireGuardObfuscationSettings.swift index b32175030f..9c2f29a7a4 100644 --- a/ios/MullvadSettings/WireGuardObfuscationSettings.swift +++ b/ios/MullvadSettings/WireGuardObfuscationSettings.swift @@ -80,12 +80,7 @@ public enum WireGuardObfuscationUdpOverTcpPort: Codable, Equatable, CustomString public var description: String { switch self { case .automatic: - NSLocalizedString( - "WIREGUARD_OBFUSCATION_UDP_TCP_PORT_AUTOMATIC", - tableName: "VPNSettings", - value: "Automatic", - comment: "" - ) + NSLocalizedString("Automatic", comment: "") case .port80: "80" case .port5001: @@ -110,12 +105,7 @@ public enum WireGuardObfuscationShadowsocksPort: Codable, Equatable, CustomStrin public var description: String { switch self { case .automatic: - NSLocalizedString( - "WIREGUARD_OBFUSCATION_SHADOWSOCKS_PORT_AUTOMATIC", - tableName: "VPNSettings", - value: "Automatic", - comment: "" - ) + NSLocalizedString("Automatic", comment: "") case let .custom(port): String(port) } diff --git a/ios/MullvadTypes/AccessMethodKind.swift b/ios/MullvadTypes/AccessMethodKind.swift index 6d4482acb6..9b6ef37696 100644 --- a/ios/MullvadTypes/AccessMethodKind.swift +++ b/ios/MullvadTypes/AccessMethodKind.swift @@ -48,9 +48,9 @@ public extension AccessMethodKind { case .direct, .bridges, .encryptedDNS: "" case .shadowsocks: - NSLocalizedString("SHADOWSOCKS", tableName: "APIAccess", value: "Shadowsocks", comment: "") + NSLocalizedString("Shadowsocks", comment: "") case .socks5: - NSLocalizedString("SOCKS_V5", tableName: "APIAccess", value: "Socks5", comment: "").uppercased() + NSLocalizedString("Socks5", comment: "").uppercased() } } diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 3a91d75af9..35ebd1315f 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -961,6 +961,7 @@ F041BE532C9878B60083EC28 /* ConnectionConfigurationBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F041BE522C9878B60083EC28 /* ConnectionConfigurationBuilder.swift */; }; F04413612BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */; }; F04413622BA45CE30018A6EE /* CustomListLocationNodeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */; }; + F04789ED2E3A4FEB0011E3A5 /* ApplicationLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04789EB2E3A4FEB0011E3A5 /* ApplicationLanguage.swift */; }; F048BFA22D31843000251CB9 /* ChangeLogModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F048BFA12D31842B00251CB9 /* ChangeLogModel.swift */; }; F04AF92D2C466013004A8314 /* EphemeralPeerNegotiationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04AF92C2C466013004A8314 /* EphemeralPeerNegotiationState.swift */; }; F04FBE612A8379EE009278D7 /* AppPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04FBE602A8379EE009278D7 /* AppPreferences.swift */; }; @@ -980,16 +981,6 @@ F05769BB2C6661EE00D9778B /* TunnelSettingsStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05769BA2C6661EE00D9778B /* TunnelSettingsStrategy.swift */; }; F05919752C45194B00C301F3 /* EphemeralPeerKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919742C45194B00C301F3 /* EphemeralPeerKey.swift */; }; F05919802C45515200C301F3 /* EphemeralPeerExchangeActor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A948809A2BC9308D0090A44C /* EphemeralPeerExchangeActor.swift */; }; - F05DCE9E2E38C563009A9B85 /* AppLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05DCE872E38C563009A9B85 /* AppLanguage.swift */; }; - F05DCE9F2E38C563009A9B85 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F05DCE9C2E38C563009A9B85 /* Localizable.strings */; }; - F05DCEA02E38C5F1009A9B85 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F05DCE9C2E38C563009A9B85 /* Localizable.strings */; }; - F05DCEA12E38C5F1009A9B85 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F05DCE9C2E38C563009A9B85 /* Localizable.strings */; }; - F05DCEA22E38C5F1009A9B85 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F05DCE9C2E38C563009A9B85 /* Localizable.strings */; }; - F05DCEA32E38C5F1009A9B85 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F05DCE9C2E38C563009A9B85 /* Localizable.strings */; }; - F05DCEA42E38C5F1009A9B85 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F05DCE9C2E38C563009A9B85 /* Localizable.strings */; }; - F05DCEA52E38C5F1009A9B85 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F05DCE9C2E38C563009A9B85 /* Localizable.strings */; }; - F05DCEA62E38C5F1009A9B85 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F05DCE9C2E38C563009A9B85 /* Localizable.strings */; }; - F05DCEA72E38C5F1009A9B85 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F05DCE9C2E38C563009A9B85 /* Localizable.strings */; }; F05F39972B21C735006E60A7 /* RelayCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5820675A26E6576800655B05 /* RelayCache.swift */; }; F05F39982B21C73C006E60A7 /* CachedRelays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585DA87626B024A600B8C587 /* CachedRelays.swift */; }; F06045E62B231EB700B2D37A /* URLSessionTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06045E52B231EB700B2D37A /* URLSessionTransport.swift */; }; @@ -1069,6 +1060,7 @@ F0B894F32BF7526700817A42 /* RelaySelector+Wireguard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B894F22BF7526700817A42 /* RelaySelector+Wireguard.swift */; }; F0B894F52BF7528700817A42 /* RelaySelector+Shadowsocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B894F42BF7528700817A42 /* RelaySelector+Shadowsocks.swift */; }; F0BE65372B9F136A005CC385 /* LocationSectionHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0BE65362B9F136A005CC385 /* LocationSectionHeaderFooterView.swift */; }; + F0C1374F2E45EF1F006307BF /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = F0C1374E2E45EF1F006307BF /* Localizable.xcstrings */; }; F0C13FE42C64F7CB00BD087D /* DAITASettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C13FE32C64F7CB00BD087D /* DAITASettings.swift */; }; F0C13FE62C64FB3400BD087D /* TunnelSettingsV6.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C13FE52C64FB3400BD087D /* TunnelSettingsV6.swift */; }; F0C2AEFD2A0BB5CC00986207 /* NotificationProviderIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C2AEFC2A0BB5CC00986207 /* NotificationProviderIdentifier.swift */; }; @@ -2431,6 +2423,7 @@ F041BE4E2C983C2B0083EC28 /* DAITASettingsPromptItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAITASettingsPromptItem.swift; sourceTree = "<group>"; }; F041BE522C9878B60083EC28 /* ConnectionConfigurationBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionConfigurationBuilder.swift; sourceTree = "<group>"; }; F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomListLocationNodeBuilder.swift; sourceTree = "<group>"; }; + F04789EB2E3A4FEB0011E3A5 /* ApplicationLanguage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationLanguage.swift; sourceTree = "<group>"; }; F048BFA12D31842B00251CB9 /* ChangeLogModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeLogModel.swift; sourceTree = "<group>"; }; F04AF92C2C466013004A8314 /* EphemeralPeerNegotiationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerNegotiationState.swift; sourceTree = "<group>"; }; F04DD3D72C130DF600E03E28 /* TunnelSettingsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelSettingsManager.swift; sourceTree = "<group>"; }; @@ -2452,27 +2445,6 @@ F05919782C45402E00C301F3 /* SingleHopEphemeralPeerExchanger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleHopEphemeralPeerExchanger.swift; sourceTree = "<group>"; }; F059197C2C454C9200C301F3 /* MultiHopEphemeralPeerExchanger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiHopEphemeralPeerExchanger.swift; sourceTree = "<group>"; }; F059197E2C454CE000C301F3 /* EphemeralPeerExchangingProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerExchangingProtocol.swift; sourceTree = "<group>"; }; - F05DCE872E38C563009A9B85 /* AppLanguage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLanguage.swift; sourceTree = "<group>"; }; - F05DCE882E38C563009A9B85 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE892E38C563009A9B85 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE8A2E38C563009A9B85 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE8B2E38C563009A9B85 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE8C2E38C563009A9B85 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE8D2E38C563009A9B85 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE8E2E38C563009A9B85 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE8F2E38C563009A9B85 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE902E38C563009A9B85 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE912E38C563009A9B85 /* my */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = my; path = my.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE922E38C563009A9B85 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE932E38C563009A9B85 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE942E38C563009A9B85 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE952E38C563009A9B85 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/Localizable.strings"; sourceTree = "<group>"; }; - F05DCE962E38C563009A9B85 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE972E38C563009A9B85 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE982E38C563009A9B85 /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = th; path = th.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE992E38C563009A9B85 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = "<group>"; }; - F05DCE9A2E38C563009A9B85 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; }; - F05DCE9B2E38C563009A9B85 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; }; F06045E52B231EB700B2D37A /* URLSessionTransport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionTransport.swift; sourceTree = "<group>"; }; F06045E92B23217E00B2D37A /* ShadowsocksTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShadowsocksTransport.swift; sourceTree = "<group>"; }; F06045EB2B2322A500B2D37A /* Jittered.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Jittered.swift; sourceTree = "<group>"; }; @@ -2526,6 +2498,7 @@ F0B894F22BF7526700817A42 /* RelaySelector+Wireguard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RelaySelector+Wireguard.swift"; sourceTree = "<group>"; }; F0B894F42BF7528700817A42 /* RelaySelector+Shadowsocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RelaySelector+Shadowsocks.swift"; sourceTree = "<group>"; }; F0BE65362B9F136A005CC385 /* LocationSectionHeaderFooterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationSectionHeaderFooterView.swift; sourceTree = "<group>"; }; + F0C1374E2E45EF1F006307BF /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; }; F0C13FE32C64F7CB00BD087D /* DAITASettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAITASettings.swift; sourceTree = "<group>"; }; F0C13FE52C64FB3400BD087D /* TunnelSettingsV6.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsV6.swift; sourceTree = "<group>"; }; F0C2AEFC2A0BB5CC00986207 /* NotificationProviderIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationProviderIdentifier.swift; sourceTree = "<group>"; }; @@ -2788,11 +2761,11 @@ 06799ABD28F98E1D00ACD94E /* MullvadREST */ = { isa = PBXGroup; children = ( - 7A2C0E872D82E450003D8048 /* MullvadAPI */, F06045F02B2324DA00B2D37A /* ApiHandlers */, 062B45A228FD4C0F00746E77 /* Assets */, 7AD63A422CDA661B00445268 /* Extensions */, 582FFA82290A84E700895745 /* Info.plist */, + 7A2C0E872D82E450003D8048 /* MullvadAPI */, 06799ABE28F98E1D00ACD94E /* MullvadREST.h */, F0DC779F2B2222D20087F09D /* Relay */, 06FAE67B28F83CA50033DD93 /* REST.swift */, @@ -3717,6 +3690,7 @@ 589A454A28DDF59B00565204 /* Shared */ = { isa = PBXGroup; children = ( + F04789EB2E3A4FEB0011E3A5 /* ApplicationLanguage.swift */, 58BFA5CB22A7CE1F00A6173D /* ApplicationConfiguration.swift */, 58C76A072A33850E00100D75 /* ApplicationTarget.swift */, F0F1EF8C2BE8FF0A00CED01D /* LaunchArguments.swift */, @@ -3949,7 +3923,6 @@ 58F3C0A824A50C0E003E76BE /* Assets */, 58ECD29023F178FD004298B6 /* Configurations */, 584F991F2902CBDD001F858D /* Frameworks */, - F05DCE9D2E38C563009A9B85 /* Localizations */, 01EF6F2D2B6A51B100125696 /* mullvad-api.h */, 8556EB512B9A1C6900D26DD4 /* MullvadApi.swift */, 58D223F4294C8FF00029F5F8 /* MullvadLogging */, @@ -4228,6 +4201,7 @@ children = ( 5859A55429CD9DD800F66591 /* changes.txt */, 587DCCEE287D84A500CE821E /* countries.geo.json */, + F0C1374E2E45EF1F006307BF /* Localizable.xcstrings */, ); path = Assets; sourceTree = "<group>"; @@ -4691,15 +4665,6 @@ path = PostQuantum; sourceTree = "<group>"; }; - F05DCE9D2E38C563009A9B85 /* Localizations */ = { - isa = PBXGroup; - children = ( - F05DCE872E38C563009A9B85 /* AppLanguage.swift */, - F05DCE9C2E38C563009A9B85 /* Localizable.strings */, - ); - path = Localizations; - sourceTree = "<group>"; - }; F06045F02B2324DA00B2D37A /* ApiHandlers */ = { isa = PBXGroup; children = ( @@ -5616,9 +5581,9 @@ "zh-Hant", ru, pl, - tr, fi, my, + tr, ); mainGroup = 58CE5E57224146200008646E; packageReferences = ( @@ -5658,7 +5623,6 @@ buildActionMask = 2147483647; files = ( 062B45A328FD4CA700746E77 /* le_root_cert.cer in Resources */, - F05DCEA22E38C5F1009A9B85 /* Localizable.strings in Resources */, 7A95B67B2D5F758300687524 /* relays.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -5681,7 +5645,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - F05DCEA52E38C5F1009A9B85 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5699,9 +5662,9 @@ A9BA08312BA32FA9005A7A2D /* PrivacyInfo.xcprivacy in Resources */, 7A83C3FF2A55B72E00DFB83A /* MullvadVPNApp.xctestplan in Resources */, 58727283265D173C00F315B2 /* LaunchScreen.storyboard in Resources */, - F05DCE9F2E38C563009A9B85 /* Localizable.strings in Resources */, 5859A55529CD9DD900F66591 /* changes.txt in Resources */, 587DCCEF287D84A500CE821E /* countries.geo.json in Resources */, + F0C1374F2E45EF1F006307BF /* Localizable.xcstrings in Resources */, 58CE5E6B224146210008646E /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -5711,7 +5674,6 @@ buildActionMask = 2147483647; files = ( A9BA08322BA32FB6005A7A2D /* PrivacyInfo.xcprivacy in Resources */, - F05DCEA02E38C5F1009A9B85 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5719,7 +5681,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - F05DCEA12E38C5F1009A9B85 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5727,7 +5688,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - F05DCEA32E38C5F1009A9B85 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5735,7 +5695,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - F05DCEA42E38C5F1009A9B85 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5750,7 +5709,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - F05DCEA62E38C5F1009A9B85 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5786,7 +5744,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - F05DCEA72E38C5F1009A9B85 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6410,6 +6367,7 @@ 7A8A190A2CE5FFE9000BCB5B /* SettingsDAITAView.swift in Sources */, F0E8E4C92A604E7400ED26A3 /* AccountDeletionInteractor.swift in Sources */, 449E9A6D2D283A2500F8574A /* ConnectionViewComponentPreview.swift in Sources */, + F04789ED2E3A4FEB0011E3A5 /* ApplicationLanguage.swift in Sources */, 7A5869952B32E9C700640D27 /* LinkButton.swift in Sources */, F09A297D2A9F8A9B00EA3B6F /* RedeemVoucherContentView.swift in Sources */, 5803B4B02940A47300C23744 /* TunnelConfiguration.swift in Sources */, @@ -6524,7 +6482,6 @@ F91CCBFA2DFAC8ED007F1925 /* DeviceListView.swift in Sources */, 7A9CCCBF2A96302800DD6A34 /* SettingsCoordinator.swift in Sources */, 58F70FE52AEA707800E6890E /* StoreTransactionLog.swift in Sources */, - F05DCE9E2E38C563009A9B85 /* AppLanguage.swift in Sources */, F9394EF02DC0B58D009595EA /* MullvadListNavigationItemView.swift in Sources */, 582AE3102440A6CA00E6733A /* InputTextFormatter.swift in Sources */, 7A6F2FAD2AFD3DA7006D0856 /* CustomDNSViewController.swift in Sources */, @@ -7330,36 +7287,6 @@ }; /* End PBXTargetDependency section */ -/* Begin PBXVariantGroup section */ - F05DCE9C2E38C563009A9B85 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - F05DCE882E38C563009A9B85 /* da */, - F05DCE892E38C563009A9B85 /* de */, - F05DCE8A2E38C563009A9B85 /* en */, - F05DCE8B2E38C563009A9B85 /* es */, - F05DCE8C2E38C563009A9B85 /* fi */, - F05DCE8D2E38C563009A9B85 /* fr */, - F05DCE8E2E38C563009A9B85 /* it */, - F05DCE8F2E38C563009A9B85 /* ja */, - F05DCE902E38C563009A9B85 /* ko */, - F05DCE912E38C563009A9B85 /* my */, - F05DCE922E38C563009A9B85 /* nb */, - F05DCE932E38C563009A9B85 /* nl */, - F05DCE942E38C563009A9B85 /* pl */, - F05DCE952E38C563009A9B85 /* pt-PT */, - F05DCE962E38C563009A9B85 /* ru */, - F05DCE972E38C563009A9B85 /* sv */, - F05DCE982E38C563009A9B85 /* th */, - F05DCE992E38C563009A9B85 /* tr */, - F05DCE9A2E38C563009A9B85 /* zh-Hans */, - F05DCE9B2E38C563009A9B85 /* zh-Hant */, - ); - name = Localizable.strings; - sourceTree = "<group>"; - }; -/* End PBXVariantGroup section */ - /* Begin XCBuildConfiguration section */ 06799AD428F98E1D00ACD94E /* Debug */ = { isa = XCBuildConfiguration; @@ -7771,6 +7698,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; SWIFT_VERSION = 6.0; @@ -7832,6 +7760,7 @@ ONLY_ACTIVE_ARCH = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; SWIFT_VERSION = 6.0; @@ -8483,6 +8412,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; SWIFT_VERSION = 6.0; @@ -9338,6 +9268,7 @@ MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; SWIFT_VERSION = 6.0; diff --git a/ios/MullvadVPN/Classes/CustomDateComponentsFormatting.swift b/ios/MullvadVPN/Classes/CustomDateComponentsFormatting.swift index 763fe4b0dd..d9aa29d59d 100644 --- a/ios/MullvadVPN/Classes/CustomDateComponentsFormatting.swift +++ b/ios/MullvadVPN/Classes/CustomDateComponentsFormatting.swift @@ -28,11 +28,7 @@ extension CustomDateComponentsFormatting { let dateComponents = calendar.dateComponents([.year, .day], from: start, to: max(start, end)) guard !isLessThanOneDay(dateComponents: dateComponents) else { - return NSLocalizedString( - "CUSTOM_DATE_COMPONENTS_FORMATTING_LESS_THAN_ONE_DAY", - value: "Less than a day", - comment: "" - ) + return NSLocalizedString("Less than a day", comment: "") } let formatter = DateComponentsFormatter() diff --git a/ios/MullvadVPN/Containers/Root/HeaderBarView.swift b/ios/MullvadVPN/Containers/Root/HeaderBarView.swift index 67c0f326b8..87e59d4dee 100644 --- a/ios/MullvadVPN/Containers/Root/HeaderBarView.swift +++ b/ios/MullvadVPN/Containers/Root/HeaderBarView.swift @@ -64,12 +64,7 @@ class HeaderBarView: UIView { let accountButton: UIButton = { let button = makeHeaderBarButton(with: UIImage.Buttons.account) button.setAccessibilityIdentifier(.accountButton) - button.accessibilityLabel = NSLocalizedString( - "HEADER_BAR_ACCOUNT_BUTTON_ACCESSIBILITY_LABEL", - tableName: "HeaderBar", - value: "Account", - comment: "" - ) + button.accessibilityLabel = NSLocalizedString("Account", comment: "") button.heightAnchor.constraint(equalToConstant: UIMetrics.Button.barButtonSize).isActive = true button.widthAnchor.constraint(equalTo: button.heightAnchor, multiplier: 1).isActive = true return button @@ -78,12 +73,7 @@ class HeaderBarView: UIView { let settingsButton: UIButton = { let button = makeHeaderBarButton(with: UIImage.Buttons.settings) button.setAccessibilityIdentifier(.settingsButton) - button.accessibilityLabel = NSLocalizedString( - "HEADER_BAR_SETTINGS_BUTTON_ACCESSIBILITY_LABEL", - tableName: "HeaderBar", - value: "Settings", - comment: "" - ) + button.accessibilityLabel = NSLocalizedString("Settings", comment: "") button.heightAnchor.constraint(equalToConstant: UIMetrics.Button.barButtonSize).isActive = true button.widthAnchor.constraint(equalTo: button.heightAnchor, multiplier: 1).isActive = true return button @@ -123,12 +113,7 @@ class HeaderBarView: UIView { private var timeLeft: Date? { didSet { if let timeLeft { - let formattedTimeLeft = NSLocalizedString( - "TIME_LEFT_HEADER_VIEW", - tableName: "Account", - value: "Time left: %@", - comment: "" - ) + let formattedTimeLeft = NSLocalizedString("Time left: %@", comment: "") timeLeftLabel.text = String( format: formattedTimeLeft, CustomDateComponentsFormatting.localizedString( @@ -146,12 +131,7 @@ class HeaderBarView: UIView { private var deviceName: String? { didSet { if let deviceName { - let formattedDeviceName = NSLocalizedString( - "DEVICE_NAME_HEADER_VIEW", - tableName: "Account", - value: "Device name: %@", - comment: "" - ) + let formattedDeviceName = NSLocalizedString("Device name: %@", comment: "") deviceNameLabel.text = String(format: formattedDeviceName, deviceName) } else { deviceNameLabel.text = "" diff --git a/ios/MullvadVPN/Coordinators/AccountCoordinator.swift b/ios/MullvadVPN/Coordinators/AccountCoordinator.swift index d3756aaf11..9e5e1aa9eb 100644 --- a/ios/MullvadVPN/Coordinators/AccountCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/AccountCoordinator.swift @@ -146,12 +146,7 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting, @unchecked } ) ) - controller.title = NSLocalizedString( - "MANAGE_DEVICES_TITLE", - tableName: "DeviceManagement", - value: "Manage devices", - comment: "" - ) + controller.title = NSLocalizedString("Manage devices", comment: "") let doneButton = UIBarButtonItem( systemItem: .done, primaryAction: UIAction(handler: { _ in @@ -172,12 +167,7 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting, @unchecked message: message, buttons: [ AlertAction( - title: NSLocalizedString( - "ERROR_ALERT_OK_ACTION", - tableName: "Common", - value: "Got it!", - comment: "" - ), + title: NSLocalizedString("Got it!", comment: ""), style: .default ), ] @@ -249,9 +239,7 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting, @unchecked private func showRestorePurchasesInfo() { let message = NSLocalizedString( - "RESTORE_PURCHASES_DIALOG_MESSAGE", - tableName: "Account", - value: """ + """ You can use the "restore purchases" function to check for any in-app payments \ made via Apple services. If there is a payment that has not been credited, it will \ add the time to the currently logged in Mullvad account. @@ -262,20 +250,10 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting, @unchecked let presentation = AlertPresentation( id: "account-device-info-alert", icon: .info, - title: NSLocalizedString( - "RESTORE_PURCHASES_DIALOG_TITLE", - tableName: "Account", - value: "If you haven’t received additional VPN time after purchasing", - comment: "" - ), + title: NSLocalizedString("If you haven’t received additional VPN time after purchasing", comment: ""), message: message, buttons: [AlertAction( - title: NSLocalizedString( - "RESTORE_PURCHASES_DIALOG_OK_ACTION", - tableName: "Account", - value: "Got it!", - comment: "" - ), + title: NSLocalizedString("Got it!", comment: ""), style: .default )] ) @@ -286,9 +264,6 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting, @unchecked func showFailToFetchProducts() { let message = NSLocalizedString( - "WELCOME_FAILED_TO_FETCH_PRODUCTS_DIALOG", - tableName: "Welcome", - value: """ Failed to connect to App store, please try again later. """, @@ -301,12 +276,7 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting, @unchecked message: message, buttons: [ AlertAction( - title: NSLocalizedString( - "WELCOME_FAILED_TO_FETCH_PRODUCTS_OK_ACTION", - tableName: "Welcome", - value: "Got it!", - comment: "" - ), + title: NSLocalizedString("Got it!", comment: ""), style: .default ), ] diff --git a/ios/MullvadVPN/Coordinators/ChangeLogCoordinator.swift b/ios/MullvadVPN/Coordinators/ChangeLogCoordinator.swift index 534adad344..7e56893c16 100644 --- a/ios/MullvadVPN/Coordinators/ChangeLogCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/ChangeLogCoordinator.swift @@ -34,22 +34,12 @@ final class ChangeLogCoordinator: Coordinator, Presentable, SettingsChildCoordin func start(animated: Bool) { let changeLogViewController = UIHostingController(rootView: ChangeLogView(viewModel: viewModel)) changeLogViewController.view.setAccessibilityIdentifier(.changeLogAlert) - changeLogViewController.navigationItem.title = NSLocalizedString( - "whats_new_title", - tableName: "Changelog", - value: "What's new", - comment: "" - ) + changeLogViewController.navigationItem.title = NSLocalizedString("What's new", comment: "") switch route { case .changelog: let barButtonItem = UIBarButtonItem( - title: NSLocalizedString( - "CHANGELOG_NAVIGATION_DONE_BUTTON", - tableName: "Changelog", - value: "Done", - comment: "" - ), + title: NSLocalizedString("Done", comment: ""), primaryAction: UIAction { [weak self] _ in guard let self else { return } didFinish?(self) diff --git a/ios/MullvadVPN/Coordinators/CustomLists/AddCustomListCoordinator.swift b/ios/MullvadVPN/Coordinators/CustomLists/AddCustomListCoordinator.swift index c73d6e408d..b11bbda73d 100644 --- a/ios/MullvadVPN/Coordinators/CustomLists/AddCustomListCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/CustomLists/AddCustomListCoordinator.swift @@ -43,19 +43,9 @@ class AddCustomListCoordinator: Coordinator, Presentable, Presenting { ) controller.delegate = self - controller.navigationItem.title = NSLocalizedString( - "CUSTOM_LISTS_NAVIGATION_EDIT_TITLE", - tableName: "CustomLists", - value: "New custom list", - comment: "" - ) + controller.navigationItem.title = NSLocalizedString("New custom list", comment: "") - controller.saveBarButton.title = NSLocalizedString( - "CUSTOM_LISTS_NAVIGATION_CREATE_BUTTON", - tableName: "CustomLists", - value: "Create", - comment: "" - ) + controller.saveBarButton.title = NSLocalizedString("Create", comment: "") controller.navigationItem.leftBarButtonItem = UIBarButtonItem( systemItem: .cancel, diff --git a/ios/MullvadVPN/Coordinators/CustomLists/AddLocationsCoordinator.swift b/ios/MullvadVPN/Coordinators/CustomLists/AddLocationsCoordinator.swift index 14ad4a9ab5..018dc9257b 100644 --- a/ios/MullvadVPN/Coordinators/CustomLists/AddLocationsCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/CustomLists/AddLocationsCoordinator.swift @@ -40,12 +40,7 @@ class AddLocationsCoordinator: Coordinator, Presentable, Presenting { ) controller.delegate = self - controller.navigationItem.title = NSLocalizedString( - "ADD_LOCATIONS_NAVIGATION_TITLE", - tableName: "AddLocations", - value: "Add locations", - comment: "" - ) + controller.navigationItem.title = NSLocalizedString("Add locations", comment: "") navigationController.pushViewController(controller, animated: true) } diff --git a/ios/MullvadVPN/Coordinators/CustomLists/CustomListItemIdentifier.swift b/ios/MullvadVPN/Coordinators/CustomLists/CustomListItemIdentifier.swift index f5b4b28664..37a479681f 100644 --- a/ios/MullvadVPN/Coordinators/CustomLists/CustomListItemIdentifier.swift +++ b/ios/MullvadVPN/Coordinators/CustomLists/CustomListItemIdentifier.swift @@ -40,13 +40,13 @@ enum CustomListItemIdentifier: Hashable, CaseIterable { var text: String? { switch self { case .name: - NSLocalizedString("NAME", tableName: "CustomLists", value: "Name", comment: "") + NSLocalizedString("Name", comment: "") case .addLocations: - NSLocalizedString("ADD", tableName: "CustomLists", value: "Add locations", comment: "") + NSLocalizedString("Add locations", comment: "") case .editLocations: - NSLocalizedString("EDIT", tableName: "CustomLists", value: "Edit locations", comment: "") + NSLocalizedString("Edit locations", comment: "") case .deleteList: - NSLocalizedString("Delete", tableName: "CustomLists", value: "Delete list", comment: "") + NSLocalizedString("Delete list", comment: "") } } diff --git a/ios/MullvadVPN/Coordinators/CustomLists/CustomListViewController.swift b/ios/MullvadVPN/Coordinators/CustomLists/CustomListViewController.swift index ab415b9091..6fd41488d5 100644 --- a/ios/MullvadVPN/Coordinators/CustomLists/CustomListViewController.swift +++ b/ios/MullvadVPN/Coordinators/CustomLists/CustomListViewController.swift @@ -47,12 +47,7 @@ class CustomListViewController: UIViewController { lazy var saveBarButton: UIBarButtonItem = { let barButtonItem = UIBarButtonItem( - title: NSLocalizedString( - "CUSTOM_LIST_NAVIGATION_SAVE_BUTTON", - tableName: "CustomLists", - value: "Save", - comment: "" - ), + title: NSLocalizedString("Save", comment: ""), primaryAction: UIAction { [weak self] _ in self?.onSave() } @@ -163,12 +158,7 @@ class CustomListViewController: UIViewController { private func onDelete() { let message = NSMutableAttributedString( - markdownString: NSLocalizedString( - "CUSTOM_LISTS_DELETE_PROMPT", - tableName: "CustomLists", - value: "Do you want to delete the list **\(subject.value.name)**?", - comment: "" - ), + markdownString: NSLocalizedString("Do you want to delete the list **\(subject.value.name)**?", comment: ""), options: MarkdownStylingOptions(font: .preferredFont(forTextStyle: .body)) ) @@ -178,12 +168,7 @@ class CustomListViewController: UIViewController { attributedMessage: message, buttons: [ AlertAction( - title: NSLocalizedString( - "CUSTOM_LISTS_DELETE_BUTTON", - tableName: "CustomLists", - value: "Delete list", - comment: "" - ), + title: NSLocalizedString("Delete list", comment: ""), style: .destructive, accessibilityId: .confirmDeleteCustomListButton, handler: { @@ -192,12 +177,7 @@ class CustomListViewController: UIViewController { } ), AlertAction( - title: NSLocalizedString( - "CUSTOM_LISTS_CANCEL_BUTTON", - tableName: "CustomLists", - value: "Cancel", - comment: "" - ), + title: NSLocalizedString("Cancel", comment: ""), style: .default, accessibilityId: .cancelDeleteCustomListButton ), diff --git a/ios/MullvadVPN/Coordinators/CustomLists/EditCustomListCoordinator.swift b/ios/MullvadVPN/Coordinators/CustomLists/EditCustomListCoordinator.swift index 42666c160e..51579b34aa 100644 --- a/ios/MullvadVPN/Coordinators/CustomLists/EditCustomListCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/CustomLists/EditCustomListCoordinator.swift @@ -58,12 +58,7 @@ class EditCustomListCoordinator: Coordinator, Presentable, Presenting { ) controller.delegate = self - controller.navigationItem.title = NSLocalizedString( - "CUSTOM_LIST_NAVIGATION_TITLE", - tableName: "CustomLists", - value: subject.value.name, - comment: "" - ) + controller.navigationItem.title = subject.value.name navigationController.interactivePopGestureRecognizer?.delegate = self navigationController.pushViewController(controller, animated: true) @@ -97,12 +92,7 @@ class EditCustomListCoordinator: Coordinator, Presentable, Presenting { private func presentUnsavedChangesDialog() { let message = NSMutableAttributedString( - markdownString: NSLocalizedString( - "CUSTOM_LISTS_UNSAVED_CHANGES_PROMPT", - tableName: "CustomLists", - value: "You have unsaved changes.", - comment: "" - ), + markdownString: NSLocalizedString("You have unsaved changes.", comment: ""), options: MarkdownStylingOptions(font: .preferredFont(forTextStyle: .body)) ) @@ -112,24 +102,14 @@ class EditCustomListCoordinator: Coordinator, Presentable, Presenting { attributedMessage: message, buttons: [ AlertAction( - title: NSLocalizedString( - "CUSTOM_LISTS_DISCARD_CHANGES_BUTTON", - tableName: "CustomLists", - value: "Discard changes", - comment: "" - ), + title: NSLocalizedString("Discard changes", comment: ""), style: .destructive, handler: { self.didCancel?(self) } ), AlertAction( - title: NSLocalizedString( - "CUSTOM_LISTS_BACK_TO_EDITING_BUTTON", - tableName: "CustomLists", - value: "Back to editing", - comment: "" - ), + title: NSLocalizedString("Back to editing", comment: ""), style: .default ), ] diff --git a/ios/MullvadVPN/Coordinators/CustomLists/EditLocationsCoordinator.swift b/ios/MullvadVPN/Coordinators/CustomLists/EditLocationsCoordinator.swift index e1ac172e93..4b426ff377 100644 --- a/ios/MullvadVPN/Coordinators/CustomLists/EditLocationsCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/CustomLists/EditLocationsCoordinator.swift @@ -41,12 +41,7 @@ class EditLocationsCoordinator: Coordinator, Presentable, Presenting { ) controller.delegate = self - controller.navigationItem.title = NSLocalizedString( - "EDIT_LOCATIONS_NAVIGATION_TITLE", - tableName: "EditLocations", - value: "Edit locations", - comment: "" - ) + controller.navigationItem.title = NSLocalizedString("Edit locations", comment: "") navigationController.pushViewController(controller, animated: true) } } diff --git a/ios/MullvadVPN/Coordinators/CustomLists/ListCustomListViewController.swift b/ios/MullvadVPN/Coordinators/CustomLists/ListCustomListViewController.swift index 1b929f0d04..9bbce28206 100644 --- a/ios/MullvadVPN/Coordinators/CustomLists/ListCustomListViewController.swift +++ b/ios/MullvadVPN/Coordinators/CustomLists/ListCustomListViewController.swift @@ -92,12 +92,7 @@ class ListCustomListViewController: UIViewController { } private func configureNavigationItem() { - navigationItem.title = NSLocalizedString( - "LIST_CUSTOM_LIST_NAVIGATION_TITLE", - tableName: "CustomList", - value: "Edit custom list", - comment: "" - ) + navigationItem.title = NSLocalizedString("Edit custom list", comment: "") navigationItem.rightBarButtonItem = UIBarButtonItem( systemItem: .done, diff --git a/ios/MullvadVPN/Coordinators/LocationCoordinator.swift b/ios/MullvadVPN/Coordinators/LocationCoordinator.swift index e482940672..a794273297 100644 --- a/ios/MullvadVPN/Coordinators/LocationCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/LocationCoordinator.swift @@ -181,9 +181,7 @@ extension LocationCoordinator: @preconcurrency LocationViewControllerWrapperDele func navigateToCustomLists(nodes: [LocationNode]) { let actionSheet = UIAlertController( - title: NSLocalizedString( - "ACTION_SHEET_TITLE", tableName: "CustomLists", value: "Custom lists", comment: "" - ), + title: NSLocalizedString("Custom lists", comment: ""), message: nil, preferredStyle: UIDevice.current.userInterfaceIdiom == .pad ? .alert : .actionSheet ) @@ -191,9 +189,7 @@ extension LocationCoordinator: @preconcurrency LocationViewControllerWrapperDele actionSheet.view.tintColor = .AlertController.tintColor let addCustomListAction = UIAlertAction( - title: NSLocalizedString( - "ACTION_SHEET_ADD_LIST_BUTTON", tableName: "CustomLists", value: "Add new list", comment: "" - ), + title: NSLocalizedString("Add new list", comment: ""), style: .default, handler: { [weak self] _ in self?.showAddCustomList(nodes: nodes) @@ -203,9 +199,7 @@ extension LocationCoordinator: @preconcurrency LocationViewControllerWrapperDele actionSheet.addAction(addCustomListAction) let editAction = UIAlertAction( - title: NSLocalizedString( - "ACTION_SHEET_EDIT_LISTS_BUTTON", tableName: "CustomLists", value: "Edit lists", comment: "" - ), + title: NSLocalizedString("Edit lists", comment: ""), style: .default, handler: { [weak self] _ in self?.showEditCustomLists(nodes: nodes) @@ -216,12 +210,7 @@ extension LocationCoordinator: @preconcurrency LocationViewControllerWrapperDele actionSheet.addAction(editAction) actionSheet.addAction(UIAlertAction( - title: NSLocalizedString( - "CUSTOM_LIST_ACTION_SHEET_CANCEL_BUTTON", - tableName: "CustomLists", - value: "Cancel", - comment: "" - ), + title: NSLocalizedString("Cancel", comment: ""), style: .cancel )) diff --git a/ios/MullvadVPN/Coordinators/LoginCoordinator.swift b/ios/MullvadVPN/Coordinators/LoginCoordinator.swift index 46220d0158..662a094def 100644 --- a/ios/MullvadVPN/Coordinators/LoginCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/LoginCoordinator.swift @@ -126,12 +126,7 @@ final class LoginCoordinator: Coordinator, Presenting { message: errorDescription, buttons: [ AlertAction( - title: NSLocalizedString( - "ERROR_ALERT_OK_ACTION", - tableName: "DeviceManagement", - value: "Got it!", - comment: "" - ), + title: NSLocalizedString("Got it!", comment: ""), style: .default ), ] diff --git a/ios/MullvadVPN/Coordinators/ProfileVoucherCoordinator.swift b/ios/MullvadVPN/Coordinators/ProfileVoucherCoordinator.swift index e3426c59df..a0e8668008 100644 --- a/ios/MullvadVPN/Coordinators/ProfileVoucherCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/ProfileVoucherCoordinator.swift @@ -65,20 +65,10 @@ extension ProfileVoucherCoordinator: @preconcurrency AddCreditSucceededViewContr } func header(in controller: AddCreditSucceededViewController) -> String { - NSLocalizedString( - "REDEEM_VOUCHER_SUCCESS_TITLE", - tableName: "ProfileRedeemVoucher", - value: "Voucher was successfully redeemed.", - comment: "" - ) + NSLocalizedString("Voucher was successfully redeemed.", comment: "") } func titleForAction(in controller: AddCreditSucceededViewController) -> String { - NSLocalizedString( - "REDEEM_VOUCHER_DISMISS_BUTTON", - tableName: "ProfileRedeemVoucher", - value: "Got it!", - comment: "" - ) + NSLocalizedString("Got it!", comment: "") } } diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Add/AddAccessMethodCoordinator.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Add/AddAccessMethodCoordinator.swift index cd456d2fc5..b9ff03a2bf 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Add/AddAccessMethodCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Add/AddAccessMethodCoordinator.swift @@ -52,26 +52,11 @@ class AddAccessMethodCoordinator: Coordinator, Presentable, Presenting { } private func setUpControllerNavigationItem(_ controller: MethodSettingsViewController) { - controller.navigationItem.prompt = NSLocalizedString( - "METHOD_SETTINGS_NAVIGATION_ADD_PROMPT", - tableName: "APIAccess", - value: "The app will test the method before saving.", - comment: "" - ) + controller.navigationItem.prompt = NSLocalizedString("The app will test the method before saving.", comment: "") - controller.navigationItem.title = NSLocalizedString( - "METHOD_SETTINGS_NAVIGATION_ADD_TITLE", - tableName: "APIAccess", - value: "Add access method", - comment: "" - ) + controller.navigationItem.title = NSLocalizedString("Add access method", comment: "") - controller.saveBarButton.title = NSLocalizedString( - "METHOD_SETTINGS_NAVIGATION_ADD_BUTTON", - tableName: "APIAccess", - value: "Add", - comment: "" - ) + controller.saveBarButton.title = NSLocalizedString("Add", comment: "") controller.navigationItem.leftBarButtonItem = UIBarButtonItem( systemItem: .cancel, diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/TextCellContentConfiguration+Extensions.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/TextCellContentConfiguration+Extensions.swift index 75195fb9cc..087ac107f7 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/TextCellContentConfiguration+Extensions.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/TextCellContentConfiguration+Extensions.swift @@ -28,19 +28,9 @@ extension TextCellContentConfiguration { var localizedDescription: String { switch self { case .required: - NSLocalizedString( - "REQUIRED_PLACEHOLDER", - tableName: "APIAccess", - value: "Required", - comment: "" - ) + NSLocalizedString("Required", comment: "") case .optional: - NSLocalizedString( - "OPTIONAL_PLACEHOLDER", - tableName: "APIAccess", - value: "Optional", - comment: "" - ) + NSLocalizedString("Optional", comment: "") } } } diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/ShadowsocksItemIdentifier.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/ShadowsocksItemIdentifier.swift index 604d9d78a0..f9a51245ae 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/ShadowsocksItemIdentifier.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/ShadowsocksItemIdentifier.swift @@ -34,13 +34,13 @@ enum ShadowsocksItemIdentifier: Hashable, CaseIterable { var text: String { switch self { case .server: - NSLocalizedString("SHADOWSOCKS_SERVER", tableName: "APIAccess", value: "Server", comment: "") + NSLocalizedString("Server", comment: "") case .port: - NSLocalizedString("SHADOWSOCKS_PORT", tableName: "APIAccess", value: "Port", comment: "") + NSLocalizedString("Port", comment: "") case .password: - NSLocalizedString("SHADOWSOCKS_PASSWORD", tableName: "APIAccess", value: "Password", comment: "") + NSLocalizedString("Password", comment: "") case .cipher: - NSLocalizedString("SHADOWSOCKS_CIPHER", tableName: "APIAccess", value: "Cipher", comment: "") + NSLocalizedString("Cipher", comment: "") } } } diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksItemIdentifier.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksItemIdentifier.swift index 7c52d88538..7e44d850bc 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksItemIdentifier.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksItemIdentifier.swift @@ -49,15 +49,15 @@ enum SocksItemIdentifier: Hashable, CaseIterable { var text: String { switch self { case .server: - NSLocalizedString("SOCKS_SERVER", tableName: "APIAccess", value: "Server", comment: "") + NSLocalizedString("Server", comment: "") case .port: - NSLocalizedString("SOCKS_PORT", tableName: "APIAccess", value: "Port", comment: "") + NSLocalizedString("Port", comment: "") case .authentication: - NSLocalizedString("SOCKS_AUTHENTICATION", tableName: "APIAccess", value: "Authentication", comment: "") + NSLocalizedString("Authentication", comment: "") case .username: - NSLocalizedString("SOCKS_USERNAME", tableName: "APIAccess", value: "Username", comment: "") + NSLocalizedString("Username", comment: "") case .password: - NSLocalizedString("SOCKS_PASSWORD", tableName: "APIAccess", value: "Password", comment: "") + NSLocalizedString("Password", comment: "") } } } diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodCoordinator.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodCoordinator.swift index 3d249c841a..997c3fd44d 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodCoordinator.swift @@ -74,26 +74,11 @@ extension EditAccessMethodCoordinator: @preconcurrency EditAccessMethodViewContr alertPresenter: AlertPresenter(context: self) ) - controller.navigationItem.prompt = NSLocalizedString( - "METHOD_SETTINGS_NAVIGATION_ADD_PROMPT", - tableName: "APIAccess", - value: "The app will test the method before saving.", - comment: "" - ) + controller.navigationItem.prompt = NSLocalizedString("The app will test the method before saving.", comment: "") - controller.navigationItem.title = NSLocalizedString( - "METHOD_SETTINGS_NAVIGATION_ADD_TITLE", - tableName: "APIAccess", - value: "Method settings", - comment: "" - ) + controller.navigationItem.title = NSLocalizedString("Method settings", comment: "") - controller.saveBarButton.title = NSLocalizedString( - "METHOD_SETTINGS_NAVIGATION_ADD_BUTTON", - tableName: "APIAccess", - value: "Save", - comment: "" - ) + controller.saveBarButton.title = NSLocalizedString("Save", comment: "") controller.delegate = self diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodItemIdentifier.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodItemIdentifier.swift index 82a10899d7..f8cd3205c9 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodItemIdentifier.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodItemIdentifier.swift @@ -54,17 +54,17 @@ enum EditAccessMethodItemIdentifier: Hashable { var text: String? { switch self { case .enableMethod: - NSLocalizedString("ENABLE_METHOD", tableName: "APIAccess", value: "Enable method", comment: "") + NSLocalizedString("Enable method", comment: "") case .methodSettings: - NSLocalizedString("METHOD_SETTINGS", tableName: "APIAccess", value: "Method settings", comment: "") + NSLocalizedString("Method settings", comment: "") case .testMethod: - NSLocalizedString("TEST_METHOD", tableName: "APIAccess", value: "Test method", comment: "") + NSLocalizedString("Test method", comment: "") case .cancelTest: - NSLocalizedString("CANCEL_TEST", tableName: "APIAccess", value: "Cancel", comment: "") + NSLocalizedString("Cancel", comment: "") case .testingStatus: nil case .deleteMethod: - NSLocalizedString("DELETE_METHOD", tableName: "APIAccess", value: "Delete method", comment: "") + NSLocalizedString("Delete method", comment: "") } } } diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodSectionIdentifier.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodSectionIdentifier.swift index be0a05b4d2..b32f81b2b7 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodSectionIdentifier.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodSectionIdentifier.swift @@ -20,19 +20,9 @@ enum EditAccessMethodSectionIdentifier: Hashable { var sectionFooter: String? { switch self { case .testMethod: - NSLocalizedString( - "TEST_METHOD_FOOTER", - tableName: "APIAccess", - value: "Performs a connection test to a Mullvad API server via this access method.", - comment: "" - ) + NSLocalizedString("Performs a connection test to a Mullvad API server via this access method.", comment: "") case .enableMethod: - NSLocalizedString( - "METHOD_FOOTER", - tableName: "APIAccess", - value: "At least one method needs to be enabled.", - comment: "" - ) + NSLocalizedString("At least one method needs to be enabled.", comment: "") case .methodSettings, .cancelTest, .testingStatus, .deleteMethod: nil } diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift index fe9345dc71..42e22e2ef4 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift @@ -379,31 +379,16 @@ extension EditAccessMethodViewController: UITableViewDelegate { private func onDelete() { let methodName = subject.value.name.isEmpty - ? NSLocalizedString( - "METHOD_SETTINGS_SAVE_PROMPT", - tableName: "APIAccess", - value: "method?", - comment: "" - ) + ? NSLocalizedString("method", comment: "") : subject.value.name let presentation = AlertPresentation( id: "api-access-methods-delete-method-alert", icon: .alert, - message: NSLocalizedString( - "METHOD_SETTINGS_DELETE_PROMPT", - tableName: "APIAccess", - value: "Delete \(methodName)?", - comment: "" - ), + message: NSLocalizedString("Delete \(methodName)?", comment: ""), buttons: [ AlertAction( - title: NSLocalizedString( - "METHOD_SETTINGS_DELETE_BUTTON", - tableName: "APIAccess", - value: "Delete", - comment: "" - ), + title: NSLocalizedString("Delete", comment: ""), style: .destructive, accessibilityId: .accessMethodConfirmDeleteButton, handler: { [weak self] in @@ -413,12 +398,7 @@ extension EditAccessMethodViewController: UITableViewDelegate { } ), AlertAction( - title: NSLocalizedString( - "METHOD_SETTINGS_CANCEL_BUTTON", - tableName: "APIAccess", - value: "Cancel", - comment: "" - ), + title: NSLocalizedString("Cancel", comment: ""), style: .default ), ] diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsCellConfiguration.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsCellConfiguration.swift index 089766c09a..c69ccb47fe 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsCellConfiguration.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsCellConfiguration.swift @@ -178,12 +178,7 @@ class MethodSettingsCellConfiguration { var contentConfiguration = MethodTestingStatusCellContentConfiguration() contentConfiguration.status = viewStatus contentConfiguration.detailText = viewStatus == .reachable - ? NSLocalizedString( - "METHOD_SETTINGS_SAVING_CHANGES", - tableName: "APIAccess", - value: "Saving changes...", - comment: "" - ) + ? NSLocalizedString("Saving changes...", comment: "") : nil cell.contentConfiguration = contentConfiguration diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsItemIdentifier.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsItemIdentifier.swift index ed2c6f2c40..74279206c5 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsItemIdentifier.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsItemIdentifier.swift @@ -71,13 +71,13 @@ enum MethodSettingsItemIdentifier: Hashable { var text: String? { switch self { case .name: - NSLocalizedString("NAME", tableName: "APIAccess", value: "Name", comment: "") + NSLocalizedString("Name", comment: "") case .protocol: - NSLocalizedString("TYPE", tableName: "APIAccess", value: "Type", comment: "") + NSLocalizedString("Type", comment: "") case .proxyConfiguration, .validationError: nil case .cancelTest: - NSLocalizedString("CANCEL_TEST", tableName: "APIAccess", value: "Cancel", comment: "") + NSLocalizedString("Cancel", comment: "") case .testingStatus: nil } diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsSectionIdentifier.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsSectionIdentifier.swift index 1c5dfeb90f..71bddcbd72 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsSectionIdentifier.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsSectionIdentifier.swift @@ -21,12 +21,7 @@ enum MethodSettingsSectionIdentifier: Hashable { case .name, .protocol, .validationError, .testingStatus, .cancelTest: nil case .proxyConfiguration: - NSLocalizedString( - "HOST_CONFIG_SECTION_TITLE", - tableName: "APIAccess", - value: "Server details", - comment: "" - ) + NSLocalizedString("Server details", comment: "") } } } diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift index 3a3f285c49..03961f495e 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift @@ -46,7 +46,7 @@ class MethodSettingsViewController: UITableViewController { lazy var saveBarButton: UIBarButtonItem = { let barButtonItem = UIBarButtonItem( - title: NSLocalizedString("SAVE_NAVIGATION_BUTTON", tableName: "APIAccess", value: "Save", comment: ""), + title: NSLocalizedString("Save", comment: ""), primaryAction: UIAction { [weak self] _ in self?.onTest() } @@ -314,20 +314,10 @@ class MethodSettingsViewController: UITableViewController { id: "api-access-methods-testing-status-failed-alert", accessibilityIdentifier: .accessMethodUnreachableAlert, icon: .warning, - message: NSLocalizedString( - "METHOD_SETTINGS_SAVE_PROMPT", - tableName: "APIAccess", - value: "API could not be reached, save anyway?", - comment: "" - ), + message: NSLocalizedString("API could not be reached, save anyway?", comment: ""), buttons: [ AlertAction( - title: NSLocalizedString( - "METHOD_SETTINGS_SAVE_BUTTON", - tableName: "APIAccess", - value: "Save anyway", - comment: "" - ), + title: NSLocalizedString("Save anyway", comment: ""), style: .default, accessibilityId: .accessMethodUnreachableSaveButton, handler: { [weak self] in @@ -335,12 +325,7 @@ class MethodSettingsViewController: UITableViewController { } ), AlertAction( - title: NSLocalizedString( - "METHOD_SETTINGS_BACK_BUTTON", - tableName: "APIAccess", - value: "Back to editing", - comment: "" - ), + title: NSLocalizedString("Back to editing", comment: ""), style: .default, accessibilityId: .accessMethodUnreachableBackButton ), diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodTestingStatusCellContentConfiguration.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodTestingStatusCellContentConfiguration.swift index e62cdadcd2..eec8b2d2bb 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodTestingStatusCellContentConfiguration.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodTestingStatusCellContentConfiguration.swift @@ -45,11 +45,11 @@ extension MethodTestingStatusCellContentConfiguration.Status { var text: String { switch self { case .unreachable: - NSLocalizedString("API_UNREACHABLE", tableName: "APIAccess", value: "API unreachable", comment: "") + NSLocalizedString("API unreachable", comment: "") case .reachable: - NSLocalizedString("API_REACHABLE", tableName: "APIAccess", value: "API reachable", comment: "") + NSLocalizedString("API reachable", comment: "") case .testing: - NSLocalizedString("API_TESTING_INPROGRESS", tableName: "APIAccess", value: "Testing...", comment: "") + NSLocalizedString("Testing...", comment: "") } } diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodCoordinator.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodCoordinator.swift index 804f9b0e34..e6f8319a73 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodCoordinator.swift @@ -37,12 +37,7 @@ class ListAccessMethodCoordinator: Coordinator, Presenting, SettingsChildCoordin ), delegate: self) ) let host = UIHostingController(rootView: view) - host.title = NSLocalizedString( - "NAVIGATION_TITLE", - tableName: "Settings", - value: "API access", - comment: "" - ) + host.title = NSLocalizedString("API access", comment: "") host.view.setAccessibilityIdentifier(.apiAccessView) navigationController.pushViewController(host, animated: animated) @@ -87,41 +82,28 @@ class ListAccessMethodCoordinator: Coordinator, Presenting, SettingsChildCoordin } private func about() { - let header = NSLocalizedString( - "ABOUT_API_ACCESS_HEADER", - tableName: "APIAccess", - value: "API access", - comment: "" - ) + let header = NSLocalizedString("API access", comment: "") let preamble = NSLocalizedString( - "ABOUT_API_ACCESS_PREAMBLE", - tableName: "APIAccess", - value: "Manage default and setup custom methods to access the Mullvad API.", + "Manage default and setup custom methods to access the Mullvad API.", comment: "" ) let body = [ NSLocalizedString( - "ABOUT_API_ACCESS_BODY_1", - tableName: "APIAccess", - value: """ + """ The app needs to communicate with a Mullvad API server to log you in, fetch server lists, \ and other critical operations. """, comment: "" ), NSLocalizedString( - "ABOUT_API_ACCESS_BODY_2", - tableName: "APIAccess", - value: """ + """ On some networks, where various types of censorship are being used, the API servers might \ not be directly reachable. """, comment: "" ), NSLocalizedString( - "ABOUT_API_ACCESS_BODY_3", - tableName: "APIAccess", - value: """ + """ This feature allows you to circumvent that censorship by adding custom ways to access the \ API via proxies and similar methods. """, diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodView.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodView.swift index cdc7389bef..f9786daa3f 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodView.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodView.swift @@ -29,17 +29,10 @@ struct ListAccessMethodView<ViewModel>: View where ViewModel: ListAccessViewMode var body: some View { VStack(alignment: .leading, spacing: 0) { let text = NSLocalizedString( - "ACCESS_METHOD_HEADER_BODY", - tableName: "APIAccess", - value: "Manage default and setup custom methods to access the Mullvad API. ", - comment: "" - ) - let about = NSLocalizedString( - "ACCESS_METHOD_HEADER_BODY", - tableName: "APIAccess", - value: "About API access…", + "Manage default and setup custom methods to access the Mullvad API. ", comment: "" ) + let about = NSLocalizedString("About API access…", comment: "") MullvadList(viewModel.items, header: { MullvadInfoHeaderView( @@ -68,20 +61,10 @@ struct ListAccessMethodView<ViewModel>: View where ViewModel: ListAccessViewMode nil } let state = viewModel.itemInUse?.id == item.id - ? NSLocalizedString( - "LIST_ACCESS_METHODS_IN_USE_ITEM", - tableName: "APIAccess", - value: "In use", - comment: "" - ) + ? NSLocalizedString("In use", comment: "") : ( !item.isEnabled - ? NSLocalizedString( - "LIST_ACCESS_METHODS_DISABLED", - tableName: "APIAccess", - value: "Disabled", - comment: "" - ) + ? NSLocalizedString("Disabled", comment: "") : nil ) MullvadListNavigationItemView( diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodValidationError.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodValidationError.swift index e050cb96a0..fa4c9f8513 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodValidationError.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodValidationError.swift @@ -16,12 +16,7 @@ struct AccessMethodValidationError: LocalizedError, Equatable { var errorDescription: String? { if fieldErrors.count > 1 { - NSLocalizedString( - "VALIDATION_ERRORS_MULTIPLE", - tableName: "APIAccess", - value: "Multiple validation errors occurred.", - comment: "" - ) + NSLocalizedString("Multiple validation errors occurred.", comment: "") } else { fieldErrors.first?.localizedDescription } @@ -75,34 +70,14 @@ struct AccessMethodFieldValidationError: LocalizedError, Equatable { var errorDescription: String? { switch kind { case .emptyValue: - NSLocalizedString( - "VALIDATION_ERRORS_EMPTY_FIELD", - tableName: "APIAccess", - value: "\(field) cannot be empty.", - comment: "" - ) + NSLocalizedString("\(field) cannot be empty.", comment: "") case .invalidIPAddress: - NSLocalizedString( - "VALIDATION_ERRORS_INVALD ADDRESS", - tableName: "APIAccess", - value: "Please enter a valid IPv4 or IPv6 address.", - comment: "" - ) + NSLocalizedString("Please enter a valid IPv4 or IPv6 address.", comment: "") case .invalidPort: - NSLocalizedString( - "VALIDATION_ERRORS_INVALID_PORT", - tableName: "APIAccess", - value: "Please enter a valid port.", - comment: "" - ) + NSLocalizedString("Please enter a valid port.", comment: "") case .nameTooLong: String( - format: NSLocalizedString( - "VALIDATION_ERRORS_NAME_TOO_LONG", - tableName: "APIAccess", - value: "Name should be no longer than %i characters.", - comment: "" - ), + format: NSLocalizedString("Name should be no longer than %i characters.", comment: ""), NameInputFormatter.maxLength ) } diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel.swift index 56a31ce75d..a9797fac7f 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel.swift @@ -81,48 +81,24 @@ extension AccessMethodViewModel { switch id { case AccessMethodRepository.directId: InfoHeaderConfig( - body: NSLocalizedString( - "DIRECT_ACCESS_METHOD_HEADER_BODY", - tableName: "APIAccess", - value: "The app communicates with a Mullvad API server directly.", - comment: "" - ), - link: NSLocalizedString( - "DIRECT_ACCESS_METHOD_HEADER_LINK", - tableName: "APIAccess", - value: "About Direct method...", - comment: "" - ) + body: NSLocalizedString("The app communicates with a Mullvad API server directly.", comment: ""), + link: NSLocalizedString("About Direct method...", comment: "") ) case AccessMethodRepository.bridgeId: InfoHeaderConfig( body: NSLocalizedString( - "BRIDGES_ACCESS_METHOD_HEADER_BODY", - tableName: "APIAccess", - value: "The app communicates with a Mullvad API server via a Mullvad bridge server.", + "The app communicates with a Mullvad API server via a Mullvad bridge server.", comment: "" ), - link: NSLocalizedString( - "BRIDGES_ACCESS_METHOD_HEADER_LINK", - tableName: "APIAccess", - value: "About Mullvad bridges method...", - comment: "" - ) + link: NSLocalizedString("About Mullvad bridges method...", comment: "") ) case AccessMethodRepository.encryptedDNSId: InfoHeaderConfig( body: NSLocalizedString( - "ENCRYPTED_DNS_ACCESS_METHOD_HEADER_BODY", - tableName: "APIAccess", - value: "The app communicates with a Mullvad API server via a proxy address.", + "The app communicates with a Mullvad API server via a proxy address.", comment: "" ), - link: NSLocalizedString( - "ENCRYPTED_DNS_ACCESS_METHOD_HEADER_LINK", - tableName: "APIAccess", - value: "About Encrypted DNS proxy method...", - comment: "" - ) + link: NSLocalizedString("About Encrypted DNS proxy method...", comment: "") ) default: nil @@ -133,87 +109,50 @@ extension AccessMethodViewModel { switch id { case AccessMethodRepository.directId: InfoModalConfig( - header: NSLocalizedString( - "DIRECT_ACCESS_METHOD_MODAL_HEADER", - tableName: "APIAccess", - value: "Direct", - comment: "" - ), - preamble: NSLocalizedString( - "DIRECT_ACCESS_METHOD_MODAL_PREAMBLE", - tableName: "APIAccess", - value: "The app communicates with a Mullvad API server directly.", - comment: "" - ), + header: NSLocalizedString("Direct", comment: ""), + preamble: NSLocalizedString("The app communicates with a Mullvad API server directly.", comment: ""), body: [ NSLocalizedString( - "DIRECT_ACCESS_METHOD_MODAL_BODY_PART_1", - tableName: "APIAccess", - value: """ + """ With the "Direct" method, the app communicates with a Mullvad API server \ directly without any intermediate proxies. """, comment: "" ), - NSLocalizedString( - "DIRECT_ACCESS_METHOD_MODAL_BODY_PART_2", - tableName: "APIAccess", - value: "This can be useful when you are not affected by censorship.", - comment: "" - ), + NSLocalizedString("This can be useful when you are not affected by censorship.", comment: ""), ] ) case AccessMethodRepository.bridgeId: InfoModalConfig( - header: NSLocalizedString( - "BRIDGES_ACCESS_METHOD_MODAL_HEADER", - tableName: "APIAccess", - value: "Mullvad bridges", - comment: "" - ), + header: NSLocalizedString("Mullvad bridges", comment: ""), preamble: NSLocalizedString( - "BRIDGES_ACCESS_METHOD_MODAL_PREAMBLE", - tableName: "APIAccess", - value: "The app communicates with a Mullvad API server via a Mullvad bridge server.", + "The app communicates with a Mullvad API server via a Mullvad bridge server.", comment: "" ), body: [ NSLocalizedString( - "BRIDGES_ACCESS_METHOD_MODAL_BODY_PART_1", - tableName: "APIAccess", - value: """ + """ With the "Mullvad bridges" method, the app communicates with a Mullvad API server via a \ Mullvad bridge server. It does this by sending the traffic obfuscated by Shadowsocks. """, comment: "" ), NSLocalizedString( - "BRIDGES_ACCESS_METHOD_MODAL_BODY_PART_2", - tableName: "APIAccess", - value: "This can be useful if the API is censored but Mullvad’s bridge servers are not.", + "This can be useful if the API is censored but Mullvad’s bridge servers are not.", comment: "" ), ] ) case AccessMethodRepository.encryptedDNSId: InfoModalConfig( - header: NSLocalizedString( - "ENCRYPTED_DNS_ACCESS_METHOD_MODAL_HEADER", - tableName: "APIAccess", - value: "Encrypted DNS proxy", - comment: "" - ), + header: NSLocalizedString("Encrypted DNS proxy", comment: ""), preamble: NSLocalizedString( - "ENCRYPTED_DNS_ACCESS_METHOD_MODAL_PREAMBLE", - tableName: "APIAccess", - value: "The app communicates with a Mullvad API server via a proxy address.", + "The app communicates with a Mullvad API server via a proxy address.", comment: "" ), body: [ NSLocalizedString( - "ENCRYPTED_DNS_ACCESS_METHOD_MODAL_BODY_PART_1", - tableName: "APIAccess", - value: """ + """ With the "Encrypted DNS proxy" method, the app will communicate with our \ Mullvad API through a proxy address. It does this by retrieving an address from a DNS over HTTPS (DoH) server and \ @@ -222,9 +161,7 @@ extension AccessMethodViewModel { comment: "" ), NSLocalizedString( - "ENCRYPTED_DNS_ACCESS_METHOD_MODAL_BODY_PART_2", - tableName: "APIAccess", - value: """ + """ If you are not connected to our VPN, then the Encrypted DNS proxy will use your own non-VPN IP \ when connecting. The DoH servers are hosted by one of the following providers: Quad9 or Cloudflare. diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/AccessMethodProtocolPicker.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/AccessMethodProtocolPicker.swift index 182621eb7b..1cae2f566b 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/AccessMethodProtocolPicker.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/AccessMethodProtocolPicker.swift @@ -27,12 +27,7 @@ struct AccessMethodProtocolPicker { let controller = ListItemPickerViewController(dataSource: dataSource, selectedItemID: currentValue) controller.view.setAccessibilityIdentifier(.accessMethodProtocolPickerView) - controller.navigationItem.title = NSLocalizedString( - "SELECT_PROTOCOL_NAV_TITLE", - tableName: "APIAccess", - value: "Type", - comment: "" - ) + controller.navigationItem.title = NSLocalizedString("Type", comment: "") controller.onSelect = { selectedItem in navigationController.popViewController(animated: true) diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/ShadowsocksCipherPicker.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/ShadowsocksCipherPicker.swift index 16711f31a4..d5f6289223 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/ShadowsocksCipherPicker.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/ShadowsocksCipherPicker.swift @@ -26,12 +26,7 @@ struct ShadowsocksCipherPicker { let dataSource = ShadowsocksCipherPickerDataSource() let controller = ListItemPickerViewController(dataSource: dataSource, selectedItemID: currentValue) - controller.navigationItem.title = NSLocalizedString( - "SELECT_SHADOWSOCKS_CIPHER_NAV_TITLE", - tableName: "APIAccess", - value: "Cipher", - comment: "" - ) + controller.navigationItem.title = NSLocalizedString("Cipher", comment: "") controller.onSelect = { selectedItem in navigationController.popViewController(animated: true) diff --git a/ios/MullvadVPN/Coordinators/Settings/DAITA/DAITAMultihopNotice.swift b/ios/MullvadVPN/Coordinators/Settings/DAITA/DAITAMultihopNotice.swift index 007fd22cba..9023f218ab 100644 --- a/ios/MullvadVPN/Coordinators/Settings/DAITA/DAITAMultihopNotice.swift +++ b/ios/MullvadVPN/Coordinators/Settings/DAITA/DAITAMultihopNotice.swift @@ -15,14 +15,9 @@ struct DAITAMultihopNotice: View { .resizable() .frame(width: 18, height: 18) .foregroundStyle(Color(.primaryTextColor).opacity(0.6)) - Text(NSLocalizedString( - "SETTINGS_DAITA_MULTIHOP_ENABLED", - tableName: "Settings", - value: "Multihop is being used to enable DAITA for your selected location.", - comment: "" - )) - .font(.mullvadTinySemiBold) - .foregroundColor(Color(.primaryTextColor).opacity(0.6)) + Text(NSLocalizedString("Multihop is being used to enable DAITA for your selected location.", comment: "")) + .font(.mullvadTinySemiBold) + .foregroundColor(Color(.primaryTextColor).opacity(0.6)) } } } diff --git a/ios/MullvadVPN/Coordinators/Settings/DAITA/DAITASettingsCoordinator.swift b/ios/MullvadVPN/Coordinators/Settings/DAITA/DAITASettingsCoordinator.swift index 9ff06070ac..bdcae2d1ec 100644 --- a/ios/MullvadVPN/Coordinators/Settings/DAITA/DAITASettingsCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/Settings/DAITA/DAITASettingsCoordinator.swift @@ -51,12 +51,7 @@ class DAITASettingsCoordinator: Coordinator, SettingsChildCoordinator, Presentab } let host = UIHostingController(rootView: view) - host.title = NSLocalizedString( - "NAVIGATION_TITLE_DAITA", - tableName: "Settings", - value: "DAITA", - comment: "" - ) + host.title = NSLocalizedString("DAITA", comment: "") host.view.setAccessibilityIdentifier(.daitaView) customiseNavigation(on: host) @@ -88,31 +83,16 @@ class DAITASettingsCoordinator: Coordinator, SettingsChildCoordinator, Presentab id: "settings-daita-prompt", accessibilityIdentifier: .daitaPromptAlert, icon: .warning, - message: NSLocalizedString( - "SETTINGS_DAITA_ENABLE_TEXT", - tableName: "DAITA", - value: item.description, - comment: "" - ), + message: item.description, buttons: [ AlertAction( - title: String(format: NSLocalizedString( - "SETTINGS_DAITA_ENABLE_OK_ACTION", - tableName: "DAITA", - value: "Enable \"%@\"", - comment: "" - ), item.title), + title: String(format: NSLocalizedString("Enable \"%@\"", comment: ""), item.title), style: .default, accessibilityId: .daitaConfirmAlertEnableButton, handler: { onSave() } ), AlertAction( - title: NSLocalizedString( - "SETTINGS_DAITA_ENABLE_CANCEL_ACTION", - tableName: "DAITA", - value: "Cancel", - comment: "" - ), + title: NSLocalizedString("Cancel", comment: ""), style: .default, handler: { onDiscard() } ), diff --git a/ios/MullvadVPN/Coordinators/Settings/DAITA/DAITASettingsPromptItem.swift b/ios/MullvadVPN/Coordinators/Settings/DAITA/DAITASettingsPromptItem.swift index 7610db99ae..6659e215e9 100644 --- a/ios/MullvadVPN/Coordinators/Settings/DAITA/DAITASettingsPromptItem.swift +++ b/ios/MullvadVPN/Coordinators/Settings/DAITA/DAITASettingsPromptItem.swift @@ -21,9 +21,9 @@ enum DAITASettingsPromptItem: CustomStringConvertible { case let .daitaSettingIncompatibleWithSinglehop(setting), let .daitaSettingIncompatibleWithMultihop(setting): switch setting { case .daita: - "DAITA" + NSLocalizedString("DAITA", comment: "") case .directOnly: - "Direct only" + NSLocalizedString("Direct only", comment: "") } } } @@ -31,15 +31,19 @@ enum DAITASettingsPromptItem: CustomStringConvertible { var description: String { switch self { case .daitaSettingIncompatibleWithSinglehop: - """ + NSLocalizedString(""" DAITA isn't available at the currently selected location. After enabling, please go to \ the "Select location" view and select a location that supports DAITA. - """ + """, comment: "") + case .daitaSettingIncompatibleWithMultihop: - """ - DAITA isn't available on the current entry server. After enabling, please go to the \ - "Select location" view and select an entry location that supports DAITA. - """ + NSLocalizedString( + """ + DAITA isn't available on the current entry server. After enabling, please go to the \ + "Select location" view and select an entry location that supports DAITA. + """, + comment: "" + ) } } } diff --git a/ios/MullvadVPN/Coordinators/Settings/DAITA/SettingsDAITAView.swift b/ios/MullvadVPN/Coordinators/Settings/DAITA/SettingsDAITAView.swift index 57f6be62cd..ce014999a2 100644 --- a/ios/MullvadVPN/Coordinators/Settings/DAITA/SettingsDAITAView.swift +++ b/ios/MullvadVPN/Coordinators/Settings/DAITA/SettingsDAITAView.swift @@ -31,33 +31,21 @@ struct SettingsDAITAView<ViewModel>: View where ViewModel: TunnelSettingsObserva GroupedRowView { SwitchRowView( isOn: daitaIsEnabled, - text: NSLocalizedString( - "SETTINGS_SWITCH_DAITA_ENABLE", - tableName: "Settings", - value: "Enable", - comment: "" - ), + text: NSLocalizedString("Enable", comment: ""), accessibilityId: .daitaSwitch ) RowSeparator() SwitchRowView( isOn: directOnlyIsEnabled, disabled: !daitaIsEnabled.wrappedValue, - text: NSLocalizedString( - "SETTINGS_SWITCH_DAITA_DIRECT_ONLY", - tableName: "Settings", - value: "Direct only", - comment: "" - ), + text: NSLocalizedString("Direct only", comment: ""), accessibilityId: .daitaDirectOnlySwitch ) } SettingsRowViewFooter( text: NSLocalizedString( - "SETTINGS_SWITCH_DAITA_ENABLE", - tableName: "Settings", - value: """ + """ By enabling "Direct only" you will have to manually select a server that \ is DAITA-enabled. Multihop won't automatically be used to enable DAITA with \ any server. @@ -116,9 +104,7 @@ extension SettingsDAITAView { pages: [ SettingsInfoViewModelPage( body: NSLocalizedString( - "SETTINGS_INFO_DAITA_PAGE_1", - tableName: "Settings", - value: """ + """ **Attention: This increases network traffic and will also negatively affect speed, latency, \ and battery usage. Use with caution on limited plans.** @@ -134,9 +120,7 @@ extension SettingsDAITAView { ), SettingsInfoViewModelPage( body: NSLocalizedString( - "SETTINGS_INFO_DAITA_PAGE_2", - tableName: "Settings", - value: """ + """ If an observer monitors these data packets, DAITA makes it significantly \ harder for them to identify which websites you are visiting or with whom \ you are communicating. diff --git a/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideCoordinator.swift b/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideCoordinator.swift index 953189d5a2..60e6ece8c6 100644 --- a/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideCoordinator.swift @@ -68,35 +68,24 @@ extension IPOverrideCoordinator: @preconcurrency IPOverrideViewControllerDelegat } func presentAbout() { - let header = NSLocalizedString( - "IP_OVERRIDE_HEADER", - tableName: "IPOverride", - value: "Server IP override", - comment: "" - ) + let header = NSLocalizedString("Server IP override", comment: "") let body = [ NSLocalizedString( - "IP_OVERRIDE_BODY_1", - tableName: "IPOverride", - value: """ + """ On some networks, where various types of censorship are being used, our server IP addresses are \ sometimes blocked. """, comment: "" ), NSLocalizedString( - "IP_OVERRIDE_BODY_2", - tableName: "IPOverride", - value: """ + """ To circumvent this you can import a file or a text, provided by our support team, \ with new IP addresses that override the default addresses of the servers in the Select location view. """, comment: "" ), NSLocalizedString( - "IP_OVERRIDE_BODY_3", - tableName: "IPOverride", - value: """ + """ If you are having issues connecting to VPN servers, please contact support. """, comment: "" diff --git a/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideStatus.swift b/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideStatus.swift index 7a64a66c07..c09dea3f0d 100644 --- a/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideStatus.swift +++ b/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideStatus.swift @@ -26,26 +26,11 @@ enum IPOverrideStatus: Equatable, CustomStringConvertible { var title: String { switch self { case .active: - NSLocalizedString( - "IP_OVERRIDE_STATUS_TITLE_ACTIVE", - tableName: "IPOverride", - value: "Overrides active", - comment: "" - ) + NSLocalizedString("Overrides active", comment: "") case .noImports, .importFailed: - NSLocalizedString( - "IP_OVERRIDE_STATUS_TITLE_NO_IMPORTS", - tableName: "IPOverride", - value: "No overrides imported", - comment: "" - ) + NSLocalizedString("No overrides imported", comment: "") case .importSuccessful: - NSLocalizedString( - "IP_OVERRIDE_STATUS_TITLE_IMPORT_SUCCESSFUL", - tableName: "IPOverride", - value: "Import successful", - comment: "" - ) + NSLocalizedString("Import successful", comment: "") } } @@ -73,19 +58,15 @@ enum IPOverrideStatus: Equatable, CustomStringConvertible { case .active, .noImports: "" case let .importFailed(context): - String(format: NSLocalizedString( - "IP_OVERRIDE_STATUS_DESCRIPTION_INACTIVE", - tableName: "IPOverride", - value: "Import %@ was unsuccessful, please try again.", - comment: "" - ), context.description) + String( + format: NSLocalizedString("Import %@ was unsuccessful, please try again.", comment: ""), + context.description + ) case let .importSuccessful(context): - String(format: NSLocalizedString( - "IP_OVERRIDE_STATUS_DESCRIPTION_INACTIVE", - tableName: "IPOverride", - value: "Import %@ was successful, overrides are now active.", - comment: "" - ), context.description) + String( + format: NSLocalizedString("Import %@ was successful, overrides are now active.", comment: ""), + context.description + ) } } } diff --git a/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideTextViewController.swift b/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideTextViewController.swift index 31f2cfce3a..7389e90921 100644 --- a/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideTextViewController.swift +++ b/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideTextViewController.swift @@ -14,12 +14,7 @@ class IPOverrideTextViewController: UIViewController { private lazy var importButton: UIBarButtonItem = { return UIBarButtonItem( - title: NSLocalizedString( - "IMPORT_TEXT_IMPORT_BUTTON", - tableName: "IPOverride", - value: "Import", - comment: "" - ), + title: NSLocalizedString("Import", comment: ""), primaryAction: UIAction(handler: { [weak self] _ in self?.interactor.import(text: self?.textView.text ?? "") self?.dismiss(animated: true) @@ -42,12 +37,7 @@ class IPOverrideTextViewController: UIViewController { view.backgroundColor = .secondaryColor - navigationItem.title = NSLocalizedString( - "IMPORT_TEXT_NAVIGATION_TITLE", - tableName: "IPOverride", - value: "Import via text", - comment: "" - ) + navigationItem.title = NSLocalizedString("Import via text", comment: "") navigationItem.leftBarButtonItem = UIBarButtonItem( systemItem: .cancel, diff --git a/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideViewController.swift b/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideViewController.swift index 72f90c18aa..73df4fd447 100644 --- a/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideViewController.swift +++ b/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideViewController.swift @@ -27,12 +27,7 @@ class IPOverrideViewController: UIViewController { private lazy var clearButton: AppButton = { let button = AppButton(style: .danger) button.addTarget(self, action: #selector(didTapClearButton), for: .touchUpInside) - button.setTitle(NSLocalizedString( - "IP_OVERRIDE_CLEAR_BUTTON", - tableName: "IPOverride", - value: "Clear all overrides", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Clear all overrides", comment: ""), for: .normal) return button }() @@ -65,12 +60,7 @@ class IPOverrideViewController: UIViewController { } private func configureNavigation() { - title = NSLocalizedString( - "IP_OVERRIDE_HEADER", - tableName: "IPOverride", - value: "Server IP override", - comment: "" - ) + title = NSLocalizedString("Server IP override", comment: "") } private func addScrollView() { @@ -112,17 +102,10 @@ class IPOverrideViewController: UIViewController { private func addHeaderView() { let body = NSLocalizedString( - "IP_OVERRIDE_HEADER_BODY", - tableName: "IPOverride", - value: "Import files or text with the new IP addresses for the servers in the Select location view.", - comment: "" - ) - let link = NSLocalizedString( - "IP_OVERRIDE_HEADER_LINK", - tableName: "IPOverride", - value: "About Server IP override...", + "Import files or text with the new IP addresses for the servers in the Select location view.", comment: "" ) + let link = NSLocalizedString("About Server IP override...", comment: "") let headerView = InfoHeaderView(config: InfoHeaderConfig(body: body, link: link)) @@ -136,22 +119,12 @@ class IPOverrideViewController: UIViewController { private func addImportButtons() { let importTextButton = AppButton(style: .default) importTextButton.addTarget(self, action: #selector(didTapImportTextButton), for: .touchUpInside) - importTextButton.setTitle(NSLocalizedString( - "IP_OVERRIDE_IMPORT_TEXT_BUTTON", - tableName: "IPOverride", - value: "Import via text", - comment: "" - ), for: .normal) + importTextButton.setTitle(NSLocalizedString("Import via text", comment: ""), for: .normal) importTextButton.titleLabel?.textAlignment = .center let importFileButton = AppButton(style: .default) importFileButton.addTarget(self, action: #selector(didTapImportFileButton), for: .touchUpInside) - importFileButton.setTitle(NSLocalizedString( - "IP_OVERRIDE_IMPORT_FILE_BUTTON", - tableName: "IPOverride", - value: "Import file", - comment: "" - ), for: .normal) + importFileButton.setTitle(NSLocalizedString("Import file", comment: ""), for: .normal) importFileButton.titleLabel?.textAlignment = .center let stackView = UIStackView(arrangedSubviews: [importTextButton, importFileButton]) stackView.distribution = .fillEqually @@ -168,16 +141,9 @@ class IPOverrideViewController: UIViewController { let presentation = AlertPresentation( id: "ip-override-clear-alert", icon: .alert, - title: NSLocalizedString( - "IP_OVERRIDE_CLEAR_DIALOG_TITLE", - tableName: "IPOverride", - value: "Clear all overrides?", - comment: "" - ), + title: NSLocalizedString("Clear all overrides?", comment: ""), message: NSLocalizedString( - "IP_OVERRIDE_CLEAR_DIALOG_MESSAGE", - tableName: "IPOverride", - value: """ + """ Clearing the imported overrides changes the server IPs, in the Select location view, \ back to default. """, @@ -185,24 +151,14 @@ class IPOverrideViewController: UIViewController { ), buttons: [ AlertAction( - title: NSLocalizedString( - "IP_OVERRIDE_CLEAR_DIALOG_CLEAR_BUTTON", - tableName: "IPOverride", - value: "Clear", - comment: "" - ), + title: NSLocalizedString("Clear", comment: ""), style: .destructive, handler: { [weak self] in self?.interactor.deleteAllOverrides() } ), AlertAction( - title: NSLocalizedString( - "IP_OVERRIDE_CLEAR_DIALOG_CANCEL_BUTTON", - tableName: "IPOverride", - value: "Cancel", - comment: "" - ), + title: NSLocalizedString("Cancel", comment: ""), style: .default ), ] diff --git a/ios/MullvadVPN/Coordinators/Settings/Multihop/MultihopSettingsCoordinator.swift b/ios/MullvadVPN/Coordinators/Settings/Multihop/MultihopSettingsCoordinator.swift index b54bab2368..60b84e4104 100644 --- a/ios/MullvadVPN/Coordinators/Settings/Multihop/MultihopSettingsCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/Settings/Multihop/MultihopSettingsCoordinator.swift @@ -39,12 +39,7 @@ class MultihopSettingsCoordinator: Coordinator, SettingsChildCoordinator, Presen let view = SettingsMultihopView(tunnelViewModel: self.viewModel) let host = UIHostingController(rootView: view) - host.title = NSLocalizedString( - "NAVIGATION_TITLE_MULTIHOP", - tableName: "Settings", - value: "Multihop", - comment: "" - ) + host.title = NSLocalizedString("Multihop", comment: "") host.view.setAccessibilityIdentifier(.multihopView) customiseNavigation(on: host) diff --git a/ios/MullvadVPN/Coordinators/Settings/Multihop/SettingsMultihopView.swift b/ios/MullvadVPN/Coordinators/Settings/Multihop/SettingsMultihopView.swift index 457356323e..107b1c2dad 100644 --- a/ios/MullvadVPN/Coordinators/Settings/Multihop/SettingsMultihopView.swift +++ b/ios/MullvadVPN/Coordinators/Settings/Multihop/SettingsMultihopView.swift @@ -19,12 +19,7 @@ struct SettingsMultihopView<ViewModel>: View where ViewModel: TunnelSettingsObse SwitchRowView( isOn: $tunnelViewModel.value.isEnabled, - text: NSLocalizedString( - "SETTINGS_SWITCH_MULTIHOP", - tableName: "Settings", - value: "Enable", - comment: "" - ), + text: NSLocalizedString("Enable", comment: ""), accessibilityId: .multihopSwitch ) .padding(.leading, UIMetrics.contentInsets.left) @@ -44,9 +39,7 @@ extension SettingsMultihopView { pages: [ SettingsInfoViewModelPage( body: NSLocalizedString( - "SETTINGS_INFO_MULTIHOP", - tableName: "Settings", - value: """ + """ Multihop routes your traffic into one WireGuard server and out another, making it \ harder to trace. This results in increased latency but increases anonymity online. """, diff --git a/ios/MullvadVPN/Coordinators/Settings/SettingsViewControllerFactory.swift b/ios/MullvadVPN/Coordinators/Settings/SettingsViewControllerFactory.swift index bef1dd4f7e..d89f0618a9 100644 --- a/ios/MullvadVPN/Coordinators/Settings/SettingsViewControllerFactory.swift +++ b/ios/MullvadVPN/Coordinators/Settings/SettingsViewControllerFactory.swift @@ -114,12 +114,7 @@ struct SettingsViewControllerFactory { let view = SettingsMultihopView(tunnelViewModel: viewModel) let host = UIHostingController(rootView: view) - host.title = NSLocalizedString( - "NAVIGATION_TITLE_MULTIHOP", - tableName: "Settings", - value: "Multihop", - comment: "" - ) + host.title = NSLocalizedString("Multihop", comment: "") host.view.setAccessibilityIdentifier(.multihopView) return .viewController(host) diff --git a/ios/MullvadVPN/Coordinators/Settings/Views/SettingsInfoView.swift b/ios/MullvadVPN/Coordinators/Settings/Views/SettingsInfoView.swift index cbabf14634..4e43614302 100644 --- a/ios/MullvadVPN/Coordinators/Settings/Views/SettingsInfoView.swift +++ b/ios/MullvadVPN/Coordinators/Settings/Views/SettingsInfoView.swift @@ -134,9 +134,7 @@ struct SettingsInfoView: View { pages: [ SettingsInfoViewModelPage( body: NSLocalizedString( - "SETTINGS_INFO_DAITA_PAGE_1", - tableName: "Settings", - value: """ + """ **Attention: This increases network traffic and will also negatively affect speed, latency, \ and battery usage. Use with caution on limited plans.** @@ -152,9 +150,7 @@ struct SettingsInfoView: View { ), SettingsInfoViewModelPage( body: NSLocalizedString( - "SETTINGS_INFO_DAITA_PAGE_2", - tableName: "Settings", - value: """ + """ If an observer monitors these data packets, DAITA makes it significantly \ harder for them to identify which websites you are visiting or with whom \ you are communicating. diff --git a/ios/MullvadVPN/Coordinators/TunnelCoordinator.swift b/ios/MullvadVPN/Coordinators/TunnelCoordinator.swift index e7a562f9a6..cac0f39bf6 100644 --- a/ios/MullvadVPN/Coordinators/TunnelCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/TunnelCoordinator.swift @@ -93,31 +93,19 @@ class TunnelCoordinator: Coordinator, Presenting { id: "main-cancel-tunnel-alert", icon: .alert, message: NSLocalizedString( - "CANCEL_TUNNEL_ALERT_MESSAGE", - tableName: "Main", - value: "If you disconnect now, you won’t be able to secure your connection until the device is online.", + "If you disconnect now, you won’t be able to secure your connection until the device is online.", comment: "" ), buttons: [ AlertAction( - title: NSLocalizedString( - "CANCEL_TUNNEL_ALERT_DISCONNECT_ACTION", - tableName: "Main", - value: "Disconnect", - comment: "" - ), + title: NSLocalizedString("Disconnect", comment: ""), style: .destructive, handler: { [weak self] in self?.tunnelManager.stopTunnel() } ), AlertAction( - title: NSLocalizedString( - "CANCEL_TUNNEL_ALERT_CANCEL_ACTION", - tableName: "Main", - value: "Cancel", - comment: "" - ), + title: NSLocalizedString("Cancel", comment: ""), style: .default ), ] diff --git a/ios/MullvadVPN/Coordinators/WelcomeCoordinator.swift b/ios/MullvadVPN/Coordinators/WelcomeCoordinator.swift index 574418bb60..34a656047f 100644 --- a/ios/MullvadVPN/Coordinators/WelcomeCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/WelcomeCoordinator.swift @@ -83,9 +83,6 @@ final class WelcomeCoordinator: Coordinator, Poppable, Presenting { extension WelcomeCoordinator: @preconcurrency WelcomeViewControllerDelegate { func didRequestToShowFailToFetchProducts(controller: WelcomeViewController) { let message = NSLocalizedString( - "WELCOME_FAILED_TO_FETCH_PRODUCTS_DIALOG", - tableName: "Welcome", - value: """ Failed to connect to App store, please try again later. """, @@ -98,12 +95,7 @@ extension WelcomeCoordinator: @preconcurrency WelcomeViewControllerDelegate { message: message, buttons: [ AlertAction( - title: NSLocalizedString( - "WELCOME_FAILED_TO_FETCH_PRODUCTS_OK_ACTION", - tableName: "Welcome", - value: "Got it!", - comment: "" - ), + title: NSLocalizedString("Got it!", comment: ""), style: .default ), ] @@ -115,9 +107,6 @@ extension WelcomeCoordinator: @preconcurrency WelcomeViewControllerDelegate { func didRequestToShowInfo(controller: WelcomeViewController) { let message = NSLocalizedString( - "WELCOME_DEVICE_CONCEPT_TEXT_DIALOG", - tableName: "Welcome", - value: """ This is the name assigned to the device. Each device logged in on a \ Mullvad account gets a unique name that helps \ @@ -135,12 +124,7 @@ extension WelcomeCoordinator: @preconcurrency WelcomeViewControllerDelegate { message: message, buttons: [ AlertAction( - title: NSLocalizedString( - "WELCOME_DEVICE_NAME_DIALOG_OK_ACTION", - tableName: "Welcome", - value: "Got it!", - comment: "" - ), + title: NSLocalizedString("Got it!", comment: ""), style: .default ), ] diff --git a/ios/MullvadVPN/Extensions/RESTCreateApplePaymentResponse+Localization.swift b/ios/MullvadVPN/Extensions/RESTCreateApplePaymentResponse+Localization.swift index d52d8e24df..9f113a1837 100644 --- a/ios/MullvadVPN/Extensions/RESTCreateApplePaymentResponse+Localization.swift +++ b/ios/MullvadVPN/Extensions/RESTCreateApplePaymentResponse+Localization.swift @@ -17,19 +17,9 @@ extension REST.CreateApplePaymentResponse { func alertTitle(context: Context) -> String { switch context { case .purchase: - return NSLocalizedString( - "TIME_ADDED_ALERT_SUCCESS_TITLE", - tableName: "REST", - value: "Thanks for your purchase", - comment: "" - ) + return NSLocalizedString("Thanks for your purchase", comment: "") case .restoration: - return NSLocalizedString( - "RESTORE_PURCHASES_ALERT_TITLE", - tableName: "REST", - value: "Restore purchases", - comment: "" - ) + return NSLocalizedString("Restore purchases", comment: "") } } @@ -37,31 +27,19 @@ extension REST.CreateApplePaymentResponse { switch context { case .purchase: return String( - format: NSLocalizedString( - "TIME_ADDED_ALERT_SUCCESS_MESSAGE", - tableName: "REST", - value: "%@ have been added to your account", - comment: "" - ), + format: NSLocalizedString("%@ have been added to your account", comment: ""), formattedTimeAdded ?? "" ) case .restoration: switch self { case .noTimeAdded: return NSLocalizedString( - "RESTORE_PURCHASES_ALERT_NO_TIME_ADDED_MESSAGE", - tableName: "REST", - value: "Your previous purchases have already been added to this account.", + "Your previous purchases have already been added to this account.", comment: "" ) case .timeAdded: return String( - format: NSLocalizedString( - "RESTORE_PURCHASES_ALERT_TIME_ADDED_MESSAGE", - tableName: "REST", - value: "%@ have been added to your account", - comment: "" - ), + format: NSLocalizedString("%@ have been added to your account", comment: ""), formattedTimeAdded ?? "" ) } @@ -73,19 +51,9 @@ extension REST.CreateApplePaymentResponse.Context { var errorTitle: String { switch self { case .purchase: - return NSLocalizedString( - "CANNOT_COMPLETE_PURCHASE_ALERT_TITLE", - tableName: "Payment", - value: "Cannot complete the purchase", - comment: "" - ) + return NSLocalizedString("Cannot complete the purchase", comment: "") case .restoration: - return NSLocalizedString( - "RESTORE_PURCHASES_FAILURE_ALERT_TITLE", - tableName: "Payment", - value: "Cannot restore purchases", - comment: "" - ) + return NSLocalizedString("Cannot restore purchases", comment: "") } } } diff --git a/ios/MullvadVPN/Extensions/RESTError+Display.swift b/ios/MullvadVPN/Extensions/RESTError+Display.swift index 38d9d959fb..edc00678ea 100644 --- a/ios/MullvadVPN/Extensions/RESTError+Display.swift +++ b/ios/MullvadVPN/Extensions/RESTError+Display.swift @@ -15,78 +15,38 @@ extension REST.Error: MullvadTypes.DisplayError { switch self { case let .network(urlError): return String( - format: NSLocalizedString( - "NETWORK_ERROR", - tableName: "REST", - value: "Network error: %@", - comment: "" - ), + format: NSLocalizedString("Network error: %@", comment: ""), urlError.localizedDescription ) case let .unhandledResponse(statusCode, serverResponse): guard let serverResponse else { - return String(format: NSLocalizedString( - "UNEXPECTED_RESPONSE", - tableName: "REST", - value: "Unexpected server response: %d", - comment: "" - ), statusCode) + return String(format: NSLocalizedString("Unexpected server response: %d", comment: ""), statusCode) } switch serverResponse.code { case .invalidAccount: - return NSLocalizedString( - "INVALID_ACCOUNT_ERROR", - tableName: "REST", - value: "Invalid account", - comment: "" - ) + return NSLocalizedString("Invalid account", comment: "") case .maxDevicesReached: - return NSLocalizedString( - "MAX_DEVICES_REACHED_ERROR", - tableName: "REST", - value: "Too many devices registered with account", - comment: "" - ) + return NSLocalizedString("Too many devices registered with account", comment: "") case .serviceUnavailable: - return NSLocalizedString( - "SERVICE_UNAVAILABLE", - tableName: "REST", - value: "We are having some issues, please try again later", - comment: "" - ) + return NSLocalizedString("We are having some issues, please try again later", comment: "") case .tooManyRequests: - return NSLocalizedString( - "TOO_MANY_REQUESTS", - tableName: "REST", - value: "We are having some issues, please try again later", - comment: "" - ) + return NSLocalizedString("We are having some issues, please try again later", comment: "") default: return String( - format: NSLocalizedString( - "SERVER_ERROR", - tableName: "REST", - value: "Unexpected server response: %1$@ (HTTP status: %2$d)", - comment: "" - ), + format: NSLocalizedString("Unexpected server response: %1$@ (HTTP status: %2$d)", comment: ""), serverResponse.code.rawValue, statusCode ) } default: - return NSLocalizedString( - "INTERNAL_ERROR", - tableName: "REST", - value: "Internal error.", - comment: "" - ) + return NSLocalizedString("Internal error.", comment: "") } } } diff --git a/ios/MullvadVPN/Extensions/SKError+Localized.swift b/ios/MullvadVPN/Extensions/SKError+Localized.swift index 8d4754e1bc..32a0cb6501 100644 --- a/ios/MullvadVPN/Extensions/SKError+Localized.swift +++ b/ios/MullvadVPN/Extensions/SKError+Localized.swift @@ -12,40 +12,15 @@ extension SKError: Foundation.LocalizedError { public var errorDescription: String? { switch code { case .unknown: - return NSLocalizedString( - "UNKNOWN_ERROR", - tableName: "StoreKitErrors", - value: "Unknown error.", - comment: "" - ) + return NSLocalizedString("Unknown error.", comment: "") case .clientInvalid: - return NSLocalizedString( - "CLIENT_INVALID", - tableName: "StoreKitErrors", - value: "Client is not allowed to issue the request.", - comment: "" - ) + return NSLocalizedString("Client is not allowed to issue the request.", comment: "") case .paymentCancelled: - return NSLocalizedString( - "PAYMENT_CANCELLED", - tableName: "StoreKitErrors", - value: "The payment request was cancelled.", - comment: "" - ) + return NSLocalizedString("The payment request was cancelled.", comment: "") case .paymentInvalid: - return NSLocalizedString( - "PAYMENT_INVALID", - tableName: "StoreKitErrors", - value: "Invalid purchase identifier.", - comment: "" - ) + return NSLocalizedString("Invalid purchase identifier.", comment: "") case .paymentNotAllowed: - return NSLocalizedString( - "PAYMENT_NOT_ALLOWED", - tableName: "StoreKitErrors", - value: "This device is not allowed to make the payment.", - comment: "" - ) + return NSLocalizedString("This device is not allowed to make the payment.", comment: "") default: return localizedDescription } diff --git a/ios/MullvadVPN/Extensions/StorePaymentManagerError+Display.swift b/ios/MullvadVPN/Extensions/StorePaymentManagerError+Display.swift index 8c4a3d42c5..39f00e8fac 100644 --- a/ios/MullvadVPN/Extensions/StorePaymentManagerError+Display.swift +++ b/ios/MullvadVPN/Extensions/StorePaymentManagerError+Display.swift @@ -14,64 +14,32 @@ extension StorePaymentManagerError: DisplayError { var displayErrorDescription: String? { switch self { case .noAccountSet: - return NSLocalizedString( - "INTERNAL_ERROR", - tableName: "StorePaymentManager", - value: "Internal error.", - comment: "" - ) + return NSLocalizedString("Internal error.", comment: "") case let .validateAccount(error): let reason = (error as? DisplayError)?.displayErrorDescription ?? "" return String( - format: NSLocalizedString( - "VALIDATE_ACCOUNT_ERROR", - tableName: "StorePaymentManager", - value: "Failed to validate account number: %@", - comment: "" - ), reason + format: NSLocalizedString("Failed to validate account number: %@", comment: ""), reason ) case let .readReceipt(readReceiptError): if readReceiptError is StoreReceiptNotFound { - return NSLocalizedString( - "RECEIPT_NOT_FOUND_ERROR", - tableName: "StorePaymentManager", - value: "AppStore receipt is not found on disk.", - comment: "" - ) + return NSLocalizedString("AppStore receipt is not found on disk.", comment: "") } else if let storeError = readReceiptError as? SKError { return String( - format: NSLocalizedString( - "REFRESH_RECEIPT_ERROR", - tableName: "StorePaymentManager", - value: "Cannot refresh the AppStore receipt: %@", - comment: "" - ), + format: NSLocalizedString("Cannot refresh the AppStore receipt: %@", comment: ""), storeError.localizedDescription ) } else { - return NSLocalizedString( - "READ_RECEIPT_ERROR", - tableName: "StorePaymentManager", - value: "Cannot read the AppStore receipt from disk", - comment: "" - ) + return NSLocalizedString("Cannot read the AppStore receipt from disk", comment: "") } case let .sendReceipt(error): let reason = (error as? DisplayError)?.displayErrorDescription ?? "" - let errorFormat = NSLocalizedString( - "SEND_RECEIPT_ERROR", - tableName: "StorePaymentManager", - value: "Failed to send the receipt to server: %@", - comment: "" - ) + let errorFormat = NSLocalizedString("Failed to send the receipt to server: %@", comment: "") let recoverySuggestion = NSLocalizedString( - "SEND_RECEIPT_RECOVERY_SUGGESTION", - tableName: "StorePaymentManager", - value: "Please retry by using the \"Restore purchases\" button.", + "Please retry by using the \"Restore purchases\" button.", comment: "" ) var errorString = String(format: errorFormat, reason) diff --git a/ios/MullvadVPN/Extensions/UIBarButtonItem+KeyboardNavigation.swift b/ios/MullvadVPN/Extensions/UIBarButtonItem+KeyboardNavigation.swift index 89b540ca37..14c56e6703 100644 --- a/ios/MullvadVPN/Extensions/UIBarButtonItem+KeyboardNavigation.swift +++ b/ios/MullvadVPN/Extensions/UIBarButtonItem+KeyboardNavigation.swift @@ -15,19 +15,9 @@ extension UIBarButtonItem { fileprivate var localizedTitle: String { switch self { case .previous: - return NSLocalizedString( - "PREVIOUS_BUTTON_TITLE", - tableName: "KeyboardNavigation", - value: "Previous", - comment: "Previous button" - ) + return NSLocalizedString("Previous", comment: "") case .next: - return NSLocalizedString( - "NEXT_BUTTON_TITLE", - tableName: "KeyboardNavigation", - value: "Next", - comment: "Next button" - ) + return NSLocalizedString("Next", comment: "") } } diff --git a/ios/MullvadVPN/Notifications/Notification Providers/AccountExpiryInAppNotificationProvider.swift b/ios/MullvadVPN/Notifications/Notification Providers/AccountExpiryInAppNotificationProvider.swift index 94a6e3f9cb..bda223bda9 100644 --- a/ios/MullvadVPN/Notifications/Notification Providers/AccountExpiryInAppNotificationProvider.swift +++ b/ios/MullvadVPN/Notifications/Notification Providers/AccountExpiryInAppNotificationProvider.swift @@ -55,9 +55,8 @@ final class AccountExpiryInAppNotificationProvider: NotificationProvider, InAppN style: .warning, title: durationText, body: NSAttributedString(string: NSLocalizedString( - "ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_BODY", - value: "You can add more time via the account view or website to continue using the VPN.", - comment: "Title for in-app notification, displayed within the last X days until account expiry." + "You can add more time via the account view or website to continue using the VPN.", + comment: "" )) ) } @@ -116,11 +115,6 @@ extension AccountExpiryInAppNotificationProvider { ) else { return nil } - return String(format: NSLocalizedString( - "ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_TITLE", - tableName: "AccountExpiry", - value: "%@ left on this account", - comment: "Message for in-app notification, displayed within the last X days until account expiry." - ), duration).uppercased() + return String(format: NSLocalizedString("%@ left on this account", comment: ""), duration).uppercased() } } diff --git a/ios/MullvadVPN/Notifications/Notification Providers/AccountExpirySystemNotificationProvider.swift b/ios/MullvadVPN/Notifications/Notification Providers/AccountExpirySystemNotificationProvider.swift index 10d3bb8d92..b106c7fe42 100644 --- a/ios/MullvadVPN/Notifications/Notification Providers/AccountExpirySystemNotificationProvider.swift +++ b/ios/MullvadVPN/Notifications/Notification Providers/AccountExpirySystemNotificationProvider.swift @@ -130,18 +130,8 @@ final class AccountExpirySystemNotificationProvider: NotificationProvider, Syste extension AccountExpirySystemNotificationProvider { private var formattedRemainingDurationTitle: String { accountHasExpired - ? NSLocalizedString( - "ACCOUNT_EXPIRY_SYSTEM_NOTIFICATION_TITLE", - tableName: "AccountExpiry", - value: "Account credit has expired", - comment: "Title for system account expiry notification, fired on account expiry." - ) - : NSLocalizedString( - "ACCOUNT_EXPIRY_SYSTEM_NOTIFICATION_TITLE", - tableName: "AccountExpiry", - value: "Account credit expires soon", - comment: "Title for system account expiry notification, fired X days prior to account expiry." - ) + ? NSLocalizedString("Account credit has expired", comment: "") + : NSLocalizedString("Account credit expires soon", comment: "") } private var formattedRemainingDurationBody: String? { @@ -159,22 +149,18 @@ extension AccountExpirySystemNotificationProvider { private var expiredText: String { NSLocalizedString( - "ACCOUNT_EXPIRY_SYSTEM_NOTIFICATION_BODY", - tableName: "AccountExpiry", - value: """ + """ Blocking internet: Your time on this account has expired. To continue using the internet, \ please add more time or disconnect the VPN. """, - comment: "Message for in-app notification, displayed on account expiry while connected to VPN." + comment: "" ) } private var singleDayText: String { NSLocalizedString( - "ACCOUNT_EXPIRY_SYSTEM_NOTIFICATION_BODY", - tableName: "AccountExpiry", - value: "You have one day left on this account. Please add more time to continue using the VPN.", - comment: "Message for in-app notification, displayed within the last 1 day until account expiry." + "You have one day left on this account. Please add more time to continue using the VPN.", + comment: "" ) } @@ -189,11 +175,9 @@ extension AccountExpirySystemNotificationProvider { ) else { return nil } - return String(format: NSLocalizedString( - "ACCOUNT_EXPIRY_SYSTEM_NOTIFICATION_BODY", - tableName: "AccountExpiry", - value: "You have %@ left on this account.", - comment: "Message for in-app notification, displayed within the last X days until account expiry." - ), duration.lowercased()) + return String( + format: NSLocalizedString("You have %@ left on this account.", comment: ""), + duration.lowercased() + ) } } diff --git a/ios/MullvadVPN/Notifications/Notification Providers/LatestChangesNotificationProvider.swift b/ios/MullvadVPN/Notifications/Notification Providers/LatestChangesNotificationProvider.swift index 02991b5848..69e2531f46 100644 --- a/ios/MullvadVPN/Notifications/Notification Providers/LatestChangesNotificationProvider.swift +++ b/ios/MullvadVPN/Notifications/Notification Providers/LatestChangesNotificationProvider.swift @@ -42,11 +42,7 @@ class LatestChangesNotificationProvider: NotificationProvider, InAppNotification return InAppNotificationDescriptor( identifier: identifier, style: .success, - title: NSLocalizedString( - "LATEST_CHANGES_IN_APP_NOTIFICATION_TITLE", - value: "NEW VERSION INSTALLED", - comment: "" - ), + title: NSLocalizedString("NEW VERSION INSTALLED", comment: ""), body: createNotificationBody(), button: createCloseButtonAction(), tapAction: createTapAction() @@ -55,11 +51,7 @@ class LatestChangesNotificationProvider: NotificationProvider, InAppNotification private func createNotificationBody() -> NSAttributedString { NSAttributedString( - markdownString: NSLocalizedString( - "LATEST_CHANGES_IN_APP_NOTIFICATION_BODY", - value: "**Tap here** to see what’s new.", - comment: "" - ), + markdownString: NSLocalizedString("**Tap here** to see what’s new.", comment: ""), options: MarkdownStylingOptions( font: .preferredFont(forTextStyle: .body) ) diff --git a/ios/MullvadVPN/Notifications/Notification Providers/NewDeviceNotificationProvider.swift b/ios/MullvadVPN/Notifications/Notification Providers/NewDeviceNotificationProvider.swift index eb6b9ef32f..62d8429984 100644 --- a/ios/MullvadVPN/Notifications/Notification Providers/NewDeviceNotificationProvider.swift +++ b/ios/MullvadVPN/Notifications/Notification Providers/NewDeviceNotificationProvider.swift @@ -26,8 +26,7 @@ final class NewDeviceNotificationProvider: NotificationProvider, private var attributedBody: NSAttributedString { let formattedString = NSLocalizedString( - "ACCOUNT_CREATION_INAPP_NOTIFICATION_BODY", - value: "Welcome, this device is now called **%@**. For more details see the info button in Account.", + "Welcome, this device is now called **%@**. For more details see the info button in Account.", comment: "" ) let deviceName = storedDeviceData?.capitalizedName ?? "" @@ -50,11 +49,7 @@ final class NewDeviceNotificationProvider: NotificationProvider, return InAppNotificationDescriptor( identifier: identifier, style: .success, - title: NSLocalizedString( - "ACCOUNT_CREATION_INAPP_NOTIFICATION_TITLE", - value: "NEW DEVICE CREATED", - comment: "" - ), + title: NSLocalizedString("NEW DEVICE CREATED", comment: ""), body: attributedBody, button: InAppNotificationAction( image: UIImage.Buttons.closeSmall, diff --git a/ios/MullvadVPN/Notifications/Notification Providers/TunnelStatusNotificationProvider.swift b/ios/MullvadVPN/Notifications/Notification Providers/TunnelStatusNotificationProvider.swift index 43eba09131..792a013ade 100644 --- a/ios/MullvadVPN/Notifications/Notification Providers/TunnelStatusNotificationProvider.swift +++ b/ios/MullvadVPN/Notifications/Notification Providers/TunnelStatusNotificationProvider.swift @@ -155,11 +155,7 @@ final class TunnelStatusNotificationProvider: NotificationProvider, InAppNotific return InAppNotificationDescriptor( identifier: identifier, style: .error, - title: NSLocalizedString( - "TUNNEL_BLOCKED_INAPP_NOTIFICATION_TITLE", - value: "BLOCKING INTERNET", - comment: "" - ), + title: NSLocalizedString("BLOCKING INTERNET", comment: ""), body: createNotificationBody(localizedReasonForBlockedStateError(packetTunnelError)), tapAction: tapAction ) @@ -167,11 +163,7 @@ final class TunnelStatusNotificationProvider: NotificationProvider, InAppNotific private func createNotificationBody(_ string: String) -> NSAttributedString { NSAttributedString( - markdownString: NSLocalizedString( - "LATEST_CHANGES_IN_APP_NOTIFICATION_BODY", - value: string, - comment: "" - ), + markdownString: string, options: MarkdownStylingOptions(font: UIFont.preferredFont(forTextStyle: .body)), applyEffect: { markdownType, _ in guard case .bold = markdownType else { return [:] } @@ -185,20 +177,12 @@ final class TunnelStatusNotificationProvider: NotificationProvider, InAppNotific if let startError = error as? StartTunnelError { body = String( - format: NSLocalizedString( - "START_TUNNEL_ERROR_INAPP_NOTIFICATION_BODY", - value: "Failed to start the tunnel: %@.", - comment: "" - ), + format: NSLocalizedString("Failed to start the tunnel: %@.", comment: ""), startError.underlyingError?.localizedDescription ?? "" ) } else if let stopError = error as? StopTunnelError { body = String( - format: NSLocalizedString( - "STOP_TUNNEL_ERROR_INAPP_NOTIFICATION_BODY", - value: "Failed to stop the tunnel: %@.", - comment: "" - ), + format: NSLocalizedString("Failed to stop the tunnel: %@.", comment: ""), stopError.underlyingError?.localizedDescription ?? "" ) } else { @@ -208,11 +192,7 @@ final class TunnelStatusNotificationProvider: NotificationProvider, InAppNotific return InAppNotificationDescriptor( identifier: identifier, style: .error, - title: NSLocalizedString( - "TUNNEL_MANAGER_ERROR_INAPP_NOTIFICATION_TITLE", - value: "TUNNEL ERROR", - comment: "" - ), + title: NSLocalizedString("TUNNEL ERROR", comment: ""), body: .init(string: body) ) } @@ -221,15 +201,10 @@ final class TunnelStatusNotificationProvider: NotificationProvider, InAppNotific InAppNotificationDescriptor( identifier: identifier, style: .warning, - title: NSLocalizedString( - "TUNNEL_NO_CONNECTIVITY_INAPP_NOTIFICATION_TITLE", - value: "NETWORK ISSUES", - comment: "" - ), + title: NSLocalizedString("NETWORK ISSUES", comment: ""), body: .init( string: NSLocalizedString( - "TUNNEL_NO_CONNECTIVITY_INAPP_NOTIFICATION_BODY", - value: """ + """ Your device is offline. The tunnel will automatically connect once \ your device is back online. """, @@ -243,15 +218,10 @@ final class TunnelStatusNotificationProvider: NotificationProvider, InAppNotific InAppNotificationDescriptor( identifier: identifier, style: .warning, - title: NSLocalizedString( - "TUNNEL_NO_NETWORK_INAPP_NOTIFICATION_TITLE", - value: "NETWORK ISSUES", - comment: "" - ), + title: NSLocalizedString("NETWORK ISSUES", comment: ""), body: .init( string: NSLocalizedString( - "TUNNEL_NO_NETWORK_INAPP_NOTIFICATION_BODY", - value: """ + """ Your device is offline. Try connecting again when the device \ has access to Internet. """, @@ -262,34 +232,33 @@ final class TunnelStatusNotificationProvider: NotificationProvider, InAppNotific } private func localizedReasonForBlockedStateError(_ error: BlockedStateReason) -> String { - let errorString: String - + let errorStringKey: String switch error { case .outdatedSchema: - errorString = "Unable to start tunnel connection after update. Please disconnect and reconnect." + errorStringKey = "ERROR_OUTDATED_SCHEMA" case .noRelaysSatisfyingFilterConstraints: - errorString = "No servers match your location filter. Try changing filter settings." + errorStringKey = "ERROR_NO_RELAYS_SATISFYING_FILTER_CONSTRAINTS" case .multihopEntryEqualsExit: - errorString = "The entry and exit servers cannot be the same. Try changing one to a new server or location." + errorStringKey = "ERROR_MULTIHOP_ENTRY_EQUALS_EXIT" case .noRelaysSatisfyingDaitaConstraints: - errorString = "No DAITA compatible servers match your location settings. Try changing location." + errorStringKey = "ERROR_NO_RELAYS_SATISFYING_DAITA_CONSTRAINTS" case .noRelaysSatisfyingConstraints: - errorString = "No servers match your settings, try changing server or other settings." + errorStringKey = "ERROR_NO_RELAYS_SATISFYING_CONSTRAINTS" case .noRelaysSatisfyingPortConstraints: - errorString = "The selected WireGuard port is not supported, please change it under **VPN settings**." + errorStringKey = "ERROR_NO_RELAYS_SATISFYING_PORT_CONSTRAINTS" case .invalidAccount: - errorString = "You are logged in with an invalid account number. Please log out and try another one." + errorStringKey = "ERROR_INVALID_ACCOUNT" case .deviceLoggedOut: - errorString = "Unable to authenticate account. Please log out and log back in." + errorStringKey = "ERROR_DEVICE_LOGGED_OUT" default: - errorString = "Unable to start tunnel connection. Please send a problem report." + errorStringKey = "ERROR_DEFAULT" } - return NSLocalizedString( - "BLOCKED_STATE_ERROR_TITLE", - tableName: "Main", - value: errorString, + let errorString = NSLocalizedString( + errorStringKey, comment: "" ) + + return errorString } } diff --git a/ios/MullvadVPN/SceneDelegate.swift b/ios/MullvadVPN/SceneDelegate.swift index feec718687..c113c6514e 100644 --- a/ios/MullvadVPN/SceneDelegate.swift +++ b/ios/MullvadVPN/SceneDelegate.swift @@ -208,16 +208,11 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, @preconcurrency Setting let presentation = AlertPresentation( id: "settings-migration-error-alert", - title: NSLocalizedString( - "ALERT_TITLE", - tableName: "SettingsMigrationUI", - value: "Settings migration error", - comment: "" - ), + title: NSLocalizedString("Settings migration error", comment: ""), message: Self.migrationErrorReason(error), buttons: [ AlertAction( - title: NSLocalizedString("Got it!", tableName: "SettingsMigrationUI", comment: ""), + title: NSLocalizedString("Got it!", comment: ""), style: .default, handler: { completionHandler() @@ -233,9 +228,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, @preconcurrency Setting private static func migrationErrorReason(_ error: Error) -> String { if error is UnsupportedSettingsVersionError { return NSLocalizedString( - "NEWER_STORED_SETTINGS_ERROR", - tableName: "SettingsMigrationUI", - value: """ + """ The version of settings stored on device is unrecognized.\ Settings will be reset to defaults and the device will be logged out. """, @@ -243,9 +236,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, @preconcurrency Setting ) } else { return NSLocalizedString( - "INTERNAL_ERROR", - tableName: "SettingsMigrationUI", - value: """ + """ Internal error occurred. Settings will be reset to defaults and device logged out. """, comment: "" diff --git a/ios/MullvadVPN/StorePaymentManager/StoreSubscription.swift b/ios/MullvadVPN/StorePaymentManager/StoreSubscription.swift index b715f85a19..ad20c741c2 100644 --- a/ios/MullvadVPN/StorePaymentManager/StoreSubscription.swift +++ b/ios/MullvadVPN/StorePaymentManager/StoreSubscription.swift @@ -17,19 +17,9 @@ enum StoreSubscription: String, CaseIterable { var localizedTitle: String { switch self { case .thirtyDays: - return NSLocalizedString( - "STORE_SUBSCRIPTION_TITLE_ADD_30_DAYS", - tableName: "StoreSubscriptions", - value: "Add 30 days", - comment: "" - ) + return NSLocalizedString("Add 30 days", comment: "") case .ninetyDays: - return NSLocalizedString( - "STORE_SUBSCRIPTION_TITLE_ADD_90_DAYS", - tableName: "StoreSubscriptions", - value: "Add 90 days", - comment: "" - ) + return NSLocalizedString("Add 90 days", comment: "") } } } diff --git a/ios/MullvadVPN/TunnelManager/TunnelManagerErrors.swift b/ios/MullvadVPN/TunnelManager/TunnelManagerErrors.swift index 2e83b3e1ec..e1dad007c1 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelManagerErrors.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelManagerErrors.swift @@ -11,23 +11,13 @@ import MullvadTypes struct UnsetTunnelError: LocalizedError { var errorDescription: String? { - NSLocalizedString( - "UNSET_TUNNEL_ERROR", - tableName: "TunnelManager", - value: "Tunnel is unset.", - comment: "" - ) + NSLocalizedString("Tunnel is unset.", comment: "") } } struct InvalidDeviceStateError: LocalizedError { var errorDescription: String? { - NSLocalizedString( - "INVALID_DEVICE_STATE_ERROR", - tableName: "TunnelManager", - value: "Invalid device state.", - comment: "" - ) + NSLocalizedString("Invalid device state.", comment: "") } } @@ -35,12 +25,7 @@ struct StartTunnelError: LocalizedError, WrappingError { private let _underlyingError: Error var errorDescription: String? { - NSLocalizedString( - "START_TUNNEL_ERROR", - tableName: "TunnelManager", - value: "Failed to start the tunnel.", - comment: "" - ) + NSLocalizedString("Failed to start the tunnel.", comment: "") } var underlyingError: Error? { @@ -56,12 +41,7 @@ struct StopTunnelError: LocalizedError, WrappingError { private let _underlyingError: Error var errorDescription: String? { - NSLocalizedString( - "STOP_TUNNEL_ERROR", - tableName: "TunnelManager", - value: "Failed to stop the tunnel.", - comment: "" - ) + NSLocalizedString("Failed to stop the tunnel.", comment: "") } var underlyingError: Error? { diff --git a/ios/MullvadVPN/TunnelManager/TunnelState+UI.swift b/ios/MullvadVPN/TunnelManager/TunnelState+UI.swift index 79fccbb020..1310adb549 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelState+UI.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelState+UI.swift @@ -38,130 +38,55 @@ extension TunnelState { switch self { case let .connecting(_, isPostQuantum, _), let .reconnecting(_, isPostQuantum, _): if isPostQuantum { - NSLocalizedString( - "TUNNEL_STATE_PQ_CONNECTING", - tableName: "Main", - value: "Creating quantum secure connection", - comment: "" - ) + NSLocalizedString("Creating quantum secure connection", comment: "") } else { - NSLocalizedString( - "TUNNEL_STATE_CONNECTING", - tableName: "Main", - value: "Creating secure connection", - comment: "" - ) + NSLocalizedString("Creating secure connection", comment: "") } case let .negotiatingEphemeralPeer(_, _, isPostQuantum, _): if isPostQuantum { - NSLocalizedString( - "TUNNEL_STATE_NEGOTIATING_KEY", - tableName: "Main", - value: "Creating quantum secure connection", - comment: "" - ) + NSLocalizedString("Creating quantum secure connection", comment: "") } else { - NSLocalizedString( - "TUNNEL_STATE_CONNECTING", - tableName: "Main", - value: "Creating secure connection", - comment: "" - ) + NSLocalizedString("Creating secure connection", comment: "") } case let .connected(_, isPostQuantum, _): if isPostQuantum { - NSLocalizedString( - "TUNNEL_STATE_PQ_CONNECTED", - tableName: "Main", - value: "Quantum secure connection", - comment: "" - ) + NSLocalizedString("Quantum secure connection", comment: "") } else { - NSLocalizedString( - "TUNNEL_STATE_CONNECTED", - tableName: "Main", - value: "Connected", - comment: "" - ) + NSLocalizedString("Connected", comment: "") } case .disconnecting(.nothing): - NSLocalizedString( - "TUNNEL_STATE_DISCONNECTING", - tableName: "Main", - value: "Disconnecting", - comment: "" - ) + NSLocalizedString("Disconnecting", comment: "") case .disconnecting(.reconnect), .pendingReconnect: - NSLocalizedString( - "TUNNEL_STATE_PENDING_RECONNECT", - tableName: "Main", - value: "Reconnecting", - comment: "" - ) + NSLocalizedString("Reconnecting", comment: "") case .disconnected: - NSLocalizedString( - "TUNNEL_STATE_DISCONNECTED", - tableName: "Main", - value: "Unsecured connection", - comment: "" - ) + NSLocalizedString("Unsecured connection", comment: "") case .waitingForConnectivity(.noConnection), .error: - NSLocalizedString( - "TUNNEL_STATE_WAITING_FOR_CONNECTIVITY", - tableName: "Main", - value: "Blocked connection", - comment: "" - ) + NSLocalizedString("Blocked connection", comment: "") case .waitingForConnectivity(.noNetwork): - NSLocalizedString( - "TUNNEL_STATE_NO_NETWORK", - tableName: "Main", - value: "No network", - comment: "" - ) + NSLocalizedString("No network", comment: "") } } var localizedTitleForSelectLocationButton: String { switch self { case .disconnecting(.reconnect), .pendingReconnect: - NSLocalizedString( - "SWITCH_LOCATION_BUTTON_TITLE", - tableName: "Main", - value: "Select location", - comment: "" - ) + NSLocalizedString("Select location", comment: "") case .disconnected, .disconnecting(.nothing): - NSLocalizedString( - "SELECT_LOCATION_BUTTON_TITLE", - tableName: "Main", - value: "Select location", - comment: "" - ) + NSLocalizedString("Select location", comment: "") case .connecting, .connected, .reconnecting, .waitingForConnectivity, .error: - NSLocalizedString( - "SWITCH_LOCATION_BUTTON_TITLE", - tableName: "Main", - value: "Switch location", - comment: "" - ) + NSLocalizedString("Switch location", comment: "") case .negotiatingEphemeralPeer: - NSLocalizedString( - "SWITCH_LOCATION_BUTTON_TITLE", - tableName: "Main", - value: "Switch location", - comment: "" - ) + NSLocalizedString("Switch location", comment: "") } } @@ -176,79 +101,38 @@ extension TunnelState { case let .connected(tunnelInfo, isPostQuantum, _): if isPostQuantum { String( - format: NSLocalizedString( - "TUNNEL_STATE_PQ_CONNECTED_ACCESSIBILITY_LABEL", - tableName: "Main", - value: "Quantum secure connection. Connected to %@, %@", - comment: "" - ), + format: NSLocalizedString("Quantum secure connection. Connected to %@, %@", comment: ""), tunnelInfo.exit.location.city, tunnelInfo.exit.location.country ) } else { String( - format: NSLocalizedString( - "TUNNEL_STATE_CONNECTED_ACCESSIBILITY_LABEL", - tableName: "Main", - value: "Secure connection. Connected to %@, %@", - comment: "" - ), + format: NSLocalizedString("Secure connection. Connected to %@, %@", comment: ""), tunnelInfo.exit.location.city, tunnelInfo.exit.location.country ) } case .disconnected: - NSLocalizedString( - "TUNNEL_STATE_DISCONNECTED_ACCESSIBILITY_LABEL", - tableName: "Main", - value: "Unsecured connection", - comment: "" - ) - + NSLocalizedString("Unsecured connection", comment: "") case let .reconnecting(tunnelInfo, _, _): String( - format: NSLocalizedString( - "TUNNEL_STATE_RECONNECTING_ACCESSIBILITY_LABEL", - tableName: "Main", - value: "Reconnecting to %@, %@", - comment: "" - ), + format: NSLocalizedString("Reconnecting to %@, %@", comment: ""), tunnelInfo.exit.location.city, tunnelInfo.exit.location.country ) case .waitingForConnectivity(.noConnection), .error: - NSLocalizedString( - "TUNNEL_STATE_WAITING_FOR_CONNECTIVITY_ACCESSIBILITY_LABEL", - tableName: "Main", - value: "Blocked connection", - comment: "" - ) + NSLocalizedString("Blocked connection", comment: "") case .waitingForConnectivity(.noNetwork): - NSLocalizedString( - "TUNNEL_STATE_NO_NETWORK_ACCESSIBILITY_LABEL", - tableName: "Main", - value: "No network", - comment: "" - ) + NSLocalizedString("No network", comment: "") case .disconnecting(.nothing): - NSLocalizedString( - "TUNNEL_STATE_DISCONNECTING_ACCESSIBILITY_LABEL", - tableName: "Main", - value: "Disconnecting", - comment: "" - ) + NSLocalizedString("Disconnecting", comment: "") case .disconnecting(.reconnect), .pendingReconnect: - NSLocalizedString( - "TUNNEL_STATE_PENDING_RECONNECT_ACCESSIBILITY_LABEL", - tableName: "Main", - value: "Reconnecting", - comment: "" - ) + NSLocalizedString("Reconnecting", comment: "") } } @@ -284,16 +168,12 @@ extension TunnelState { return if let entryName { String(format: NSLocalizedString( - "CONNECT_PANEL_TITLE", - tableName: "Main", - value: "%@ via %@\(usingDaita ? " using DAITA" : "")", + "%@ via %@\(usingDaita ? " using DAITA" : "")", comment: "" ), exitName, entryName) } else { String(format: NSLocalizedString( - "CONNECT_PANEL_TITLE", - tableName: "Main", - value: "%@\(usingDaita ? " using DAITA" : "")", + "%@\(usingDaita ? " using DAITA" : "")", comment: "" ), exitName) } @@ -301,19 +181,9 @@ extension TunnelState { func secureConnectionLabel(isPostQuantum: Bool) -> String { if isPostQuantum { - NSLocalizedString( - "TUNNEL_STATE_PQ_CONNECTING_ACCESSIBILITY_LABEL", - tableName: "Main", - value: "Creating quantum secure connection", - comment: "" - ) + NSLocalizedString("Creating quantum secure connection", comment: "") } else { - NSLocalizedString( - "TUNNEL_STATE_CONNECTING_ACCESSIBILITY_LABEL", - tableName: "Main", - value: "Creating secure connection", - comment: "" - ) + NSLocalizedString("Creating secure connection", comment: "") } } } diff --git a/ios/MullvadVPN/View controllers/Account/AccountContentView.swift b/ios/MullvadVPN/View controllers/Account/AccountContentView.swift index 0c8a87bd2c..f671ef074e 100644 --- a/ios/MullvadVPN/View controllers/Account/AccountContentView.swift +++ b/ios/MullvadVPN/View controllers/Account/AccountContentView.swift @@ -12,70 +12,40 @@ class AccountContentView: UIView { let purchaseButton: InAppPurchaseButton = { let button = InAppPurchaseButton() button.setAccessibilityIdentifier(.purchaseButton) - button.setTitle(NSLocalizedString( - "ADD_TIME_BUTTON_TITLE", - tableName: "Account", - value: "Add time", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Add time", comment: ""), for: .normal) return button }() let storeKit2PurchaseButton: AppButton = { let button = AppButton(style: .success) - button.setTitle(NSLocalizedString( - "BUY_SUBSCRIPTION_STOREKIT_2", - tableName: "Account", - value: "Make a purchase with StoreKit2", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Make a purchase with StoreKit2", comment: ""), for: .normal) return button }() let storeKit2RefundButton: AppButton = { let button = AppButton(style: .success) - button.setTitle(NSLocalizedString( - "BUY_SUBSCRIPTION_STOREKIT_2", - tableName: "Account", - value: "Refund last purchase with StoreKit2", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Refund last purchase with StoreKit2", comment: ""), for: .normal) return button }() let redeemVoucherButton: AppButton = { let button = AppButton(style: .success) button.setAccessibilityIdentifier(.redeemVoucherButton) - button.setTitle(NSLocalizedString( - "REDEEM_VOUCHER_BUTTON_TITLE", - tableName: "Account", - value: "Redeem voucher", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Redeem voucher", comment: ""), for: .normal) return button }() let logoutButton: AppButton = { let button = AppButton(style: .danger) button.setAccessibilityIdentifier(.logoutButton) - button.setTitle(NSLocalizedString( - "LOGOUT_BUTTON_TITLE", - tableName: "Account", - value: "Log out", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Log out", comment: ""), for: .normal) return button }() let deleteButton: AppButton = { let button = AppButton(style: .danger) button.setAccessibilityIdentifier(.deleteButton) - button.setTitle(NSLocalizedString( - "DELETE_BUTTON_TITLE", - tableName: "Account", - value: "Delete account", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Delete account", comment: ""), for: .normal) return button }() diff --git a/ios/MullvadVPN/View controllers/Account/AccountDeviceRow.swift b/ios/MullvadVPN/View controllers/Account/AccountDeviceRow.swift index 07cac860f1..a8643b4c76 100644 --- a/ios/MullvadVPN/View controllers/Account/AccountDeviceRow.swift +++ b/ios/MullvadVPN/View controllers/Account/AccountDeviceRow.swift @@ -21,12 +21,7 @@ class AccountDeviceRow: UIView { private let titleLabel: UILabel = { let label = UILabel() - label.text = NSLocalizedString( - "DEVICE_NAME", - tableName: "Account", - value: "Device name", - comment: "" - ) + label.text = NSLocalizedString("Device name", comment: "") label.font = .mullvadTiny label.adjustsFontForContentSizeCategory = true label.textColor = UIColor(white: 1.0, alpha: 0.6) @@ -54,12 +49,7 @@ class AccountDeviceRow: UIView { .foregroundColor: UIColor.primaryTextColor, .underlineStyle: NSUnderlineStyle.single.rawValue, ] - let title = NSLocalizedString( - "DEVICE_MANAGEMENT", - tableName: "Account", - value: "Manage devices", - comment: "" - ) + let title = NSLocalizedString("Manage devices", comment: "") button.attributedText = NSMutableAttributedString( string: title, attributes: attributes diff --git a/ios/MullvadVPN/View controllers/Account/AccountExpiryRow.swift b/ios/MullvadVPN/View controllers/Account/AccountExpiryRow.swift index 7133739466..847f468f2c 100644 --- a/ios/MullvadVPN/View controllers/Account/AccountExpiryRow.swift +++ b/ios/MullvadVPN/View controllers/Account/AccountExpiryRow.swift @@ -15,12 +15,7 @@ class AccountExpiryRow: UIView { let expiry = value if let expiry, expiry <= Date() { - let localizedString = NSLocalizedString( - "ACCOUNT_OUT_OF_TIME_LABEL", - tableName: "Account", - value: "OUT OF TIME", - comment: "" - ) + let localizedString = NSLocalizedString("OUT OF TIME", comment: "") valueLabel.text = localizedString accessibilityValue = localizedString @@ -46,12 +41,7 @@ class AccountExpiryRow: UIView { private let textLabel: UILabel = { let textLabel = UILabel() textLabel.translatesAutoresizingMaskIntoConstraints = false - textLabel.text = NSLocalizedString( - "ACCOUNT_EXPIRY_LABEL", - tableName: "Account", - value: "Paid until", - comment: "" - ) + textLabel.text = NSLocalizedString("Paid until", comment: "") textLabel.font = .mullvadTiny textLabel.numberOfLines = 0 textLabel.adjustsFontForContentSizeCategory = true diff --git a/ios/MullvadVPN/View controllers/Account/AccountNumberRow.swift b/ios/MullvadVPN/View controllers/Account/AccountNumberRow.swift index c9d13e4058..152e555ce0 100644 --- a/ios/MullvadVPN/View controllers/Account/AccountNumberRow.swift +++ b/ios/MullvadVPN/View controllers/Account/AccountNumberRow.swift @@ -26,12 +26,7 @@ class AccountNumberRow: UIView { private let titleLabel: UILabel = { let textLabel = UILabel() - textLabel.text = NSLocalizedString( - "ACCOUNT_TOKEN_LABEL", - tableName: "Account", - value: "Account number", - comment: "" - ) + textLabel.text = NSLocalizedString("Account number", comment: "") textLabel.font = .mullvadTiny textLabel.adjustsFontForContentSizeCategory = true textLabel.textColor = UIColor(white: 1.0, alpha: 0.6) @@ -168,12 +163,7 @@ class AccountNumberRow: UIView { if isObscured { return NSAttributedString( - string: NSLocalizedString( - "ACCOUNT_ACCESSIBILITY_OBSCURED", - tableName: "Account", - value: "Obscured", - comment: "" - ) + string: NSLocalizedString("Obscured", comment: "") ) } else { return NSAttributedString( @@ -193,12 +183,7 @@ class AccountNumberRow: UIView { selector: #selector(didTapShowHideAccount) ), UIAccessibilityCustomAction( - name: NSLocalizedString( - "ACCOUNT_ACCESSIBILITY_COPY_TO_PASTEBOARD", - tableName: "Account", - value: "Copy to pasteboard", - comment: "" - ), + name: NSLocalizedString("Copy to pasteboard", comment: ""), target: self, selector: #selector(didTapCopyAccountNumber) ), @@ -207,19 +192,9 @@ class AccountNumberRow: UIView { private var showHideAccessibilityActionName: String { if isObscured { - return NSLocalizedString( - "ACCOUNT_ACCESSIBILITY_SHOW_ACCOUNT_NUMBER", - tableName: "Account", - value: "Show account number", - comment: "" - ) + return NSLocalizedString("Show account number", comment: "") } else { - return NSLocalizedString( - "ACCOUNT_ACCESSIBILITY_HIDE_ACCOUNT_NUMBER", - tableName: "Account", - value: "Hide account number", - comment: "" - ) + return NSLocalizedString("Hide account number", comment: "") } } diff --git a/ios/MullvadVPN/View controllers/Account/AccountViewController.swift b/ios/MullvadVPN/View controllers/Account/AccountViewController.swift index 831839ac50..e3fd297f0d 100644 --- a/ios/MullvadVPN/View controllers/Account/AccountViewController.swift +++ b/ios/MullvadVPN/View controllers/Account/AccountViewController.swift @@ -64,12 +64,7 @@ class AccountViewController: UIViewController, @unchecked Sendable { super.viewDidLoad() view.backgroundColor = .secondaryColor - navigationItem.title = NSLocalizedString( - "NAVIGATION_TITLE", - tableName: "Account", - value: "Account", - comment: "" - ) + navigationItem.title = NSLocalizedString("Account", comment: "") navigationItem.rightBarButtonItem = UIBarButtonItem( barButtonSystemItem: .done, diff --git a/ios/MullvadVPN/View controllers/Account/PaymentAlertPresenter.swift b/ios/MullvadVPN/View controllers/Account/PaymentAlertPresenter.swift index f78ef062e0..1a9d297478 100644 --- a/ios/MullvadVPN/View controllers/Account/PaymentAlertPresenter.swift +++ b/ios/MullvadVPN/View controllers/Account/PaymentAlertPresenter.swift @@ -16,18 +16,8 @@ struct PaymentAlertPresenter { func showAlertForRefund(completion: (@MainActor @Sendable () -> Void)? = nil) { let presentation = AlertPresentation( id: "payment-refund-alert", - title: NSLocalizedString( - "PAYMENT_REFUND_ALERT_TITLE", - tableName: "Payment", - value: "Refund successful", - comment: "" - ), - message: NSLocalizedString( - "PAYMENT_REFUND_ALERT_MESSAGE", - tableName: "Payment", - value: "Your purchase was successfully refunded.", - comment: "" - ), + title: NSLocalizedString("Refund successful", comment: ""), + message: NSLocalizedString("Your purchase was successfully refunded.", comment: ""), buttons: [ AlertAction( title: okButtonTextForKey("PAYMENT_REFUND_ALERT_OK_ACTION"), @@ -121,11 +111,6 @@ struct PaymentAlertPresenter { } private func okButtonTextForKey(_ key: String) -> String { - NSLocalizedString( - key, - tableName: "Payment", - value: "Got it!", - comment: "" - ) + NSLocalizedString("Got it!", comment: "") } } diff --git a/ios/MullvadVPN/View controllers/Account/RestorePurchasesView.swift b/ios/MullvadVPN/View controllers/Account/RestorePurchasesView.swift index 64dc2dedd2..16fe1da69b 100644 --- a/ios/MullvadVPN/View controllers/Account/RestorePurchasesView.swift +++ b/ios/MullvadVPN/View controllers/Account/RestorePurchasesView.swift @@ -64,12 +64,7 @@ class RestorePurchasesView: UIView { } private func makeAttributedString() -> NSAttributedString { - let text = NSLocalizedString( - "RESTORE_PURCHASES_BUTTON_TITLE", - tableName: "Account", - value: "Restore purchases", - comment: "" - ) + let text = NSLocalizedString("Restore purchases", comment: "") return NSAttributedString(string: text, attributes: [ .font: UIFont.mullvadMini, diff --git a/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionContentView.swift b/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionContentView.swift index 6772016fba..3b8e04d258 100644 --- a/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionContentView.swift +++ b/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionContentView.swift @@ -39,12 +39,7 @@ class AccountDeletionContentView: UIView { label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping label.textColor = .white - label.text = NSLocalizedString( - "ACCOUNT_DELETION_PAGE_TITLE", - tableName: "Account", - value: "Account deletion", - comment: "" - ) + label.text = NSLocalizedString("Account deletion", comment: "") return label }() @@ -68,9 +63,7 @@ class AccountDeletionContentView: UIView { label.lineBreakMode = .byWordWrapping label.textColor = .white label.text = NSLocalizedString( - "TIP_TEXT", - tableName: "Account", - value: """ + """ This logs out all devices using this account and all \ VPN access will be denied even if there is time left on the account. \ Enter the last 4 digits of the account number and hit "Delete account" \ @@ -106,24 +99,14 @@ class AccountDeletionContentView: UIView { private let deleteButton: AppButton = { let button = AppButton(style: .danger) button.setAccessibilityIdentifier(.deleteButton) - button.setTitle(NSLocalizedString( - "DELETE_ACCOUNT_BUTTON_TITLE", - tableName: "Account", - value: "Delete Account", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Delete Account", comment: ""), for: .normal) return button }() private let cancelButton: AppButton = { let button = AppButton(style: .default) button.setAccessibilityIdentifier(.cancelButton) - button.setTitle(NSLocalizedString( - "CANCEL_BUTTON_TITLE", - tableName: "Account", - value: "Cancel", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Cancel", comment: ""), for: .normal) return button }() @@ -219,12 +202,7 @@ class AccountDeletionContentView: UIView { case let .failure(error): return error.localizedDescription case .loading: - return NSLocalizedString( - "DELETE_ACCOUNT_STATUS_WAITING", - tableName: "Account", - value: "Deleting account...", - comment: "" - ) + return NSLocalizedString("Deleting account...", comment: "") default: return "" } } @@ -324,9 +302,7 @@ class AccountDeletionContentView: UIView { private func updateData() { viewModel.flatMap { viewModel in let text = NSLocalizedString( - "BODY_LABEL_TEXT", - tableName: "Account", - value: """ + """ Are you sure you want to delete account **\(viewModel.accountNumber)**? """, comment: "" diff --git a/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionInteractor.swift b/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionInteractor.swift index 112deb46fc..7935ead5bb 100644 --- a/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionInteractor.swift +++ b/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionInteractor.swift @@ -16,12 +16,7 @@ enum AccountDeletionError: LocalizedError { var errorDescription: String? { switch self { case .invalidInput: - return NSLocalizedString( - "INVALID_ACCOUNT_NUMBER", - tableName: "Account", - value: "Last four digits of the account number are incorrect", - comment: "" - ) + return NSLocalizedString("Last four digits of the account number are incorrect", comment: "") } } } diff --git a/ios/MullvadVPN/View controllers/CreationAccount/Completed/SetupAccountCompletedContentView.swift b/ios/MullvadVPN/View controllers/CreationAccount/Completed/SetupAccountCompletedContentView.swift index 6309deba54..9796aace27 100644 --- a/ios/MullvadVPN/View controllers/CreationAccount/Completed/SetupAccountCompletedContentView.swift +++ b/ios/MullvadVPN/View controllers/CreationAccount/Completed/SetupAccountCompletedContentView.swift @@ -21,12 +21,7 @@ class SetupAccountCompletedContentView: UIView { label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping label.numberOfLines = .zero - label.text = NSLocalizedString( - "CREATED_ACCOUNT_CONFIRMATION_PAGE_TITLE", - tableName: "CreatedAccountConfirmation", - value: "You’re all set!!", - comment: "" - ) + label.text = NSLocalizedString("You’re all set!!", comment: "") return label }() @@ -34,9 +29,7 @@ class SetupAccountCompletedContentView: UIView { let label = UILabel() let message = NSMutableAttributedString(string: NSLocalizedString( - "CREATED_ACCOUNT_CONFIRMATION_PAGE_BODY", - tableName: "CreatedAccountConfirmation", - value: """ + """ Go ahead and start using the app to begin reclaiming your online privacy. To continue your journey as a privacy ninja, \ visit our website to pick up other privacy-friendly habits and tools. @@ -57,12 +50,7 @@ class SetupAccountCompletedContentView: UIView { private let privacyButton: AppButton = { let button = AppButton(style: .success) button.setAccessibilityIdentifier(.learnAboutPrivacyButton) - let localizedString = NSLocalizedString( - "LEARN_ABOUT_PRIVACY_BUTTON", - tableName: "CreatedAccountConfirmation", - value: "Learn about privacy", - comment: "" - ) + let localizedString = NSLocalizedString("Learn about privacy", comment: "") button.setTitle(localizedString, for: .normal) button.setImage(UIImage(named: "IconExtlink")?.imageFlippedForRightToLeftLayoutDirection(), for: .normal) return button @@ -71,12 +59,7 @@ class SetupAccountCompletedContentView: UIView { private let startButton: AppButton = { let button = AppButton(style: .success) button.setAccessibilityIdentifier(.startUsingTheAppButton) - button.setTitle(NSLocalizedString( - "START_USING_THE_APP_BUTTON", - tableName: "CreatedAccountConfirmation", - value: "Start using the app", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Start using the app", comment: ""), for: .normal) return button }() diff --git a/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift b/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift index b00187d8c9..dd401958d3 100644 --- a/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift +++ b/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift @@ -29,12 +29,7 @@ final class WelcomeContentView: UIView, Sendable { label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping label.numberOfLines = .zero - label.text = NSLocalizedString( - "WELCOME_PAGE_TITLE", - tableName: "Welcome", - value: "Congrats!", - comment: "" - ) + label.text = NSLocalizedString("Congrats!", comment: "") return label }() @@ -45,12 +40,7 @@ final class WelcomeContentView: UIView, Sendable { label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping label.numberOfLines = .zero - label.text = NSLocalizedString( - "WELCOME_PAGE_SUBTITLE", - tableName: "Welcome", - value: "Here’s your account number. Save it!", - comment: "" - ) + label.text = NSLocalizedString("Here’s your account number. Save it!", comment: "") return label }() @@ -107,9 +97,7 @@ final class WelcomeContentView: UIView, Sendable { label.lineBreakMode = .byWordWrapping label.lineBreakStrategy = [] label.text = NSLocalizedString( - "WELCOME_PAGE_DESCRIPTION", - tableName: "Welcome", - value: """ + """ To start using the app, you first need to \ add time to your account. Either buy credit \ on our website or redeem a voucher. @@ -122,12 +110,7 @@ final class WelcomeContentView: UIView, Sendable { private let purchaseButton: InAppPurchaseButton = { let button = InAppPurchaseButton() button.setAccessibilityIdentifier(.purchaseButton) - let localizedString = NSLocalizedString( - "ADD_TIME_BUTTON", - tableName: "Welcome", - value: "Add time", - comment: "" - ) + let localizedString = NSLocalizedString("Add time", comment: "") button.setTitle(localizedString, for: .normal) return button }() @@ -171,12 +154,10 @@ final class WelcomeContentView: UIView, Sendable { var viewModel: WelcomeViewModel? { didSet { accountNumberLabel.text = viewModel?.accountNumber - deviceNameLabel.text = String(format: NSLocalizedString( - "DEVICE_NAME_TEXT", - tableName: "Welcome", - value: "Device name: %@", - comment: "" - ), viewModel?.deviceName ?? "") + deviceNameLabel.text = String( + format: NSLocalizedString("Device name: %@", comment: ""), + viewModel?.deviceName ?? "" + ) } } diff --git a/ios/MullvadVPN/View controllers/InAppPurchase/InAppPurchaseViewController.swift b/ios/MullvadVPN/View controllers/InAppPurchase/InAppPurchaseViewController.swift index 03cd30bf64..f4491addd0 100644 --- a/ios/MullvadVPN/View controllers/InAppPurchase/InAppPurchaseViewController.swift +++ b/ios/MullvadVPN/View controllers/InAppPurchase/InAppPurchaseViewController.swift @@ -101,12 +101,7 @@ class InAppPurchaseViewController: UIViewController, StorePaymentObserver { } func showPurchaseOptions(for products: [SKProduct]) { - let localizedString = NSLocalizedString( - "ADD_TIME_BUTTON", - tableName: "Welcome", - value: "Add Time", - comment: "" - ) + let localizedString = NSLocalizedString("Add Time", comment: "") let sheetController = UIAlertController( title: localizedString, message: nil, @@ -127,12 +122,7 @@ class InAppPurchaseViewController: UIViewController, StorePaymentObserver { sheetController.addAction(action) } - let cancelAction = UIAlertAction(title: NSLocalizedString( - "SHEET_CANCEL_BUTTON", - tableName: "ActionSheet", - value: "Cancel", - comment: "" - ), style: .cancel) { _ in + let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { _ in self.didFinish?() } cancelAction.accessibilityIdentifier = "actoin-sheet-cancel-button" diff --git a/ios/MullvadVPN/View controllers/Login/AccountInputGroupView.swift b/ios/MullvadVPN/View controllers/Login/AccountInputGroupView.swift index 13c6a8d684..221d07bc86 100644 --- a/ios/MullvadVPN/View controllers/Login/AccountInputGroupView.swift +++ b/ios/MullvadVPN/View controllers/Login/AccountInputGroupView.swift @@ -25,12 +25,7 @@ final class AccountInputGroupView: UIView { button.setImage(UIImage.Buttons.rightArrow, for: .normal) button.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) button.setAccessibilityIdentifier(.loginTextFieldButton) - button.accessibilityLabel = NSLocalizedString( - "ACCOUNT_INPUT_LOGIN_BUTTON_ACCESSIBILITY_LABEL", - tableName: "AccountInput", - value: "Log in", - comment: "" - ) + button.accessibilityLabel = NSLocalizedString("Log in", comment: "") return button }() @@ -97,12 +92,7 @@ final class AccountInputGroupView: UIView { button.translatesAutoresizingMaskIntoConstraints = false button.contentHorizontalAlignment = .leading button.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - button.accessibilityLabel = NSLocalizedString( - "LAST_USED_ACCOUNT_ACCESSIBILITY_LABEL", - tableName: "AccountInput", - value: "Last used account", - comment: "" - ) + button.accessibilityLabel = NSLocalizedString("Last used account", comment: "") button.configuration?.contentInsets = UIMetrics.textFieldMargins.toDirectionalInsets button.configuration?.title = " " button.configuration? @@ -120,12 +110,7 @@ final class AccountInputGroupView: UIView { let button = CustomButton() button.translatesAutoresizingMaskIntoConstraints = false button.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) - button.accessibilityLabel = NSLocalizedString( - "REMOVE_LAST_USED_ACCOUNT_ACCESSIBILITY_LABEL", - tableName: "AccountInput", - value: "Remove last used account", - comment: "" - ) + button.accessibilityLabel = NSLocalizedString("Remove last used account", comment: "") button.configuration?.image = UIImage.Buttons.closeSmall.withTintColor(.primaryColor) button.configuration?.title = " " return button diff --git a/ios/MullvadVPN/View controllers/Login/LoginContentView.swift b/ios/MullvadVPN/View controllers/Login/LoginContentView.swift index 74c4dd1bc0..bb6fef965e 100644 --- a/ios/MullvadVPN/View controllers/Login/LoginContentView.swift +++ b/ios/MullvadVPN/View controllers/Login/LoginContentView.swift @@ -78,12 +78,7 @@ class LoginContentView: UIView { textLabel.translatesAutoresizingMaskIntoConstraints = false textLabel.adjustsFontForContentSizeCategory = true textLabel.numberOfLines = 0 - textLabel.text = NSLocalizedString( - "CREATE_BUTTON_HEADER_LABEL", - tableName: "Login", - value: "Don’t have an account number?", - comment: "" - ) + textLabel.text = NSLocalizedString("Don’t have an account number?", comment: "") textLabel.numberOfLines = 0 return textLabel }() @@ -92,12 +87,7 @@ class LoginContentView: UIView { let button = AppButton(style: .default) button.setAccessibilityIdentifier(.createAccountButton) button.translatesAutoresizingMaskIntoConstraints = false - button.setTitle(NSLocalizedString( - "CREATE_ACCOUNT_BUTTON_LABEL", - tableName: "Login", - value: "Create account", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Create account", comment: ""), for: .normal) return button }() diff --git a/ios/MullvadVPN/View controllers/Login/LoginViewController.swift b/ios/MullvadVPN/View controllers/Login/LoginViewController.swift index 533c34ae74..0dc0b53622 100644 --- a/ios/MullvadVPN/View controllers/Login/LoginViewController.swift +++ b/ios/MullvadVPN/View controllers/Login/LoginViewController.swift @@ -49,12 +49,7 @@ class LoginViewController: UIViewController, RootContainment { private lazy var accountInputAccessoryLoginButton: UIBarButtonItem = { let barButtonItem = UIBarButtonItem( - title: NSLocalizedString( - "LOGIN_ACCESSORY_TOOLBAR_BUTTON_TITLE", - tableName: "Login", - value: "Log in", - comment: "" - ), + title: NSLocalizedString("Log in", comment: ""), style: .done, target: self, action: #selector(doLogin) @@ -320,65 +315,30 @@ private extension LoginState { var localizedTitle: String { switch self { case .default: - return NSLocalizedString( - "HEADING_TITLE_DEFAULT", - tableName: "Login", - value: "Login", - comment: "" - ) + return NSLocalizedString("Login", comment: "") case .authenticating: - return NSLocalizedString( - "HEADING_TITLE_AUTHENTICATING", - tableName: "Login", - value: "Logging in...", - comment: "" - ) + return NSLocalizedString("Logging in...", comment: "") case .failure: - return NSLocalizedString( - "HEADING_TITLE_FAILURE", - tableName: "Login", - value: "Login failed", - comment: "" - ) + return NSLocalizedString("Login failed", comment: "") case .success: - return NSLocalizedString( - "HEADING_TITLE_SUCCESS", - tableName: "Login", - value: "Logged in", - comment: "" - ) + return NSLocalizedString("Logged in", comment: "") } } var localizedMessage: String { switch self { case .default: - return NSLocalizedString( - "SUBHEAD_TITLE_DEFAULT", - tableName: "Login", - value: "Enter your account number", - comment: "" - ) + return NSLocalizedString("Enter your account number", comment: "") case let .authenticating(method): switch method { case .useExistingAccount: - return NSLocalizedString( - "SUBHEAD_TITLE_AUTHENTICATING", - tableName: "Login", - value: "Checking account number", - comment: "" - ) + return NSLocalizedString("Checking account number", comment: "") case .createAccount: - return NSLocalizedString( - "SUBHEAD_TITLE_CREATING_ACCOUNT", - tableName: "Login", - value: "Creating new account", - comment: "" - ) + return NSLocalizedString("Creating new account", comment: "") } case let .failure(_, error): @@ -387,19 +347,9 @@ private extension LoginState { case let .success(method): switch method { case .useExistingAccount: - return NSLocalizedString( - "SUBHEAD_TITLE_SUCCESS", - tableName: "Login", - value: "Correct account number", - comment: "" - ) + return NSLocalizedString("Correct account number", comment: "") case .createAccount: - return NSLocalizedString( - "SUBHEAD_TITLE_CREATED_ACCOUNT", - tableName: "Login", - value: "Account created", - comment: "" - ) + return NSLocalizedString("Account created", comment: "") } } } diff --git a/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeContentView.swift b/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeContentView.swift index 33d4f8d10b..d169c65c08 100644 --- a/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeContentView.swift +++ b/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeContentView.swift @@ -18,12 +18,7 @@ class OutOfTimeContentView: UIView { private lazy var titleLabel: UILabel = { let label = UILabel() - label.text = NSLocalizedString( - "OUT_OF_TIME_TITLE", - tableName: "OutOfTime", - value: "Out of time", - comment: "" - ) + label.text = NSLocalizedString("Out of time", comment: "") label.font = .mullvadLarge label.adjustsFontForContentSizeCategory = true label.textColor = .white @@ -42,12 +37,7 @@ class OutOfTimeContentView: UIView { let button = AppButton(style: .danger) button.translatesAutoresizingMaskIntoConstraints = false button.alpha = 0 - let localizedString = NSLocalizedString( - "OUT_OF_TIME_DISCONNECT_BUTTON", - tableName: "OutOfTime", - value: "Disconnect", - comment: "" - ) + let localizedString = NSLocalizedString("Disconnect", comment: "") button.setTitle(localizedString, for: .normal) return button }() @@ -55,12 +45,7 @@ class OutOfTimeContentView: UIView { lazy var purchaseButton: InAppPurchaseButton = { let button = InAppPurchaseButton() button.translatesAutoresizingMaskIntoConstraints = false - let localizedString = NSLocalizedString( - "OUT_OF_TIME_PURCHASE_BUTTON", - tableName: "OutOfTime", - value: "Add time", - comment: "" - ) + let localizedString = NSLocalizedString("Add time", comment: "") button.setTitle(localizedString, for: .normal) return button }() @@ -68,12 +53,7 @@ class OutOfTimeContentView: UIView { lazy var restoreButton: AppButton = { let button = AppButton(style: .default) button.translatesAutoresizingMaskIntoConstraints = false - button.setTitle(NSLocalizedString( - "RESTORE_PURCHASES_BUTTON_TITLE", - tableName: "OutOfTime", - value: "Restore purchases", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Restore purchases", comment: ""), for: .normal) return button }() diff --git a/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeViewController.swift b/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeViewController.swift index 4a9906a429..21914abc27 100644 --- a/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeViewController.swift +++ b/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeViewController.swift @@ -111,9 +111,7 @@ class OutOfTimeViewController: UIViewController, RootContainment { if tunnelState.isSecured { contentView.setBodyLabelText( NSLocalizedString( - "OUT_OF_TIME_BODY_CONNECTED", - tableName: "OutOfTime", - value: """ + """ You have no more VPN time left on this account. To add more, you will need to \ disconnect and access the Internet with an unsecure connection. """, @@ -123,9 +121,7 @@ class OutOfTimeViewController: UIViewController, RootContainment { } else { contentView.setBodyLabelText( NSLocalizedString( - "OUT_OF_TIME_BODY_DISCONNECTED", - tableName: "OutOfTime", - value: """ + """ You have no more VPN time left on this account. Either buy credit on our website \ or make an in-app purchase via the **Add time** button below. """, diff --git a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportReviewViewController.swift b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportReviewViewController.swift index 939e782af8..fb689abe57 100644 --- a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportReviewViewController.swift +++ b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportReviewViewController.swift @@ -32,12 +32,7 @@ class ProblemReportReviewViewController: UIViewController { view.backgroundColor = .secondaryColor view.setAccessibilityIdentifier(.appLogsView) - navigationItem.title = NSLocalizedString( - "NAVIGATION_TITLE", - tableName: "ProblemReportReview", - value: "App logs", - comment: "" - ) + navigationItem.title = NSLocalizedString("App logs", comment: "") navigationItem.rightBarButtonItem = UIBarButtonItem( systemItem: .done, diff --git a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportSubmissionOverlayView.swift b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportSubmissionOverlayView.swift index 2c341f0557..bdbb9e1819 100644 --- a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportSubmissionOverlayView.swift +++ b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportSubmissionOverlayView.swift @@ -28,26 +28,11 @@ class ProblemReportSubmissionOverlayView: UIView { var title: String? { switch self { case .sending: - NSLocalizedString( - "SUBMISSION_STATUS_SENDING", - tableName: "ProblemReport", - value: "Sending...", - comment: "" - ) + NSLocalizedString("Sending...", comment: "") case .sent: - NSLocalizedString( - "SUBMISSION_STATUS_SENT", - tableName: "ProblemReport", - value: "Sent", - comment: "" - ) + NSLocalizedString("Sent", comment: "") case .failure: - NSLocalizedString( - "SUBMISSION_STATUS_FAILURE", - tableName: "ProblemReport", - value: "Failed to send", - comment: "" - ) + NSLocalizedString("Failed to send", comment: "") } } @@ -57,34 +42,19 @@ class ProblemReportSubmissionOverlayView: UIView { return nil case let .sent(email): let combinedAttributedString = NSMutableAttributedString( - string: NSLocalizedString( - "THANKS_MESSAGE", - tableName: "ProblemReport", - value: "Thanks!", - comment: "" - ) + string: NSLocalizedString("Thanks!", comment: "") ) if email.isEmpty { combinedAttributedString.append(NSAttributedString(string: " ")) combinedAttributedString.append( NSAttributedString( - string: NSLocalizedString( - "WE_WILL_LOOK_INTO_THIS_MESSAGE", - tableName: "ProblemReport", - value: "We will look into this.", - comment: "" - ) + string: NSLocalizedString("We will look into this.", comment: "") ) ) } else { let emailText = String( - format: NSLocalizedString( - "CONTACT_BACK_EMAIL_MESSAGE_FORMAT", - tableName: "ProblemReport", - value: "If needed we will contact you at %@", - comment: "" - ), email + format: NSLocalizedString("If needed we will contact you at %@", comment: ""), email ) let emailAttributedString = NSMutableAttributedString(string: emailText) if let emailRange = emailText.range(of: email) { @@ -104,9 +74,6 @@ class ProblemReportSubmissionOverlayView: UIView { return [ NSAttributedString( string: NSLocalizedString( - "MESSAGE_FAILED_PART_1", - tableName: "ProblemReport", - value: """ If you exit the form and try again later, the information you already entered will still \ be here. @@ -115,16 +82,13 @@ class ProblemReportSubmissionOverlayView: UIView { ) ), NSAttributedString( - markdownString: NSLocalizedString( - "MESSAGE_FAILED_PART_2", - tableName: "ProblemReport", - value: + markdownString: String(format: NSLocalizedString( """ If you still experience issues you can email our support directly at \ - **\(supportEmail)**. Please attach your app log to your email. + **%@**. Please attach your app log to your email. """, comment: "" - ), + ), supportEmail), options: MarkdownStylingOptions( font: .preferredFont(forTextStyle: .body) ), applyEffect: { _, _ in @@ -201,12 +165,7 @@ class ProblemReportSubmissionOverlayView: UIView { private lazy var cancelButton: AppButton = { let button = AppButton(style: .default) button.translatesAutoresizingMaskIntoConstraints = false - button.setTitle(NSLocalizedString( - "CANCEL_BUTTON", - tableName: "ProblemReport", - value: "Cancel", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Cancel", comment: ""), for: .normal) button.addTarget(self, action: #selector(handleCancelButton), for: .touchUpInside) return button }() @@ -214,12 +173,7 @@ class ProblemReportSubmissionOverlayView: UIView { private lazy var editMessageButton: AppButton = { let button = AppButton(style: .default) button.translatesAutoresizingMaskIntoConstraints = false - button.setTitle(NSLocalizedString( - "EDIT_MESSAGE_BUTTON", - tableName: "ProblemReport", - value: "Edit message", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Edit message", comment: ""), for: .normal) button.addTarget(self, action: #selector(handleEditButton), for: .touchUpInside) return button }() @@ -227,12 +181,7 @@ class ProblemReportSubmissionOverlayView: UIView { private lazy var tryAgainButton: AppButton = { let button = AppButton(style: .success) button.translatesAutoresizingMaskIntoConstraints = false - button.setTitle(NSLocalizedString( - "TRY_AGAIN_BUTTON", - tableName: "ProblemReport", - value: "Try again", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Try again", comment: ""), for: .normal) button.addTarget(self, action: #selector(handleRetryButton), for: .touchUpInside) return button }() diff --git a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportViewModel.swift b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportViewModel.swift index e6537ec46b..e7113b2b2c 100644 --- a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportViewModel.swift +++ b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportViewModel.swift @@ -12,17 +12,10 @@ struct ProblemReportViewModel { let email: String let message: String - static let navigationTitle = NSLocalizedString( - "NAVIGATION_TITLE", - tableName: "ProblemReport", - value: "Report a problem", - comment: "" - ) + static let navigationTitle = NSLocalizedString("Report a problem", comment: "") static let subheadLabelText = NSLocalizedString( - "SUBHEAD_LABEL", - tableName: "ProblemReport", - value: """ + """ To help you more effectively, your app’s log file will be attached to \ this message. Your data will remain secure and private, as it is anonymised \ before being sent over an encrypted channel. @@ -30,60 +23,31 @@ struct ProblemReportViewModel { comment: "" ) - static let emailPlaceholderText = NSLocalizedString( - "EMAIL_TEXTFIELD_PLACEHOLDER", - tableName: "ProblemReport", - value: "Your email (optional)", - comment: "" - ) + static let emailPlaceholderText = NSLocalizedString("Your email (optional)", comment: "") static let messageTextViewPlaceholder = NSLocalizedString( - "DESCRIPTION_TEXTVIEW_PLACEHOLDER", - tableName: "ProblemReport", - value: """ + """ To assist you better, please write in English or Swedish and \ include which country you are connecting from. """, comment: "" ) - static let viewLogsButtonTitle = NSLocalizedString( - "VIEW_APP_LOGS_BUTTON_TITLE", - tableName: "ProblemReport", - value: "View app logs", - comment: "" - ) + static let viewLogsButtonTitle = NSLocalizedString("View app logs", comment: "") - static let sendLogsButtonTitle = NSLocalizedString( - "SEND_BUTTON_TITLE", - tableName: "ProblemReport", - value: "Send", - comment: "" - ) + static let sendLogsButtonTitle = NSLocalizedString("Send", comment: "") static let emptyEmailAlertWarning = NSLocalizedString( - "EMPTY_EMAIL_ALERT_MESSAGE", - tableName: "ProblemReport", - value: """ + """ You are about to send the problem report without a way for us to get back to you. \ If you want an answer to your report you will have to enter an email address. """, comment: "" ) - static let confirmEmptyEmailTitle = NSLocalizedString( - "EMPTY_EMAIL_ALERT_SEND_ANYWAY_ACTION", - tableName: "ProblemReport", - value: "Send anyway", - comment: "" - ) + static let confirmEmptyEmailTitle = NSLocalizedString("Send anyway", comment: "") - static let cancelEmptyEmailTitle = NSLocalizedString( - "EMPTY_EMAIL_ALERT_CANCEL_ACTION", - tableName: "ProblemReport", - value: "Cancel", - comment: "" - ) + static let cancelEmptyEmailTitle = NSLocalizedString("Cancel", comment: "") init() { email = "" diff --git a/ios/MullvadVPN/View controllers/RedeemVoucher/AddCreditSucceededViewController.swift b/ios/MullvadVPN/View controllers/RedeemVoucher/AddCreditSucceededViewController.swift index 06c7f1ef08..a2e989462f 100644 --- a/ios/MullvadVPN/View controllers/RedeemVoucher/AddCreditSucceededViewController.swift +++ b/ios/MullvadVPN/View controllers/RedeemVoucher/AddCreditSucceededViewController.swift @@ -77,12 +77,7 @@ class AddCreditSucceededViewController: UIViewController, RootContainment { view.directionalLayoutMargins = UIMetrics.contentLayoutMargins messageLabel.text = String( - format: NSLocalizedString( - "ADDED_TIME_SUCCESS_MESSAGE", - tableName: "AddedTime", - value: "%@ were added to your account.", - comment: "" - ), + format: NSLocalizedString("%@ were added to your account.", comment: ""), timeAddedComponents.formattedAddedDay ) } diff --git a/ios/MullvadVPN/View controllers/RedeemVoucher/LogoutDialogueView.swift b/ios/MullvadVPN/View controllers/RedeemVoucher/LogoutDialogueView.swift index a01da9eaa4..b56acc1754 100644 --- a/ios/MullvadVPN/View controllers/RedeemVoucher/LogoutDialogueView.swift +++ b/ios/MullvadVPN/View controllers/RedeemVoucher/LogoutDialogueView.swift @@ -22,9 +22,7 @@ class LogoutDialogueView: UIView { let label = UILabel() let message = NSMutableAttributedString(string: NSLocalizedString( - "ACCOUNT_NUMBER_AS_VOUCHER_INPUT_ERROR_BODY", - tableName: "CreateAccountRedeemingVoucher", - value: """ + """ It looks like you have entered a Mullvad account number instead of a voucher code. \ Do you want to log in to an existing account? If so, click log out below to log in with the other account number. @@ -43,12 +41,7 @@ class LogoutDialogueView: UIView { private let logoutButton: AppButton = { let button = AppButton(style: .danger) - button.setTitle(NSLocalizedString( - "LOGOUT_BUTTON_TITLE", - tableName: "CreateAccountRedeemingVoucher", - value: "Log out", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Log out", comment: ""), for: .normal) return button }() diff --git a/ios/MullvadVPN/View controllers/RedeemVoucher/RedeemVoucherContentView.swift b/ios/MullvadVPN/View controllers/RedeemVoucher/RedeemVoucherContentView.swift index 16dceaf257..89fcc7004b 100644 --- a/ios/MullvadVPN/View controllers/RedeemVoucher/RedeemVoucherContentView.swift +++ b/ios/MullvadVPN/View controllers/RedeemVoucher/RedeemVoucherContentView.swift @@ -35,12 +35,7 @@ final class RedeemVoucherContentView: UIView { private let title: UILabel = { let label = UILabel() label.font = .mullvadLarge - label.text = NSLocalizedString( - "REDEEM_VOUCHER_TITLE", - tableName: "RedeemVoucher", - value: "Redeem voucher", - comment: "" - ) + label.text = NSLocalizedString("Redeem voucher", comment: "") label.textColor = .white label.numberOfLines = 0 label.adjustsFontForContentSizeCategory = true @@ -51,12 +46,7 @@ final class RedeemVoucherContentView: UIView { let label = UILabel() label.font = .mullvadTinySemiBold - label.text = NSLocalizedString( - "REDEEM_VOUCHER_INSTRUCTION", - tableName: "RedeemVoucher", - value: "Enter voucher code", - comment: "" - ) + label.text = NSLocalizedString("Enter voucher code", comment: "") label.textColor = .white label.numberOfLines = 0 label.adjustsFontForContentSizeCategory = true @@ -109,23 +99,13 @@ final class RedeemVoucherContentView: UIView { private let redeemButton: AppButton = { let button = AppButton(style: .success) - button.setTitle(NSLocalizedString( - "REDEEM_VOUCHER_REDEEM_BUTTON", - tableName: "RedeemVoucher", - value: "Redeem", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Redeem", comment: ""), for: .normal) return button }() private let cancelButton: AppButton = { let button = AppButton(style: .default) - button.setTitle(NSLocalizedString( - "REDEEM_VOUCHER_CANCEL_BUTTON", - tableName: "RedeemVoucher", - value: "Cancel", - comment: "" - ), for: .normal) + button.setTitle(NSLocalizedString("Cancel", comment: ""), for: .normal) return button }() @@ -175,19 +155,9 @@ final class RedeemVoucherContentView: UIView { } return restError.description case .verifying: - return NSLocalizedString( - "REDEEM_VOUCHER_STATUS_WAITING", - tableName: "RedeemVoucher", - value: "Verifying voucher...", - comment: "" - ) + return NSLocalizedString("Verifying voucher...", comment: "") case .logout: - return NSLocalizedString( - "REDEEM_VOUCHER_STATUS_WAITING", - tableName: "RedeemVoucher", - value: "Logging out...", - comment: "" - ) + return NSLocalizedString("Logging out...", comment: "") default: return "" } } @@ -372,19 +342,9 @@ final class RedeemVoucherContentView: UIView { private extension REST.Error { var description: String { if compareErrorCode(.invalidVoucher) { - return NSLocalizedString( - "REDEEM_VOUCHER_STATUS_FAILURE", - tableName: "RedeemVoucher", - value: "Voucher code is invalid.", - comment: "" - ) + return NSLocalizedString("Voucher code is invalid.", comment: "") } else if compareErrorCode(.usedVoucher) { - return NSLocalizedString( - "REDEEM_VOUCHER_STATUS_FAILURE", - tableName: "RedeemVoucher", - value: "This voucher code has already been used.", - comment: "" - ) + return NSLocalizedString("This voucher code has already been used.", comment: "") } return displayErrorDescription ?? "" } diff --git a/ios/MullvadVPN/View controllers/RelayFilter/FilterDescriptor.swift b/ios/MullvadVPN/View controllers/RelayFilter/FilterDescriptor.swift index f50dc04c0a..5e3611e811 100644 --- a/ios/MullvadVPN/View controllers/RelayFilter/FilterDescriptor.swift +++ b/ios/MullvadVPN/View controllers/RelayFilter/FilterDescriptor.swift @@ -40,12 +40,7 @@ struct FilterDescriptor { var title: String { guard isEnabled else { - return NSLocalizedString( - "RELAY_FILTER_BUTTON_TITLE", - tableName: "RelayFilter", - value: "No matching servers", - comment: "" - ) + return NSLocalizedString("No matching servers", comment: "") } return createTitleForAvailableServers() } @@ -54,12 +49,7 @@ struct FilterDescriptor { guard settings.daita.daitaState.isEnabled else { return "" } - return NSLocalizedString( - "RELAY_FILTER_BUTTON_DESCRIPTION", - tableName: "RelayFilter", - value: "When using DAITA, one provider with DAITA-enabled servers is required.", - comment: "" - ) + return NSLocalizedString("When using DAITA, one provider with DAITA-enabled servers is required.", comment: "") } init(relayFilterResult: RelayCandidates, settings: LatestTunnelSettings) { diff --git a/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterCellFactory.swift b/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterCellFactory.swift index 80eb58c550..1cf0bd9cee 100644 --- a/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterCellFactory.swift +++ b/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterCellFactory.swift @@ -38,12 +38,7 @@ struct RelayFilterCellFactory: @preconcurrency CellFactoryProtocol { private func configureOwnershipCell(_ cell: SelectableSettingsCell?, item: RelayFilterDataSourceItem) { guard let cell = cell else { return } - cell.titleLabel.text = NSLocalizedString( - "RELAY_FILTER_CELL_LABEL", - tableName: "Relay filter ownership cell", - value: item.name, - comment: "" - ) + cell.titleLabel.text = item.name let accessibilityIdentifier: AccessibilityIdentifier switch item.type { @@ -66,12 +61,7 @@ struct RelayFilterCellFactory: @preconcurrency CellFactoryProtocol { guard let cell = cell else { return } let alpha = item.isEnabled ? 1.0 : 0.2 - cell.titleLabel.text = NSLocalizedString( - "RELAY_FILTER_CELL_LABEL", - tableName: "Relay filter provider cell", - value: item.name, - comment: "" - ) + cell.titleLabel.text = item.name cell.detailTitleLabel.text = item.description if item.type == .allProviders { diff --git a/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterDataSource.swift b/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterDataSource.swift index 12b7805ee2..328cd670a0 100644 --- a/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterDataSource.swift +++ b/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterDataSource.swift @@ -260,20 +260,15 @@ extension RelayFilterDataSource: UITableViewDelegate { switch sectionId { case .ownership: accessibilityIdentifier = .locationFilterOwnershipHeaderCell - title = "Ownership" + title = NSLocalizedString("Ownership", comment: "") case .providers: accessibilityIdentifier = .locationFilterProvidersHeaderCell - title = "Providers" + title = NSLocalizedString("Providers", comment: "") } view.isExpanded = true view.setAccessibilityIdentifier(accessibilityIdentifier) - view.titleLabel.text = NSLocalizedString( - "RELAY_FILTER_HEADER_LABEL", - tableName: "Relay filter header", - value: title, - comment: "" - ) + view.titleLabel.text = title view.didCollapseHandler = { [weak self] headerView in guard let self else { return } diff --git a/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterDataSourceItem.swift b/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterDataSourceItem.swift index 6a74626b5e..9bc2a9e338 100644 --- a/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterDataSourceItem.swift +++ b/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterDataSourceItem.swift @@ -18,36 +18,32 @@ struct RelayFilterDataSourceItem: Hashable, Comparable { case ownershipAny, ownershipOwned, ownershipRented, allProviders, provider } - static let anyOwnershipItem = RelayFilterDataSourceItem(name: NSLocalizedString( - "RELAY_FILTER_ANY_LABEL", - tableName: "RelayFilter", - value: "Any", - comment: "" - ), type: .ownershipAny, isEnabled: true) + static let anyOwnershipItem = RelayFilterDataSourceItem( + name: NSLocalizedString("Any", comment: ""), + type: .ownershipAny, + isEnabled: true + ) - static let ownedOwnershipItem = RelayFilterDataSourceItem(name: NSLocalizedString( - "RELAY_FILTER_OWNED_LABEL", - tableName: "RelayFilter", - value: "Owned", - comment: "" - ), type: .ownershipOwned, isEnabled: true) + static let ownedOwnershipItem = RelayFilterDataSourceItem( + name: NSLocalizedString("Owned", comment: ""), + type: .ownershipOwned, + isEnabled: true + ) - static let rentedOwnershipItem = RelayFilterDataSourceItem(name: NSLocalizedString( - "RELAY_FILTER_RENTED_LABEL", - tableName: "RelayFilter", - value: "Rented", - comment: "" - ), type: .ownershipRented, isEnabled: true) + static let rentedOwnershipItem = RelayFilterDataSourceItem( + name: NSLocalizedString("Rented", comment: ""), + type: .ownershipRented, + isEnabled: true + ) static let ownerships: [RelayFilterDataSourceItem] = [anyOwnershipItem, ownedOwnershipItem, rentedOwnershipItem] static var allProviders: RelayFilterDataSourceItem { - RelayFilterDataSourceItem(name: NSLocalizedString( - "RELAY_FILTER_ALL_PROVIDERS_LABEL", - tableName: "RelayFilter", - value: "All Providers", - comment: "" - ), type: .allProviders, isEnabled: true) + RelayFilterDataSourceItem( + name: NSLocalizedString("All Providers", comment: ""), + type: .allProviders, + isEnabled: true + ) } static func < (lhs: RelayFilterDataSourceItem, rhs: RelayFilterDataSourceItem) -> Bool { diff --git a/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterView.swift b/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterView.swift index 5fb0fb2a0e..dfed96cbfb 100644 --- a/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterView.swift +++ b/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterView.swift @@ -17,12 +17,7 @@ class RelayFilterView: UIView { private let titleLabel: UILabel = { let label = UILabel() - label.text = NSLocalizedString( - "RELAY_FILTER_APPLIED_TITLE", - tableName: "RelayFilter", - value: "Filtered:", - comment: "" - ) + label.text = NSLocalizedString("Filtered:", comment: "") label.font = UIFont.preferredFont(forTextStyle: .caption1) label.adjustsFontForContentSizeCategory = true label.textColor = .white @@ -59,12 +54,7 @@ class RelayFilterView: UIView { func setDaita(_ enabled: Bool) { let chip = ChipConfiguration( group: .settings, - title: NSLocalizedString( - "RELAY_FILTER_APPLIED_DAITA", - tableName: "RelayFilter", - value: "Setting: DAITA", - comment: "" - ), + title: NSLocalizedString("Setting: DAITA", comment: ""), accessibilityId: .daitaFilterPill, didTapButton: nil ) @@ -75,12 +65,7 @@ class RelayFilterView: UIView { func setObfuscation(_ enabled: Bool) { let chip = ChipConfiguration( group: .settings, - title: NSLocalizedString( - "RELAY_FILTER_APPLIED_OBFUSCATION", - tableName: "RelayFilter", - value: "Setting: Obfuscation", - comment: "" - ), + title: NSLocalizedString("Setting: Obfuscation", comment: ""), accessibilityId: .obfuscationFilterPill, didTapButton: nil ) @@ -150,12 +135,9 @@ class RelayFilterView: UIView { case .any: return nil case .owned, .rented: - let title = NSLocalizedString( - "RELAY_FILTER_APPLIED_OWNERSHIP", - tableName: "RelayFilter", - value: ownership == .owned ? "Owned" : "Rented", - comment: "" - ) + let title = ownership == .owned + ? RelayFilterDataSourceItem.ownedOwnershipItem.name + : RelayFilterDataSourceItem.rentedOwnershipItem.name return ChipConfiguration(group: .filter, title: title, didTapButton: { [weak self] in guard var filter = self?.filter else { return } filter.ownership = .any @@ -170,12 +152,7 @@ class RelayFilterView: UIView { return nil case let .only(providerList): let title = String( - format: NSLocalizedString( - "RELAY_FILTER_APPLIED_PROVIDERS", - tableName: "RelayFilter", - value: "Providers: %d", - comment: "" - ), + format: NSLocalizedString("Providers: %d", comment: ""), providerList.count ) return ChipConfiguration(group: .filter, title: title, didTapButton: { [weak self] in diff --git a/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterViewController.swift b/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterViewController.swift index d63214f9f8..8dbe6a72f2 100644 --- a/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterViewController.swift +++ b/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterViewController.swift @@ -64,12 +64,7 @@ class RelayFilterViewController: UIViewController { view.directionalLayoutMargins = UIMetrics.contentLayoutMargins view.backgroundColor = .secondaryColor - navigationItem.title = NSLocalizedString( - "RELAY_FILTER_NAVIGATION_TITLE", - tableName: "RelayFilter", - value: "Filter", - comment: "" - ) + navigationItem.title = NSLocalizedString("Filter", comment: "") navigationItem.rightBarButtonItem = UIBarButtonItem( systemItem: .cancel, diff --git a/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterViewModel.swift b/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterViewModel.swift index 3fd833bfc4..7bc28486ca 100644 --- a/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterViewModel.swift +++ b/ios/MullvadVPN/View controllers/RelayFilter/RelayFilterViewModel.swift @@ -109,12 +109,7 @@ final class RelayFilterViewModel { return RelayFilterDataSourceItem( name: providerName, description: isDaitaEnabled && isProviderEnabled - ? NSLocalizedString( - "RELAY_FILTER_PROVIDER_DESCRIPTION_FORMAT_LABEL", - tableName: "RelayFilter", - value: "DAITA-enabled", - comment: "Format for DAITA provider description" - ) + ? NSLocalizedString("DAITA-enabled", comment: "") : "", type: .provider, // If the current filter is valid, return true immediately. diff --git a/ios/MullvadVPN/View controllers/RevokedDevice/RevokedDeviceViewController.swift b/ios/MullvadVPN/View controllers/RevokedDevice/RevokedDeviceViewController.swift index 01fdc7900b..9afbee4a77 100644 --- a/ios/MullvadVPN/View controllers/RevokedDevice/RevokedDeviceViewController.swift +++ b/ios/MullvadVPN/View controllers/RevokedDevice/RevokedDeviceViewController.swift @@ -22,12 +22,7 @@ class RevokedDeviceViewController: UIViewController, RootContainment { titleLabel.adjustsFontForContentSizeCategory = true titleLabel.numberOfLines = 0 titleLabel.textColor = .white - titleLabel.text = NSLocalizedString( - "TITLE_LABEL", - tableName: "RevokedDevice", - value: "Device is inactive", - comment: "" - ) + titleLabel.text = NSLocalizedString("Device is inactive", comment: "") return titleLabel }() @@ -39,9 +34,7 @@ class RevokedDeviceViewController: UIViewController, RootContainment { bodyLabel.numberOfLines = 0 bodyLabel.textColor = .white bodyLabel.text = NSLocalizedString( - "DESCRIPTION_LABEL", - tableName: "RevokedDevice", - value: "You have removed this device. To connect again, you will need to log back in.", + "You have removed this device. To connect again, you will need to log back in.", comment: "" ) return bodyLabel @@ -54,12 +47,7 @@ class RevokedDeviceViewController: UIViewController, RootContainment { bodyLabel.adjustsFontForContentSizeCategory = true bodyLabel.numberOfLines = 0 bodyLabel.textColor = .white - bodyLabel.text = NSLocalizedString( - "UNBLOCK_INTERNET_LABEL", - tableName: "RevokedDevice", - value: "Going to login will unblock the Internet on this device.", - comment: "" - ) + bodyLabel.text = NSLocalizedString("Going to login will unblock the Internet on this device.", comment: "") return bodyLabel }() @@ -68,12 +56,7 @@ class RevokedDeviceViewController: UIViewController, RootContainment { button.setAccessibilityIdentifier(.revokedDeviceLoginButton) button.translatesAutoresizingMaskIntoConstraints = false button.setTitle( - NSLocalizedString( - "GOTO_LOGIN_BUTTON_LABEL", - tableName: "RevokedDevice", - value: "Go to login", - comment: "" - ), + NSLocalizedString("Go to login", comment: ""), for: .normal ) return button diff --git a/ios/MullvadVPN/View controllers/SelectLocation/DAITAInfoView.swift b/ios/MullvadVPN/View controllers/SelectLocation/DAITAInfoView.swift index 35e9a4e785..b4b56db8f9 100644 --- a/ios/MullvadVPN/View controllers/SelectLocation/DAITAInfoView.swift +++ b/ios/MullvadVPN/View controllers/SelectLocation/DAITAInfoView.swift @@ -19,9 +19,7 @@ class DAITAInfoView: UIView { label.attributedText = NSAttributedString( string: NSLocalizedString( - "SELECT_LOCATION_DAITA_INFO", - tableName: "SelectLocation", - value: """ + """ The entry server for multihop is currently overridden by DAITA. \ To select an entry server, please first enable “Direct only” or disable “DAITA” in the settings. """, @@ -40,12 +38,7 @@ class DAITAInfoView: UIView { let settingsButton: UIButton = { let settingsButton = AppButton(style: .default) - settingsButton.setTitle(NSLocalizedString( - "SELECT_LOCATION_DAITA_BUTTON", - tableName: "SelectLocation", - value: "Open DAITA settings", - comment: "" - ), for: .normal) + settingsButton.setTitle(NSLocalizedString("Open DAITA settings", comment: ""), for: .normal) return settingsButton }() diff --git a/ios/MullvadVPN/View controllers/SelectLocation/LocationSection.swift b/ios/MullvadVPN/View controllers/SelectLocation/LocationSection.swift index f92d86e8b3..62f3877456 100644 --- a/ios/MullvadVPN/View controllers/SelectLocation/LocationSection.swift +++ b/ios/MullvadVPN/View controllers/SelectLocation/LocationSection.swift @@ -14,35 +14,18 @@ enum LocationSection: String, Hashable, CaseIterable, CellIdentifierProtocol, Se var header: String { switch self { case .customLists: - return NSLocalizedString( - "HEADER_SELECT_LOCATION_ADD_CUSTOM_LISTS", - value: "Custom lists", - comment: "" - ) + return NSLocalizedString("Custom lists", comment: "") case .allLocations: - return NSLocalizedString( - "HEADER_SELECT_LOCATION_ALL_LOCATIONS", - value: "All locations", - comment: "" - ) + return NSLocalizedString("All locations", comment: "") } } var footer: String { switch self { case .customLists: - return NSLocalizedString( - "CUSTOM_LIST_FOOTER", - tableName: "SelectLocation", - value: "To create a custom list, tap on \"...\" ", - comment: "" - ) + return NSLocalizedString("To create a custom list, tap on \"...\" ", comment: "") case .allLocations: - return NSLocalizedString( - "FOOTER_SELECT_LOCATION_ALL_LOCATIONS", - value: "No matching relays found, check your filter settings.", - comment: "" - ) + return NSLocalizedString("No matching relays found, check your filter settings.", comment: "") } } diff --git a/ios/MullvadVPN/View controllers/SelectLocation/LocationViewController.swift b/ios/MullvadVPN/View controllers/SelectLocation/LocationViewController.swift index c3d8ed2110..072375bae2 100644 --- a/ios/MullvadVPN/View controllers/SelectLocation/LocationViewController.swift +++ b/ios/MullvadVPN/View controllers/SelectLocation/LocationViewController.swift @@ -206,12 +206,7 @@ final class LocationViewController: UIViewController { searchBar.searchBarStyle = .minimal searchBar.layer.cornerRadius = 8 searchBar.clipsToBounds = true - searchBar.placeholder = NSLocalizedString( - "SEARCHBAR_PLACEHOLDER", - tableName: "SelectLocation", - value: "Search for...", - comment: "" - ) + searchBar.placeholder = NSLocalizedString("Search for...", comment: "") searchBar.searchTextField.setAccessibilityIdentifier(.selectLocationSearchTextField) UITextField.SearchTextFieldAppearance.inactive.apply(to: searchBar) diff --git a/ios/MullvadVPN/View controllers/SelectLocation/LocationViewControllerWrapper.swift b/ios/MullvadVPN/View controllers/SelectLocation/LocationViewControllerWrapper.swift index b2e8ea61a0..ae058de96a 100644 --- a/ios/MullvadVPN/View controllers/SelectLocation/LocationViewControllerWrapper.swift +++ b/ios/MullvadVPN/View controllers/SelectLocation/LocationViewControllerWrapper.swift @@ -27,19 +27,9 @@ final class LocationViewControllerWrapper: UIViewController { var description: String { switch self { case .entry: - NSLocalizedString( - "MULTIHOP_ENTRY", - tableName: "SelectLocation", - value: "Entry", - comment: "" - ) + NSLocalizedString("Entry", comment: "") case .exit: - NSLocalizedString( - "MULTIHOP_EXIT", - tableName: "SelectLocation", - value: "Exit", - comment: "" - ) + NSLocalizedString("Exit", comment: "") } } } @@ -171,20 +161,10 @@ final class LocationViewControllerWrapper: UIViewController { private func setUpNavigation() { navigationItem.largeTitleDisplayMode = .never - navigationItem.title = NSLocalizedString( - "NAVIGATION_TITLE", - tableName: "SelectLocation", - value: "Select location", - comment: "" - ) + navigationItem.title = NSLocalizedString("Select location", comment: "") navigationItem.leftBarButtonItem = UIBarButtonItem( - title: NSLocalizedString( - "NAVIGATION_FILTER", - tableName: "SelectLocation", - value: "Filter", - comment: "" - ), + title: NSLocalizedString("Filter", comment: ""), primaryAction: UIAction(handler: { [weak self] _ in guard let self = self else { return } delegate?.navigateToFilter() diff --git a/ios/MullvadVPN/View controllers/Settings/Obfuscation/ShadowsocksObfuscationSettingsView.swift b/ios/MullvadVPN/View controllers/Settings/Obfuscation/ShadowsocksObfuscationSettingsView.swift index 164772b315..2978ad99cb 100644 --- a/ios/MullvadVPN/View controllers/Settings/Obfuscation/ShadowsocksObfuscationSettingsView.swift +++ b/ios/MullvadVPN/View controllers/Settings/Obfuscation/ShadowsocksObfuscationSettingsView.swift @@ -13,24 +13,14 @@ struct ShadowsocksObfuscationSettingsView<VM>: View where VM: ShadowsocksObfusca @StateObject var viewModel: VM var body: some View { - let portString = NSLocalizedString( - "SHADOWSOCKS_PORT_LABEL", - tableName: "Shadowsocks", - value: "Port", - comment: "" - ) + let portString = NSLocalizedString("Port", comment: "") SingleChoiceList( title: portString, options: [WireGuardObfuscationShadowsocksPort.automatic], value: $viewModel.value, tableAccessibilityIdentifier: AccessibilityIdentifier.wireGuardObfuscationShadowsocksTable.asString, - itemDescription: { item in NSLocalizedString( - "SHADOWSOCKS_PORT_VALUE_\(item)", - tableName: "Shadowsocks", - value: "\(item)", - comment: "" - ) }, + itemDescription: { item in NSLocalizedString("\(item)", comment: "") }, parseCustomValue: { UInt16($0).flatMap { $0 > 0 ? WireGuardObfuscationShadowsocksPort.custom($0) : nil } }, formatCustomValue: { @@ -40,24 +30,9 @@ struct ShadowsocksObfuscationSettingsView<VM>: View where VM: ShadowsocksObfusca nil } }, - customLabel: NSLocalizedString( - "SHADOWSOCKS_PORT_VALUE_CUSTOM", - tableName: "Shadowsocks", - value: "Custom", - comment: "" - ), - customPrompt: NSLocalizedString( - "SHADOWSOCKS_PORT_VALUE_PORT_PROMPT", - tableName: "Shadowsocks", - value: "Port", - comment: "" - ), - customLegend: NSLocalizedString( - "SHADOWSOCKS_PORT_VALUE_PORT_LEGEND", - tableName: "Shadowsocks", - value: "Valid range: 1 - 65535", - comment: "" - ), + customLabel: NSLocalizedString("Custom", comment: ""), + customPrompt: NSLocalizedString("Port", comment: ""), + customLegend: NSLocalizedString("Valid range: 1 - 65535", comment: ""), customInputMinWidth: 100, customInputMaxLength: 5, customFieldMode: .numericText diff --git a/ios/MullvadVPN/View controllers/Settings/Obfuscation/UDPOverTCPObfuscationSettingsView.swift b/ios/MullvadVPN/View controllers/Settings/Obfuscation/UDPOverTCPObfuscationSettingsView.swift index 2ddc06ba11..544ca5d24f 100644 --- a/ios/MullvadVPN/View controllers/Settings/Obfuscation/UDPOverTCPObfuscationSettingsView.swift +++ b/ios/MullvadVPN/View controllers/Settings/Obfuscation/UDPOverTCPObfuscationSettingsView.swift @@ -13,23 +13,18 @@ struct UDPOverTCPObfuscationSettingsView<VM>: View where VM: UDPOverTCPObfuscati @StateObject var viewModel: VM var body: some View { - let portString = NSLocalizedString( - "UDP_TCP_PORT_LABEL", - tableName: "UdpToTcp", - value: "Port", - comment: "" - ) + let portString = NSLocalizedString("Port", comment: "") SingleChoiceList( title: portString, options: [WireGuardObfuscationUdpOverTcpPort.automatic, .port80, .port5001], value: $viewModel.value, tableAccessibilityIdentifier: AccessibilityIdentifier.wireGuardObfuscationUdpOverTcpTable.asString, - itemDescription: { item in NSLocalizedString( - "UDP_TCP_PORT_VALUE_\(item)", - tableName: "UdpToTcp", - value: "\(item)", - comment: "" - ) } + itemDescription: { item in + String( + format: NSLocalizedString("%@", comment: ""), + "\(item)" + ) + } ).onDisappear { viewModel.commit() } diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift b/ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift index 39831b9464..b74dcbf1cc 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift @@ -50,24 +50,14 @@ final class SettingsCellFactory: @preconcurrency CellFactoryProtocol { case .vpnSettings: guard let cell = cell as? SettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "VPN_SETTINGS_CELL_LABEL", - tableName: "Settings", - value: "VPN settings", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("VPN settings", comment: "") cell.detailTitleLabel.text = nil cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.disclosureType = .chevron case .changelog: guard let cell = cell as? SettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "APP_VERSION_CELL_LABEL", - tableName: "Settings", - value: "What's new", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("What's new", comment: "") cell.detailTitleLabel.text = Bundle.main.productVersion cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.disclosureType = .chevron @@ -75,12 +65,7 @@ final class SettingsCellFactory: @preconcurrency CellFactoryProtocol { case .problemReport: guard let cell = cell as? SettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "REPORT_PROBLEM_CELL_LABEL", - tableName: "Settings", - value: "Report a problem", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Report a problem", comment: "") cell.detailTitleLabel.text = nil cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.disclosureType = .chevron @@ -88,24 +73,14 @@ final class SettingsCellFactory: @preconcurrency CellFactoryProtocol { case .faq: guard let cell = cell as? SettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "FAQ_AND_GUIDES_CELL_LABEL", - tableName: "Settings", - value: "FAQs & Guides", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("FAQs & Guides", comment: "") cell.detailTitleLabel.text = nil cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.disclosureType = .externalLink case .apiAccess: guard let cell = cell as? SettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "API_ACCESS_CELL_LABEL", - tableName: "Settings", - value: "API access", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("API access", comment: "") cell.detailTitleLabel.text = nil cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.disclosureType = .chevron @@ -113,19 +88,11 @@ final class SettingsCellFactory: @preconcurrency CellFactoryProtocol { case .daita: guard let cell = cell as? SettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "DAITA_CELL_LABEL", - tableName: "Settings", - value: "DAITA", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("DAITA", comment: "") - cell.detailTitleLabel.text = NSLocalizedString( - "DAITA_CELL_DETAIL_LABEL", - tableName: "Settings", - value: viewModel.daitaSettings.daitaState.isEnabled ? "On" : "Off", - comment: "" - ) + cell.detailTitleLabel.text = viewModel.daitaSettings.daitaState.isEnabled + ? NSLocalizedString("On", comment: "") + : NSLocalizedString("Off", comment: "") cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.disclosureType = .chevron @@ -133,38 +100,20 @@ final class SettingsCellFactory: @preconcurrency CellFactoryProtocol { case .multihop: guard let cell = cell as? SettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "MULTIHOP_CELL_LABEL", - tableName: "Settings", - value: "Multihop", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Multihop", comment: "") - cell.detailTitleLabel.text = NSLocalizedString( - "MULTIHOP_CELL_DETAIL_LABEL", - tableName: "Settings", - value: viewModel.multihopState.isEnabled ? "On" : "Off", - comment: "" - ) + cell.detailTitleLabel.text = viewModel.multihopState.isEnabled + ? NSLocalizedString("On", comment: "") + : NSLocalizedString("Off", comment: "") cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.disclosureType = .chevron case .language: guard let cell = cell as? SettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "LANGUAGE_CELL_LABEL", - tableName: "Settings", - value: "Language", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Language", comment: "") - cell.detailTitleLabel.text = NSLocalizedString( - "LANGUAGE_CELL_DETAIL_LABEL", - tableName: "Settings", - value: viewModel.currentLanguage, - comment: "" - ) + cell.detailTitleLabel.text = viewModel.currentLanguage cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.disclosureType = .chevron diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsDNSTextCell.swift b/ios/MullvadVPN/View controllers/Settings/SettingsDNSTextCell.swift index 3a4c1c3ae5..cf024f7c43 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsDNSTextCell.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsDNSTextCell.swift @@ -29,12 +29,7 @@ class SettingsDNSTextCell: SettingsCell, UITextFieldDelegate { textField.backgroundColor = .clear textField.textColor = UIColor.TextField.textColor textField.textMargins = UIMetrics.SettingsCell.textFieldContentInsets - textField.placeholder = NSLocalizedString( - "DNS_TEXT_CELL_PLACEHOLDER", - tableName: "Settings", - value: "Enter IP", - comment: "" - ) + textField.placeholder = NSLocalizedString("Enter IP", comment: "") textField.setAccessibilityIdentifier(.dnsSettingsEnterIPAddressTextField) textField.cornerRadius = 0 textField.keyboardType = .numbersAndPunctuation diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift b/ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift index 91f89e29b1..8aa6b0bccf 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift @@ -137,18 +137,8 @@ class SettingsHeaderView: UITableViewHeaderFooterView { private func updateAccessibilityCustomActions() { let actionName = isExpanded - ? NSLocalizedString( - "SETTINGS_HEADER_COLLAPSE_ACCESSIBILITY_ACTION", - tableName: "Settings", - value: "Collapse \(accessibilityCustomActionName)", - comment: "" - ) - : NSLocalizedString( - "SETTINGS_HEADER_EXPAND_ACCESSIBILITY_ACTION", - tableName: "Settings", - value: "Expand \(accessibilityCustomActionName)", - comment: "" - ) + ? NSLocalizedString("Collapse \(accessibilityCustomActionName)", comment: "") + : NSLocalizedString("Expand \(accessibilityCustomActionName)", comment: "") accessibilityCustomActions = [ UIAccessibilityCustomAction( diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsInfoButtonItem.swift b/ios/MullvadVPN/View controllers/Settings/SettingsInfoButtonItem.swift index 4197cdd68b..2d6326ed37 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsInfoButtonItem.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsInfoButtonItem.swift @@ -16,9 +16,7 @@ enum SettingsInfoButtonItem: CustomStringConvertible { switch self { case .daita: NSLocalizedString( - "DAITA_INFORMATION_TEXT", - tableName: "DAITA", - value: """ + """ DAITA (Defence against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic. \ If anyone is monitoring your connection, this makes it significantly harder for them to identify \ what websites you are visiting. @@ -32,9 +30,7 @@ enum SettingsInfoButtonItem: CustomStringConvertible { ) case .daitaDirectOnly: NSLocalizedString( - "DIRECT_ONLY_INFORMATION_TEXT", - tableName: "DAITA", - value: """ + """ By enabling "Direct only" you will have to manually select a server that is DAITA-enabled. \ This can cause you to end up in a blocked state until you have selected a compatible server \ in the "Select location" view. diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsInputCell.swift b/ios/MullvadVPN/View controllers/Settings/SettingsInputCell.swift index 51dedaa27f..f3239b758d 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsInputCell.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsInputCell.swift @@ -27,12 +27,7 @@ class SettingsInputCell: SelectableSettingsCell { super.init(style: style, reuseIdentifier: reuseIdentifier) toolbarDoneButton = UIBarButtonItem( - title: NSLocalizedString( - "INPUT_CELL_TOOLBAR_BUTTON_DONE", - tableName: "VPNSettings", - value: "Done", - comment: "" - ), + title: NSLocalizedString("Done", comment: ""), style: .done, target: self, action: #selector(confirmInput) diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift b/ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift index 9348e198aa..46aeb5a8f5 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift @@ -43,12 +43,7 @@ class SettingsViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() - navigationItem.title = NSLocalizedString( - "NAVIGATION_TITLE", - tableName: "Settings", - value: "Settings", - comment: "" - ) + navigationItem.title = NSLocalizedString("Settings", comment: "") let doneButton = UIBarButtonItem( systemItem: .done, @@ -94,12 +89,7 @@ extension SettingsViewController: @preconcurrency SettingsDataSourceDelegate { message: item.description, buttons: [ AlertAction( - title: NSLocalizedString( - "SETTINGS_INFO_ALERT_OK_ACTION", - tableName: "Settings", - value: "Got it!", - comment: "" - ), + title: NSLocalizedString("Got it!", comment: ""), style: .default ), ] diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsViewModel.swift b/ios/MullvadVPN/View controllers/Settings/SettingsViewModel.swift index 77abcf9f05..44ec88ed49 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsViewModel.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsViewModel.swift @@ -13,7 +13,7 @@ struct SettingsViewModel { private(set) var multihopState: MultihopState var currentLanguage: String { - let currentLanguage = AppLanguage.currentLanguage + let currentLanguage = ApplicationLanguage.currentLanguage return "\(currentLanguage.flagEmoji) \(currentLanguage.displayName)" } diff --git a/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipFeature.swift b/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipFeature.swift index b9016064b4..8c236741a4 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipFeature.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipFeature.swift @@ -9,10 +9,6 @@ import MullvadSettings import PacketTunnelCore import SwiftUI -// Opting to use NSLocalizedString instead of LocalizedStringKey here in order -// to be able to fetch the string value at a later point (eg. in ChipViewModelProtocol, -// when calculating the text widths of the chips). - protocol ChipFeature: Identifiable { var id: FeatureType { get } var isEnabled: Bool { get } @@ -41,18 +37,8 @@ struct DaitaFeature: ChipFeature { // When multihop is enabled via DAITA without being explicitly enabled // by the user, display combined indicator instead. state.isMultihop && !settings.tunnelMultihopState.isEnabled - ? NSLocalizedString( - "FEATURE_INDICATORS_CHIP_DAITA_MULTIHOP", - tableName: "FeatureIndicatorsChip", - value: "DAITA: Multihop", - comment: "" - ) - : NSLocalizedString( - "FEATURE_INDICATORS_CHIP_DAITA", - tableName: "FeatureIndicatorsChip", - value: "DAITA", - comment: "" - ) + ? NSLocalizedString("DAITA: Multihop", comment: "") + : NSLocalizedString("DAITA", comment: "") } } @@ -65,12 +51,7 @@ struct QuantumResistanceFeature: ChipFeature { } var name: String { - NSLocalizedString( - "FEATURE_INDICATORS_CHIP_QUANTUM_RESISTANCE", - tableName: "FeatureIndicatorsChip", - value: "Quantum resistance", - comment: "" - ) + NSLocalizedString("Quantum resistance", comment: "") } } @@ -86,12 +67,7 @@ struct MultihopFeature: ChipFeature { } var name: String { - NSLocalizedString( - "FEATURE_INDICATORS_CHIP_MULTIHOP", - tableName: "FeatureIndicatorsChip", - value: "Multihop", - comment: "" - ) + NSLocalizedString("Multihop", comment: "") } } @@ -118,12 +94,7 @@ struct ObfuscationFeature: ChipFeature { // or a colour/border style or whatever), use the `isAutomatic` field. // To say what type of obfuscation it is, // we can look at `actualObfuscationMethod` - NSLocalizedString( - "FEATURE_INDICATORS_CHIP_OBFUSCATION", - tableName: "FeatureIndicatorsChip", - value: "Obfuscation", - comment: "" - ) + NSLocalizedString("Obfuscation", comment: "") } } @@ -137,19 +108,9 @@ struct DNSFeature: ChipFeature { var name: String { if !settings.dnsSettings.blockingOptions.isEmpty { - NSLocalizedString( - "FEATURE_INDICATORS_CHIP_CONTENT_BLOCKERS", - tableName: "FeatureIndicatorsChip", - value: "DNS content blockers", - comment: "" - ) + NSLocalizedString("DNS content blockers", comment: "") } else { - NSLocalizedString( - "FEATURE_INDICATORS_CHIP_CUSTOM_DNS", - tableName: "FeatureIndicatorsChip", - value: "Custom DNS", - comment: "" - ) + NSLocalizedString("Custom DNS", comment: "") } } } @@ -170,11 +131,6 @@ struct IPOverrideFeature: ChipFeature { } var name: String { - NSLocalizedString( - "FEATURE_INDICATORS_CHIP_IP_OVERRIDE", - tableName: "FeatureIndicatorsChip", - value: "Server IP Override", - comment: "" - ) + NSLocalizedString("Server IP Override", comment: "") } } diff --git a/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipViewModelProtocol.swift b/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipViewModelProtocol.swift index b5fbd83e06..a663e43217 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipViewModelProtocol.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipViewModelProtocol.swift @@ -18,15 +18,8 @@ extension ChipViewModelProtocol { var chipsToAdd = [ChipModel]() var isOverflowing = false - let moreTextWidth = String( - format: NSLocalizedString( - "CONNECTION_VIEW_CHIPS_MORE", - tableName: "ConnectionView", - value: "@d more...", - comment: "" - ), arguments: [chips.count] - ) - .width(using: .preferredFont(forTextStyle: .subheadline)) + 4 // Some extra to be safe. + let moreTextWidth = String(format: NSLocalizedString("%d more...", comment: ""), chips.count) + .width(using: .preferredFont(forTextStyle: .subheadline)) + 4 // Some extra to be safe. var totalChipsWidth: CGFloat = 0 for (index, chip) in chips.enumerated() { diff --git a/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift b/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift index 8150e2ef8a..0118ee2a43 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift @@ -60,12 +60,7 @@ final class CustomDNSCellFactory: @preconcurrency CellFactoryProtocol { func configureCell(_ cell: UITableViewCell, item: CustomDNSDataSource.Item, indexPath: IndexPath) { switch item { case .blockAll: - let localizedString = NSLocalizedString( - "BLOCK_ALL_CELL_LABEL", - tableName: "VPNSettings", - value: "All", - comment: "" - ) + let localizedString = NSLocalizedString("All", comment: "") configure( cell, @@ -75,12 +70,7 @@ final class CustomDNSCellFactory: @preconcurrency CellFactoryProtocol { ) case .blockAdvertising: - let localizedString = NSLocalizedString( - "BLOCK_ADS_CELL_LABEL", - tableName: "VPNSettings", - value: "Ads", - comment: "" - ) + let localizedString = NSLocalizedString("Ads", comment: "") configure( cell, @@ -90,12 +80,7 @@ final class CustomDNSCellFactory: @preconcurrency CellFactoryProtocol { ) case .blockTracking: - let localizedString = NSLocalizedString( - "BLOCK_TRACKERS_CELL_LABEL", - tableName: "VPNSettings", - value: "Trackers", - comment: "" - ) + let localizedString = NSLocalizedString("Trackers", comment: "") configure( cell, toggleSetting: viewModel.blockTracking, @@ -106,12 +91,7 @@ final class CustomDNSCellFactory: @preconcurrency CellFactoryProtocol { case .blockMalware: guard let cell = cell as? SettingsSwitchCell else { return } - let localizedString = NSLocalizedString( - "BLOCK_MALWARE_CELL_LABEL", - tableName: "VPNSettings", - value: "Malware", - comment: "" - ) + let localizedString = NSLocalizedString("Malware", comment: "") configure( cell, toggleSetting: viewModel.blockMalware, @@ -123,12 +103,7 @@ final class CustomDNSCellFactory: @preconcurrency CellFactoryProtocol { } case .blockAdultContent: - let localizedString = NSLocalizedString( - "BLOCK_ADULT_CELL_LABEL", - tableName: "VPNSettings", - value: "Adult content", - comment: "" - ) + let localizedString = NSLocalizedString("Adult content", comment: "") configure( cell, toggleSetting: viewModel.blockAdultContent, @@ -137,12 +112,7 @@ final class CustomDNSCellFactory: @preconcurrency CellFactoryProtocol { ) case .blockGambling: - let localizedString = NSLocalizedString( - "BLOCK_GAMBLING_CELL_LABEL", - tableName: "VPNSettings", - value: "Gambling", - comment: "" - ) + let localizedString = NSLocalizedString("Gambling", comment: "") configure( cell, toggleSetting: viewModel.blockGambling, @@ -151,12 +121,7 @@ final class CustomDNSCellFactory: @preconcurrency CellFactoryProtocol { ) case .blockSocialMedia: - let localizedString = NSLocalizedString( - "BLOCK_SOCIAL_MEDIA_CELL_LABEL", - tableName: "VPNSettings", - value: "Social media", - comment: "" - ) + let localizedString = NSLocalizedString("Social media", comment: "") configure( cell, toggleSetting: viewModel.blockSocialMedia, @@ -167,12 +132,7 @@ final class CustomDNSCellFactory: @preconcurrency CellFactoryProtocol { case .useCustomDNS: guard let cell = cell as? SettingsSwitchCell else { return } - cell.titleLabel.text = NSLocalizedString( - "CUSTOM_DNS_CELL_LABEL", - tableName: "VPNSettings", - value: "Use custom DNS server", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Use custom DNS server", comment: "") cell.setSwitchEnabled(viewModel.customDNSPrecondition == .satisfied) cell.setOn(viewModel.effectiveEnableCustomDNS, animated: false) cell.accessibilityHint = viewModel.customDNSPrecondition @@ -185,12 +145,7 @@ final class CustomDNSCellFactory: @preconcurrency CellFactoryProtocol { case .addDNSServer: guard let cell = cell as? SettingsAddDNSEntryCell else { return } - cell.titleLabel.text = NSLocalizedString( - "ADD_CUSTOM_DNS_SERVER_CELL_LABEL", - tableName: "VPNSettings", - value: "Add a server", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Add a server", comment: "") cell.setAccessibilityIdentifier(.dnsSettingsAddServerCell) cell.tapAction = { [weak self] in self?.delegate?.addDNSEntry() diff --git a/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSDataSource.swift b/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSDataSource.swift index d620e101be..95135d27ac 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSDataSource.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSDataSource.swift @@ -577,12 +577,7 @@ final class CustomDNSDataSource: UITableViewDiffableDataSource< } private func configureContentBlockersHeader(_ header: SettingsHeaderView) { - let title = NSLocalizedString( - "CONTENT_BLOCKERS_HEADER_LABEL", - tableName: "VPNSettings", - value: "DNS content blockers", - comment: "" - ) + let title = NSLocalizedString("DNS content blockers", comment: "") let enabledBlockersCount = viewModel.enabledBlockersCount let attributedTitle = NSMutableAttributedString(string: title) diff --git a/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSViewController.swift b/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSViewController.swift index 7b1227cfe0..8f663c14af 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSViewController.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSViewController.swift @@ -42,12 +42,7 @@ class CustomDNSViewController: UITableViewController { dataSource = CustomDNSDataSource(tableView: tableView) dataSource?.delegate = self - navigationItem.title = NSLocalizedString( - "NAVIGATION_TITLE", - tableName: "VPNSettings", - value: "DNS settings", - comment: "" - ) + navigationItem.title = NSLocalizedString("DNS settings", comment: "") if navigationItem.rightBarButtonItem != nil { navigationItem.leftBarButtonItem = editButtonItem navigationItem.leftBarButtonItem?.setAccessibilityIdentifier(.dnsSettingsEditButton) @@ -92,12 +87,7 @@ class CustomDNSViewController: UITableViewController { attributedMessage: message, buttons: [ AlertAction( - title: NSLocalizedString( - "VPN_SETTINGS_DNS_SETTINGS_OK_ACTION", - tableName: "ContentBlockers", - value: "Got it!", - comment: "" - ), + title: NSLocalizedString("Got it!", comment: ""), style: .default ), ] diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift index 91b0a5db98..d3299eaebb 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift @@ -51,12 +51,7 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { } } - cell.titleLabel.text = NSLocalizedString( - "LOCAL_NETWORK_SHARING_CELL_LABEL", - tableName: "VPNSettings", - value: "Include all networks", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Include all networks", comment: "") cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.setOn(viewModel.includeAllNetworks, animated: true) case .localNetworkSharing: @@ -68,12 +63,7 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { } } - cell.titleLabel.text = NSLocalizedString( - "LOCAL_NETWORK_SHARING_CELL_LABEL", - tableName: "VPNSettings", - value: "Local network sharing", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Local network sharing", comment: "") cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.setOn(viewModel.localNetworkSharing, animated: true) cell.setSwitchEnabled(viewModel.includeAllNetworks) @@ -81,12 +71,7 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { case .dnsSettings: guard let cell = cell as? SettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "DNS_SETTINGS_CELL_LABEL", - tableName: "VPNSettings", - value: "DNS settings", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("DNS settings", comment: "") cell.disclosureType = .chevron cell.setAccessibilityIdentifier(item.accessibilityIdentifier) @@ -94,12 +79,7 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { case .ipOverrides: guard let cell = cell as? SettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "IP_OVERRIDE_CELL_LABEL", - tableName: "VPNSettings", - value: "Server IP override", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Server IP override", comment: "") cell.disclosureType = .chevron cell.setAccessibilityIdentifier(item.accessibilityIdentifier) @@ -107,12 +87,7 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { case let .wireGuardPort(port): guard let cell = cell as? SelectableSettingsCell else { return } - var portString = NSLocalizedString( - "WIREGUARD_PORT_CELL_LABEL", - tableName: "VPNSettings", - value: "Automatic", - comment: "" - ) + var portString = NSLocalizedString("Automatic", comment: "") if let port { portString = String(port) } @@ -124,18 +99,8 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { case .wireGuardCustomPort: guard let cell = cell as? SettingsInputCell else { return } - cell.titleLabel.text = NSLocalizedString( - "WIREGUARD_CUSTOM_PORT_CELL_LABEL", - tableName: "VPNSettings", - value: "Custom", - comment: "" - ) - cell.textField.placeholder = NSLocalizedString( - "WIREGUARD_CUSTOM_PORT_CELL_INPUT_PLACEHOLDER", - tableName: "VPNSettings", - value: "Port", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Custom", comment: "") + cell.textField.placeholder = NSLocalizedString("Port", comment: "") cell.textField.setAccessibilityIdentifier(.customWireGuardPortTextField) cell.setAccessibilityIdentifier(item.accessibilityIdentifier) @@ -165,31 +130,19 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { case .wireGuardObfuscationAutomatic: guard let cell = cell as? SelectableSettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "WIREGUARD_OBFUSCATION_AUTOMATIC_LABEL", - tableName: "VPNSettings", - value: "Automatic", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Automatic", comment: "") cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.applySubCellStyling() case .wireGuardObfuscationUdpOverTcp: guard let cell = cell as? SelectableSettingsDetailsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "WIREGUARD_OBFUSCATION_UDP_TCP_LABEL", - tableName: "VPNSettings", - value: "UDP-over-TCP", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("UDP-over-TCP", comment: "") - cell.detailTitleLabel.text = String(format: NSLocalizedString( - "WIREGUARD_OBFUSCATION_UDP_TCP_PORT", - tableName: "VPNSettings", - value: "Port: %@", - comment: "" - ), viewModel.obfuscationUpdOverTcpPort.description) + cell.detailTitleLabel.text = String( + format: NSLocalizedString("Port: %@", comment: ""), + viewModel.obfuscationUpdOverTcpPort.description + ) cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.detailTitleLabel.setAccessibilityIdentifier(.wireGuardObfuscationUdpOverTcpPort) @@ -202,19 +155,12 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { case .wireGuardObfuscationShadowsocks: guard let cell = cell as? SelectableSettingsDetailsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "WIREGUARD_OBFUSCATION_SHADOWSOCKS_LABEL", - tableName: "VPNSettings", - value: "Shadowsocks", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Shadowsocks", comment: "") - cell.detailTitleLabel.text = String(format: NSLocalizedString( - "WIREGUARD_OBFUSCATION_SHADOWSOCKS_PORT", - tableName: "VPNSettings", - value: "Port: %@", - comment: "" - ), viewModel.obfuscationShadowsocksPort.description) + cell.detailTitleLabel.text = String( + format: NSLocalizedString("Port: %@", comment: ""), + viewModel.obfuscationShadowsocksPort.description + ) cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.detailTitleLabel.setAccessibilityIdentifier(.wireGuardObfuscationShadowsocksPort) @@ -227,12 +173,7 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { case .wireGuardObfuscationQuic: guard let cell = cell as? SelectableSettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "WIREGUARD_OBFUSCATION_QUIC_LABEL", - tableName: "VPNSettings", - value: "QUIC", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("QUIC", comment: "") cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.detailTitleLabel.setAccessibilityIdentifier(.wireGuardObfuscationQuic) @@ -241,12 +182,7 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { case .wireGuardObfuscationOff: guard let cell = cell as? SelectableSettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "WIREGUARD_OBFUSCATION_OFF_LABEL", - tableName: "VPNSettings", - value: "Off", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Off", comment: "") cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.applySubCellStyling() @@ -254,48 +190,28 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { guard let cell = cell as? SelectableSettingsCell else { return } let portString = port.description - cell.titleLabel.text = NSLocalizedString( - "WIREGUARD_OBFUSCATION_PORT_LABEL", - tableName: "VPNSettings", - value: portString, - comment: "" - ) + cell.titleLabel.text = portString cell.accessibilityIdentifier = "\(item.accessibilityIdentifier)\(portString)" cell.applySubCellStyling() case .quantumResistanceAutomatic: guard let cell = cell as? SelectableSettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "QUANTUM_RESISTANCE_AUTOMATIC_LABEL", - tableName: "VPNSettings", - value: "Automatic", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Automatic", comment: "") cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.applySubCellStyling() case .quantumResistanceOn: guard let cell = cell as? SelectableSettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "QUANTUM_RESISTANCE_ON_LABEL", - tableName: "VPNSettings", - value: "On", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("On", comment: "") cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.applySubCellStyling() case .quantumResistanceOff: guard let cell = cell as? SelectableSettingsCell else { return } - cell.titleLabel.text = NSLocalizedString( - "QUANTUM_RESISTANCE_OFF_LABEL", - tableName: "VPNSettings", - value: "Off", - comment: "" - ) + cell.titleLabel.text = NSLocalizedString("Off", comment: "") cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.applySubCellStyling() } diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift index f76100bd29..31f1d7ce93 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift @@ -565,12 +565,7 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource< } private func configureWireguardPortsHeader(_ header: SettingsHeaderView) { - let title = NSLocalizedString( - "WIREGUARD_PORTS_HEADER_LABEL", - tableName: "VPNSettings", - value: "WireGuard ports", - comment: "" - ) + let title = NSLocalizedString("WireGuard ports", comment: "") header.setAccessibilityIdentifier(.wireGuardPortsCell) header.titleLabel.text = title @@ -609,12 +604,7 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource< } private func configureObfuscationHeader(_ header: SettingsHeaderView) { - let title = NSLocalizedString( - "OBFUSCATION_HEADER_LABEL", - tableName: "VPNSettings", - value: "WireGuard Obfuscation", - comment: "" - ) + let title = NSLocalizedString("WireGuard Obfuscation", comment: "") header.setAccessibilityIdentifier(.wireGuardObfuscationCell) header.titleLabel.text = title @@ -641,12 +631,7 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource< } private func configureQuantumResistanceHeader(_ header: SettingsHeaderView) { - let title = NSLocalizedString( - "QUANTUM_RESISTANCE_HEADER_LABEL", - tableName: "VPNSettings", - value: "Quantum-resistant tunnel", - comment: "" - ) + let title = NSLocalizedString("Quantum-resistant tunnel", comment: "") header.setAccessibilityIdentifier(.quantumResistantTunnelCell) header.titleLabel.text = title diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift index 693def0662..1b0e76a397 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift @@ -22,9 +22,7 @@ enum VPNSettingsInfoButtonItem: CustomStringConvertible { switch self { case .localNetworkSharing: NSLocalizedString( - "VPN_SETTINGS_LOCAL_NETWORK_SHARING", - tableName: "LocalNetworkSharing", - value: """ + """ This feature allows access to other devices on the local network, such as for sharing, printing, \ streaming, etc. Attention: toggling “Local network sharing” requires restarting the VPN connection. @@ -33,9 +31,7 @@ enum VPNSettingsInfoButtonItem: CustomStringConvertible { ) case .contentBlockers: NSLocalizedString( - "VPN_SETTINGS_CONTENT_BLOCKERS_GENERAL", - tableName: "ContentBlockers", - value: """ + """ When this feature is enabled it stops the device from contacting certain \ domains or websites known for distributing ads, malware, trackers and more. \ @@ -46,9 +42,7 @@ enum VPNSettingsInfoButtonItem: CustomStringConvertible { ) case .blockMalware: NSLocalizedString( - "VPN_SETTINGS_CONTENT_BLOCKERS_MALWARE", - tableName: "ContentBlockers", - value: """ + """ Warning: The malware blocker is not an anti-virus and should not \ be treated as such, this is just an extra layer of protection. """, @@ -57,9 +51,7 @@ enum VPNSettingsInfoButtonItem: CustomStringConvertible { case let .wireGuardPorts(portsString): String( format: NSLocalizedString( - "VPN_SETTINGS_WIREGUARD_PORTS_GENERAL", - tableName: "WireGuardPorts", - value: """ + """ The automatic setting will randomly choose from the valid port ranges shown below. The custom port can be any value inside the valid ranges: %@ @@ -70,9 +62,7 @@ enum VPNSettingsInfoButtonItem: CustomStringConvertible { ) case .wireGuardObfuscation: NSLocalizedString( - "VPN_SETTINGS_WIREGUARD_OBFUSCATION_GENERAL", - tableName: "WireGuardObfuscation", - value: """ + """ Obfuscation hides the WireGuard traffic inside another protocol. \ It can be used to help circumvent censorship and other types of filtering, \ where a plain WireGuard connection would be blocked. @@ -81,16 +71,12 @@ enum VPNSettingsInfoButtonItem: CustomStringConvertible { ) case .wireGuardObfuscationPort: NSLocalizedString( - "VPN_SETTINGS_WIREGUARD_OBFUSCATION_PORT_GENERAL", - tableName: "WireGuardObfuscation", - value: "Which TCP port the UDP-over-TCP obfuscation protocol should connect to on the VPN server.", + "Which TCP port the UDP-over-TCP obfuscation protocol should connect to on the VPN server.", comment: "" ) case .quantumResistance: NSLocalizedString( - "VPN_SETTINGS_QUANTUM_RESISTANCE_GENERAL", - tableName: "QuantumResistance", - value: """ + """ This feature makes the WireGuard tunnel resistant to potential attacks from quantum computers. It does this by performing an extra key exchange using a quantum safe algorithm and mixing \ the result into WireGuard’s regular encryption. @@ -100,9 +86,7 @@ enum VPNSettingsInfoButtonItem: CustomStringConvertible { ) case .multihop: NSLocalizedString( - "MULTIHOP_INFORMATION_TEXT", - tableName: "Multihop", - value: """ + """ Multihop routes your traffic into one WireGuard server and out another, making it harder to trace. This results in increased latency but increases anonymity online. """, diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift index 053b2188b6..4337ab1132 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift @@ -58,12 +58,7 @@ class VPNSettingsViewController: UITableViewController { dataSource?.delegate = self - navigationItem.title = NSLocalizedString( - "NAVIGATION_TITLE", - tableName: "VPNSettings", - value: "VPN settings", - comment: "" - ) + navigationItem.title = NSLocalizedString("VPN settings", comment: "") interactor.tunnelSettingsDidChange = { [weak self] newSettings in self?.dataSource?.reload(from: newSettings) @@ -108,12 +103,7 @@ extension VPNSettingsViewController: @preconcurrency VPNSettingsDataSourceDelega message: item.description, buttons: [ AlertAction( - title: NSLocalizedString( - "VPN_SETTINGS_VPN_SETTINGS_OK_ACTION", - tableName: "ContentBlockers", - value: "Got it!", - comment: "" - ), + title: NSLocalizedString("Got it!", comment: ""), style: .default ), ] @@ -144,12 +134,7 @@ extension VPNSettingsViewController: @preconcurrency VPNSettingsDataSourceDelega let viewModel = TunnelUDPOverTCPObfuscationSettingsViewModel(tunnelManager: interactor.tunnelManager) let view = UDPOverTCPObfuscationSettingsView(viewModel: viewModel) let vc = UIHostingController(rootView: view) - vc.title = NSLocalizedString( - "UDP_OVER_TCP_TITLE", - tableName: "VPNSettings", - value: "UDP-over-TCP", - comment: "" - ) + vc.title = NSLocalizedString("UDP-over-TCP", comment: "") navigationController?.pushViewController(vc, animated: true) } @@ -157,12 +142,7 @@ extension VPNSettingsViewController: @preconcurrency VPNSettingsDataSourceDelega let viewModel = TunnelShadowsocksObfuscationSettingsViewModel(tunnelManager: interactor.tunnelManager) let view = ShadowsocksObfuscationSettingsView(viewModel: viewModel) let vc = UIHostingController(rootView: view) - vc.title = NSLocalizedString( - "SHADOWSOCKS_TITLE", - tableName: "VPNSettings", - value: "Shadowsocks", - comment: "" - ) + vc.title = NSLocalizedString("Shadowsocks", comment: "") navigationController?.pushViewController(vc, animated: true) } @@ -172,15 +152,12 @@ extension VPNSettingsViewController: @preconcurrency VPNSettingsDataSourceDelega func showLocalNetworkSharingWarning(_ enable: Bool, completion: @escaping (Bool) -> Void) { if interactor.tunnelManager.tunnelStatus.state.isSecured { + let status = enable + ? NSLocalizedString("Enabling", comment: "") + : NSLocalizedString("Disabling", comment: "") let description = NSLocalizedString( - "VPN_SETTINGS_LOCAL_NETWORK_SHARING_WARNING", - tableName: "LocalNetworkSharing", - value: """ - \( - enable - ? "Enabling" - : "Disabling" - ) “Local network sharing” requires restarting the VPN connection, which will disconnect you and briefly expose your traffic. + """ + “%@ Local network sharing” requires restarting the VPN connection, which will disconnect you and briefly expose your traffic. To prevent this, manually enable Airplane Mode and turn off Wi-Fi before continuing. Would you like to continue to enable “Local network sharing”? """, @@ -190,15 +167,10 @@ extension VPNSettingsViewController: @preconcurrency VPNSettingsDataSourceDelega let presentation = AlertPresentation( id: "vpn-settings-local-network-sharing-warning", icon: .info, - message: description, + message: String(format: description, status), buttons: [ AlertAction( - title: NSLocalizedString( - "VPN_SETTINGS_LOCAL_NETWORK_SHARING_OK_ACTION", - tableName: "ContentBlockers", - value: "Yes, continue", - comment: "" - ), + title: NSLocalizedString("Yes, continue", comment: ""), style: .destructive, accessibilityId: .acceptLocalNetworkSharingButton, handler: { @@ -206,12 +178,7 @@ extension VPNSettingsViewController: @preconcurrency VPNSettingsDataSourceDelega } ), AlertAction( - title: NSLocalizedString( - "VPN_SETTINGS_LOCAL_NETWORK_SHARING_CANCEL_ACTION", - tableName: "ContentBlockers", - value: "Cancel", - comment: "" - ), + title: NSLocalizedString("Cancel", comment: ""), style: .default, handler: { completion(false) } ), diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewModel.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewModel.swift index 8e731419a4..8823ef46a4 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewModel.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewModel.swift @@ -41,21 +41,16 @@ enum CustomDNSPrecondition { if isEditing { return NSAttributedString( string: NSLocalizedString( - "CUSTOM_DNS_NO_DNS_ENTRIES_EDITING_ON_FOOTNOTE", - tableName: "VPNSettings", - value: "To enable this setting, add at least one server.", - comment: "Foot note displayed if there are no DNS entries and table view is in editing mode." + "To enable this setting, add at least one server.", + comment: "" ), attributes: [.font: preferredFont] ) } else { return NSAttributedString( markdownString: NSLocalizedString( - "CUSTOM_DNS_NO_DNS_ENTRIES_EDITING_OFF_FOOTNOTE", - tableName: "VPNSettings", - value: "Tap **Edit** to add at least one DNS server.", - comment: - "Foot note displayed if there are no DNS entries, but table view is not in editing mode." + "Tap **Edit** to add at least one DNS server.", + comment: "" ), options: MarkdownStylingOptions(font: preferredFont) ) @@ -64,13 +59,8 @@ enum CustomDNSPrecondition { case .conflictsWithOtherSettings: return NSAttributedString( string: NSLocalizedString( - "CUSTOM_DNS_DISABLE_CONTENT_BLOCKERS_FOOTNOTE", - tableName: "VPNSettings", - value: "Disable all content blockers to activate this setting.", - comment: """ - Foot note displayed when custom DNS cannot be enabled, because content blockers should be \ - disabled first. - """ + "Disable all content blockers to activate this setting.", + comment: "" ), attributes: [.font: preferredFont] ) diff --git a/ios/MullvadVPNUITests/Pages/Page.swift b/ios/MullvadVPNUITests/Pages/Page.swift index 5cb281f70d..137b2532c8 100644 --- a/ios/MullvadVPNUITests/Pages/Page.swift +++ b/ios/MullvadVPNUITests/Pages/Page.swift @@ -46,7 +46,7 @@ class Page { } @discardableResult func tapKeyboardDoneButton() -> Self { - app.toolbars.buttons["Done"].tap() + app.toolbars.buttons[NSLocalizedString("Done", comment: "")].tap() return self } diff --git a/ios/Localizations/AppLanguage.swift b/ios/Shared/ApplicationLanguage.swift index 8b1788bd81..0b98d9e9c0 100644 --- a/ios/Localizations/AppLanguage.swift +++ b/ios/Shared/ApplicationLanguage.swift @@ -1,5 +1,5 @@ // -// AppLanguage.swift +// ApplicationLanguage.swift // MullvadVPN // // Created by Mojgan on 2025-07-16. @@ -19,7 +19,7 @@ import Foundation * • Remove bilingual content only for Staging. * • Eliminate the Debug configuration check. */ -enum AppLanguage: String, CaseIterable, Identifiable { +enum ApplicationLanguage: String, CaseIterable, Identifiable { case english = "en" case danish = "da" case german = "de" @@ -103,8 +103,8 @@ enum AppLanguage: String, CaseIterable, Identifiable { return flagString } - static var currentLanguage: AppLanguage { - let defaultCode = AppLanguage.english.rawValue + static var currentLanguage: ApplicationLanguage { + let defaultCode = ApplicationLanguage.english.rawValue let fullCode = Locale.preferredLanguages.first ?? defaultCode if #available(iOS 16, *) { @@ -131,6 +131,6 @@ enum AppLanguage: String, CaseIterable, Identifiable { let locale = Locale(identifier: fullCode) let langCode = locale.languageCode ?? defaultCode - return AppLanguage(rawValue: langCode) ?? .english + return ApplicationLanguage(rawValue: langCode) ?? .english } } diff --git a/ios/build-wireguard-go.sh b/ios/build-wireguard-go.sh index dcfd0a46ec..250de5c058 100755 --- a/ios/build-wireguard-go.sh +++ b/ios/build-wireguard-go.sh @@ -12,27 +12,22 @@ # Passed by Xcode ACTION=$1 -# Do normal builds when building documentation. -if [ "$ACTION" == "docbuild" ]; then - ACTION="build" -fi - if [ "$SOURCE_PACKAGES_PATH" == "" ]; then - # When archiving, Xcode sets the action to "install" - if [ "$ACTION" == "install" ]; then - SOURCE_PACKAGES_PATH="$BUILD_DIR/../../../../../SourcePackages" - elif [ "$ENABLE_PREVIEWS" == "YES" ]; then - SOURCE_PACKAGES_PATH="$BUILD_DIR/../../../../../../SourcePackages" - else - SOURCE_PACKAGES_PATH="$BUILD_DIR/../../SourcePackages" - fi + # When archiving, Xcode sets the action to "install" + if [ "$ACTION" == "install" ]; then + SOURCE_PACKAGES_PATH="$BUILD_DIR/../../../../../SourcePackages" + elif [ "$ENABLE_PREVIEWS" == "YES" ]; then + SOURCE_PACKAGES_PATH="$BUILD_DIR/../../../../../../SourcePackages" + else + SOURCE_PACKAGES_PATH="$BUILD_DIR/../../SourcePackages" + fi fi # Resolve SourcesPackages path -RESOLVED_SOURCE_PACKAGES_PATH="$( cd "$SOURCE_PACKAGES_PATH" && pwd -P )" +RESOLVED_SOURCE_PACKAGES_PATH="$(cd "$SOURCE_PACKAGES_PATH" && pwd -P)" if [ "$RESOLVED_SOURCE_PACKAGES_PATH" == "" ]; then - echo "Failed to resolve the SourcePackages path: $SOURCE_PACKAGES_PATH" - exit 1 + echo "Failed to resolve the SourcePackages path: $SOURCE_PACKAGES_PATH" + exit 1 fi # Compile the path to the Makefile directory @@ -41,6 +36,23 @@ echo "WireGuardKitGo path resolved to $WIREGUARD_KIT_GO_PATH" export PATH=/opt/homebrew/opt/go@1.21/bin:$PATH +case "$ACTION" in +docbuild) + MAKE_TARGET="build" + ;; +build | install | clean) + MAKE_TARGET="$ACTION" + ;; +exportloc) + echo "Skipping WireGuardKitGo build for exportloc" + exit 0 + ;; +*) + echo "Unknown or unsupported ACTION '$ACTION' — defaulting to 'build'" + MAKE_TARGET="build" + ;; +esac + # Run make # shellcheck disable=SC2086 -/usr/bin/make -C "$WIREGUARD_KIT_GO_PATH" $ACTION +/usr/bin/make -C "$WIREGUARD_KIT_GO_PATH" "$MAKE_TARGET" diff --git a/ios/translation/crowdin.yml b/ios/translation/crowdin.yml new file mode 100644 index 0000000000..fdf39f6d77 --- /dev/null +++ b/ios/translation/crowdin.yml @@ -0,0 +1,20 @@ +# Usage: +# crowdin upload sources +# crowdin download + +'project_id': '350815' +'api_token_env': 'CROWDIN_API_KEY' +'base_path': './locales' +'base_url': 'https://api.crowdin.com' +'preserve_hierarchy': true + +files: [ + { + 'source': '/*.xliff', + 'translation': '/%osx_locale%.xliff', + 'translation_replace': { + 'zh-Hans': 'zh-CN', + 'zh-Hant': 'zh-TW', + }, + }, +] diff --git a/ios/translation/locales/en.xliff b/ios/translation/locales/en.xliff new file mode 100644 index 0000000000..0364b59fd6 --- /dev/null +++ b/ios/translation/locales/en.xliff @@ -0,0 +1,2029 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd"> + <file original="Assets/Localizable.xcstrings" source-language="en" target-language="en" datatype="plaintext"> + <header> + <tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="16.1" build-num="16B40"/> + </header> + <body> + <trans-unit id="%@" xml:space="preserve"> + <source>%@</source> + <target state="new">%@</target> + <note/> + </trans-unit> + <trans-unit id="%@ have been added to your account" xml:space="preserve"> + <source>%@ have been added to your account</source> + <target state="new">%@ have been added to your account</target> + <note/> + </trans-unit> + <trans-unit id="%@ left on this account" xml:space="preserve"> + <source>%@ left on this account</source> + <target state="new">%@ left on this account</target> + <note/> + </trans-unit> + <trans-unit id="%@ via %@" xml:space="preserve"> + <source>%1$@ via %2$@</source> + <target state="new">%1$@ via %2$@</target> + <note/> + </trans-unit> + <trans-unit id="%@ were added to your account." xml:space="preserve"> + <source>%@ were added to your account.</source> + <target state="new">%@ were added to your account.</target> + <note/> + </trans-unit> + <trans-unit id="%@, %@" xml:space="preserve"> + <source>%1$@, %2$@</source> + <target state="new">%1$@, %2$@</target> + <note/> + </trans-unit> + <trans-unit id="%d more..." xml:space="preserve"> + <source>%d more...</source> + <target state="new">%d more...</target> + <note/> + </trans-unit> + <trans-unit id="%lld more..." xml:space="preserve"> + <source>%lld more...</source> + <target state="new">%lld more...</target> + <note/> + </trans-unit> + <trans-unit id="**Attention: This increases network traffic and will also negatively affect speed, latency, and battery usage. Use with caution on limited plans.** DAITA (Defense against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic. By using sophisticated AI it’s possible to analyze the traffic of data packets going in and out of your device (even if the traffic is encrypted)." xml:space="preserve"> + <source>**Attention: This increases network traffic and will also negatively affect speed, latency, and battery usage. Use with caution on limited plans.** + +DAITA (Defense against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic. + +By using sophisticated AI it’s possible to analyze the traffic of data packets going in and out of your device (even if the traffic is encrypted).</source> + <target state="new">**Attention: This increases network traffic and will also negatively affect speed, latency, and battery usage. Use with caution on limited plans.** + +DAITA (Defense against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic. + +By using sophisticated AI it’s possible to analyze the traffic of data packets going in and out of your device (even if the traffic is encrypted).</target> + <note/> + </trans-unit> + <trans-unit id="**Tap here** to see what’s new." xml:space="preserve"> + <source>**Tap here** to see what’s new.</source> + <target state="new">**Tap here** to see what’s new.</target> + <note/> + </trans-unit> + <trans-unit id="API access" xml:space="preserve"> + <source>API access</source> + <target state="new">API access</target> + <note/> + </trans-unit> + <trans-unit id="API could not be reached, save anyway?" xml:space="preserve"> + <source>API could not be reached, save anyway?</source> + <target state="new">API could not be reached, save anyway?</target> + <note/> + </trans-unit> + <trans-unit id="API reachable" xml:space="preserve"> + <source>API reachable</source> + <target state="new">API reachable</target> + <note/> + </trans-unit> + <trans-unit id="API unreachable" xml:space="preserve"> + <source>API unreachable</source> + <target state="new">API unreachable</target> + <note/> + </trans-unit> + <trans-unit id="About API access…" xml:space="preserve"> + <source>About API access…</source> + <target state="new">About API access…</target> + <note/> + </trans-unit> + <trans-unit id="About Direct method..." xml:space="preserve"> + <source>About Direct method...</source> + <target state="new">About Direct method...</target> + <note/> + </trans-unit> + <trans-unit id="About Encrypted DNS proxy method..." xml:space="preserve"> + <source>About Encrypted DNS proxy method...</source> + <target state="new">About Encrypted DNS proxy method...</target> + <note/> + </trans-unit> + <trans-unit id="About Mullvad bridges method..." xml:space="preserve"> + <source>About Mullvad bridges method...</source> + <target state="new">About Mullvad bridges method...</target> + <note/> + </trans-unit> + <trans-unit id="About Server IP override..." xml:space="preserve"> + <source>About Server IP override...</source> + <target state="new">About Server IP override...</target> + <note/> + </trans-unit> + <trans-unit id="Account" xml:space="preserve"> + <source>Account</source> + <target state="new">Account</target> + <note/> + </trans-unit> + <trans-unit id="Account created" xml:space="preserve"> + <source>Account created</source> + <target state="new">Account created</target> + <note/> + </trans-unit> + <trans-unit id="Account credit expires soon" xml:space="preserve"> + <source>Account credit expires soon</source> + <target state="new">Account credit expires soon</target> + <note/> + </trans-unit> + <trans-unit id="Account credit has expired" xml:space="preserve"> + <source>Account credit has expired</source> + <target state="new">Account credit has expired</target> + <note/> + </trans-unit> + <trans-unit id="Account deletion" xml:space="preserve"> + <source>Account deletion</source> + <target state="new">Account deletion</target> + <note/> + </trans-unit> + <trans-unit id="Account number" xml:space="preserve"> + <source>Account number</source> + <target state="new">Account number</target> + <note/> + </trans-unit> + <trans-unit id="Active features" xml:space="preserve"> + <source>Active features</source> + <target state="new">Active features</target> + <note/> + </trans-unit> + <trans-unit id="Add" xml:space="preserve"> + <source>Add</source> + <target state="new">Add</target> + <note/> + </trans-unit> + <trans-unit id="Add 30 days" xml:space="preserve"> + <source>Add 30 days</source> + <target state="new">Add 30 days</target> + <note/> + </trans-unit> + <trans-unit id="Add 90 days" xml:space="preserve"> + <source>Add 90 days</source> + <target state="new">Add 90 days</target> + <note/> + </trans-unit> + <trans-unit id="Add Time" xml:space="preserve"> + <source>Add Time</source> + <target state="new">Add Time</target> + <note/> + </trans-unit> + <trans-unit id="Add a server" xml:space="preserve"> + <source>Add a server</source> + <target state="new">Add a server</target> + <note/> + </trans-unit> + <trans-unit id="Add access method" xml:space="preserve"> + <source>Add access method</source> + <target state="new">Add access method</target> + <note/> + </trans-unit> + <trans-unit id="Add locations" xml:space="preserve"> + <source>Add locations</source> + <target state="new">Add locations</target> + <note/> + </trans-unit> + <trans-unit id="Add new list" xml:space="preserve"> + <source>Add new list</source> + <target state="new">Add new list</target> + <note/> + </trans-unit> + <trans-unit id="Add time" xml:space="preserve"> + <source>Add time</source> + <target state="new">Add time</target> + <note/> + </trans-unit> + <trans-unit id="Ads" xml:space="preserve"> + <source>Ads</source> + <target state="new">Ads</target> + <note/> + </trans-unit> + <trans-unit id="Adult content" xml:space="preserve"> + <source>Adult content</source> + <target state="new">Adult content</target> + <note/> + </trans-unit> + <trans-unit id="Agree and continue" xml:space="preserve"> + <source>Agree and continue</source> + <target state="new">Agree and continue</target> + <note/> + </trans-unit> + <trans-unit id="All" xml:space="preserve"> + <source>All</source> + <target state="new">All</target> + <note/> + </trans-unit> + <trans-unit id="All Providers" xml:space="preserve"> + <source>All Providers</source> + <target state="new">All Providers</target> + <note/> + </trans-unit> + <trans-unit id="All locations" xml:space="preserve"> + <source>All locations</source> + <target state="new">All locations</target> + <note/> + </trans-unit> + <trans-unit id="Any" xml:space="preserve"> + <source>Any</source> + <target state="new">Any</target> + <note/> + </trans-unit> + <trans-unit id="App logs" xml:space="preserve"> + <source>App logs</source> + <target state="new">App logs</target> + <note/> + </trans-unit> + <trans-unit id="AppStore receipt is not found on disk." xml:space="preserve"> + <source>AppStore receipt is not found on disk.</source> + <target state="new">AppStore receipt is not found on disk.</target> + <note/> + </trans-unit> + <trans-unit id="Are you sure you want to log %@ out?" xml:space="preserve"> + <source>Are you sure you want to log %@ out?</source> + <target state="new">Are you sure you want to log %@ out?</target> + <note/> + </trans-unit> + <trans-unit id="At least one method needs to be enabled." xml:space="preserve"> + <source>At least one method needs to be enabled.</source> + <target state="new">At least one method needs to be enabled.</target> + <note/> + </trans-unit> + <trans-unit id="Authentication" xml:space="preserve"> + <source>Authentication</source> + <target state="new">Authentication</target> + <note/> + </trans-unit> + <trans-unit id="Automatic" xml:space="preserve"> + <source>Automatic</source> + <target state="new">Automatic</target> + <note/> + </trans-unit> + <trans-unit id="BLOCKING INTERNET" xml:space="preserve"> + <source>BLOCKING INTERNET</source> + <target state="new">BLOCKING INTERNET</target> + <note/> + </trans-unit> + <trans-unit id="Back to editing" xml:space="preserve"> + <source>Back to editing</source> + <target state="new">Back to editing</target> + <note/> + </trans-unit> + <trans-unit id="Blocked connection" xml:space="preserve"> + <source>Blocked connection</source> + <target state="new">Blocked connection</target> + <note/> + </trans-unit> + <trans-unit id="Blocking internet: Your time on this account has expired. To continue using the internet, please add more time or disconnect the VPN." xml:space="preserve"> + <source>Blocking internet: Your time on this account has expired. To continue using the internet, please add more time or disconnect the VPN.</source> + <target state="new">Blocking internet: Your time on this account has expired. To continue using the internet, please add more time or disconnect the VPN.</target> + <note/> + </trans-unit> + <trans-unit id="By enabling "Direct only" you will have to manually select a server that is DAITA-enabled. Multihop won't automatically be used to enable DAITA with any server." xml:space="preserve"> + <source>By enabling "Direct only" you will have to manually select a server that is DAITA-enabled. Multihop won't automatically be used to enable DAITA with any server.</source> + <target state="new">By enabling "Direct only" you will have to manually select a server that is DAITA-enabled. Multihop won't automatically be used to enable DAITA with any server.</target> + <note/> + </trans-unit> + <trans-unit id="By enabling "Direct only" you will have to manually select a server that is DAITA-enabled. This can cause you to end up in a blocked state until you have selected a compatible server in the "Select location" view." xml:space="preserve"> + <source>By enabling "Direct only" you will have to manually select a server that is DAITA-enabled. This can cause you to end up in a blocked state until you have selected a compatible server in the "Select location" view.</source> + <target state="new">By enabling "Direct only" you will have to manually select a server that is DAITA-enabled. This can cause you to end up in a blocked state until you have selected a compatible server in the "Select location" view.</target> + <note/> + </trans-unit> + <trans-unit id="Cancel" xml:space="preserve"> + <source>Cancel</source> + <target state="new">Cancel</target> + <note/> + </trans-unit> + <trans-unit id="Cannot complete the purchase" xml:space="preserve"> + <source>Cannot complete the purchase</source> + <target state="new">Cannot complete the purchase</target> + <note/> + </trans-unit> + <trans-unit id="Cannot read the AppStore receipt from disk" xml:space="preserve"> + <source>Cannot read the AppStore receipt from disk</source> + <target state="new">Cannot read the AppStore receipt from disk</target> + <note/> + </trans-unit> + <trans-unit id="Cannot refresh the AppStore receipt: %@" xml:space="preserve"> + <source>Cannot refresh the AppStore receipt: %@</source> + <target state="new">Cannot refresh the AppStore receipt: %@</target> + <note/> + </trans-unit> + <trans-unit id="Cannot restore purchases" xml:space="preserve"> + <source>Cannot restore purchases</source> + <target state="new">Cannot restore purchases</target> + <note/> + </trans-unit> + <trans-unit id="Checking account number" xml:space="preserve"> + <source>Checking account number</source> + <target state="new">Checking account number</target> + <note/> + </trans-unit> + <trans-unit id="Cipher" xml:space="preserve"> + <source>Cipher</source> + <target state="new">Cipher</target> + <note/> + </trans-unit> + <trans-unit id="Clear" xml:space="preserve"> + <source>Clear</source> + <target state="new">Clear</target> + <note/> + </trans-unit> + <trans-unit id="Clear all overrides" xml:space="preserve"> + <source>Clear all overrides</source> + <target state="new">Clear all overrides</target> + <note/> + </trans-unit> + <trans-unit id="Clear all overrides?" xml:space="preserve"> + <source>Clear all overrides?</source> + <target state="new">Clear all overrides?</target> + <note/> + </trans-unit> + <trans-unit id="Clearing the imported overrides changes the server IPs, in the Select location view, back to default." xml:space="preserve"> + <source>Clearing the imported overrides changes the server IPs, in the Select location view, back to default.</source> + <target state="new">Clearing the imported overrides changes the server IPs, in the Select location view, back to default.</target> + <note/> + </trans-unit> + <trans-unit id="Client is not allowed to issue the request." xml:space="preserve"> + <source>Client is not allowed to issue the request.</source> + <target state="new">Client is not allowed to issue the request.</target> + <note/> + </trans-unit> + <trans-unit id="Collapses this location." xml:space="preserve"> + <source>Collapses this location.</source> + <target state="new">Collapses this location.</target> + <note/> + </trans-unit> + <trans-unit id="Congrats!" xml:space="preserve"> + <source>Congrats!</source> + <target state="new">Congrats!</target> + <note/> + </trans-unit> + <trans-unit id="Connect" xml:space="preserve"> + <source>Connect</source> + <target state="new">Connect</target> + <note/> + </trans-unit> + <trans-unit id="Connected" xml:space="preserve"> + <source>Connected</source> + <target state="new">Connected</target> + <note/> + </trans-unit> + <trans-unit id="Connected to %@, %@" xml:space="preserve"> + <source>Connected to %1$@, %2$@</source> + <target state="new">Connected to %1$@, %2$@</target> + <note/> + </trans-unit> + <trans-unit id="Connecting to %@, %@" xml:space="preserve"> + <source>Connecting to %1$@, %2$@</source> + <target state="new">Connecting to %1$@, %2$@</target> + <note/> + </trans-unit> + <trans-unit id="Connecting..." xml:space="preserve"> + <source>Connecting...</source> + <target state="new">Connecting...</target> + <note/> + </trans-unit> + <trans-unit id="Connection details" xml:space="preserve"> + <source>Connection details</source> + <target state="new">Connection details</target> + <note/> + </trans-unit> + <trans-unit id="Continue with login" xml:space="preserve"> + <source>Continue with login</source> + <target state="new">Continue with login</target> + <note/> + </trans-unit> + <trans-unit id="Copy to pasteboard" xml:space="preserve"> + <source>Copy to pasteboard</source> + <target state="new">Copy to pasteboard</target> + <note/> + </trans-unit> + <trans-unit id="Correct account number" xml:space="preserve"> + <source>Correct account number</source> + <target state="new">Correct account number</target> + <note/> + </trans-unit> + <trans-unit id="Create" xml:space="preserve"> + <source>Create</source> + <target state="new">Create</target> + <note/> + </trans-unit> + <trans-unit id="Create account" xml:space="preserve"> + <source>Create account</source> + <target state="new">Create account</target> + <note/> + </trans-unit> + <trans-unit id="Created: %@" xml:space="preserve"> + <source>Created: %@</source> + <target state="new">Created: %@</target> + <note/> + </trans-unit> + <trans-unit id="Creating new account" xml:space="preserve"> + <source>Creating new account</source> + <target state="new">Creating new account</target> + <note/> + </trans-unit> + <trans-unit id="Creating quantum secure connection" xml:space="preserve"> + <source>Creating quantum secure connection</source> + <target state="new">Creating quantum secure connection</target> + <note/> + </trans-unit> + <trans-unit id="Creating secure connection" xml:space="preserve"> + <source>Creating secure connection</source> + <target state="new">Creating secure connection</target> + <note/> + </trans-unit> + <trans-unit id="Current device" xml:space="preserve"> + <source>Current device</source> + <target state="new">Current device</target> + <note/> + </trans-unit> + <trans-unit id="Custom" xml:space="preserve"> + <source>Custom</source> + <target state="new">Custom</target> + <note/> + </trans-unit> + <trans-unit id="Custom DNS" xml:space="preserve"> + <source>Custom DNS</source> + <target state="new">Custom DNS</target> + <note/> + </trans-unit> + <trans-unit id="Custom lists" xml:space="preserve"> + <source>Custom lists</source> + <target state="new">Custom lists</target> + <note/> + </trans-unit> + <trans-unit id="DAITA" xml:space="preserve"> + <source>DAITA</source> + <target state="new">DAITA</target> + <note/> + </trans-unit> + <trans-unit id="DAITA (Defence against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic. If anyone is monitoring your connection, this makes it significantly harder for them to identify what websites you are visiting. It does this by carefully adding network noise and making all network packets the same size. Not all our servers are DAITA-enabled. Therefore, we use multihop automatically to enable DAITA with any server. Attention: Be cautious if you have a limited data plan as this feature will increase your network traffic." xml:space="preserve"> + <source>DAITA (Defence against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic. If anyone is monitoring your connection, this makes it significantly harder for them to identify what websites you are visiting. +It does this by carefully adding network noise and making all network packets the same size. +Not all our servers are DAITA-enabled. Therefore, we use multihop automatically to enable DAITA with any server. +Attention: Be cautious if you have a limited data plan as this feature will increase your network traffic.</source> + <target state="new">DAITA (Defence against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic. If anyone is monitoring your connection, this makes it significantly harder for them to identify what websites you are visiting. +It does this by carefully adding network noise and making all network packets the same size. +Not all our servers are DAITA-enabled. Therefore, we use multihop automatically to enable DAITA with any server. +Attention: Be cautious if you have a limited data plan as this feature will increase your network traffic.</target> + <note/> + </trans-unit> + <trans-unit id="DAITA isn't available at the currently selected location. After enabling, please go to the "Select location" view and select a location that supports DAITA." xml:space="preserve"> + <source>DAITA isn't available at the currently selected location. After enabling, please go to the "Select location" view and select a location that supports DAITA.</source> + <target state="new">DAITA isn't available at the currently selected location. After enabling, please go to the "Select location" view and select a location that supports DAITA.</target> + <note/> + </trans-unit> + <trans-unit id="DAITA isn't available on the current entry server. After enabling, please go to the "Select location" view and select an entry location that supports DAITA." xml:space="preserve"> + <source>DAITA isn't available on the current entry server. After enabling, please go to the "Select location" view and select an entry location that supports DAITA.</source> + <target state="new">DAITA isn't available on the current entry server. After enabling, please go to the "Select location" view and select an entry location that supports DAITA.</target> + <note/> + </trans-unit> + <trans-unit id="DAITA-enabled" xml:space="preserve"> + <source>DAITA-enabled</source> + <target state="new">DAITA-enabled</target> + <note/> + </trans-unit> + <trans-unit id="DAITA: Multihop" xml:space="preserve"> + <source>DAITA: Multihop</source> + <target state="new">DAITA: Multihop</target> + <note/> + </trans-unit> + <trans-unit id="DNS content blockers" xml:space="preserve"> + <source>DNS content blockers</source> + <target state="new">DNS content blockers</target> + <note/> + </trans-unit> + <trans-unit id="DNS settings" xml:space="preserve"> + <source>DNS settings</source> + <target state="new">DNS settings</target> + <note/> + </trans-unit> + <trans-unit id="Delete" xml:space="preserve"> + <source>Delete</source> + <target state="new">Delete</target> + <note/> + </trans-unit> + <trans-unit id="Delete Account" xml:space="preserve"> + <source>Delete Account</source> + <target state="new">Delete Account</target> + <note/> + </trans-unit> + <trans-unit id="Delete account" xml:space="preserve"> + <source>Delete account</source> + <target state="new">Delete account</target> + <note/> + </trans-unit> + <trans-unit id="Delete list" xml:space="preserve"> + <source>Delete list</source> + <target state="new">Delete list</target> + <note/> + </trans-unit> + <trans-unit id="Delete method" xml:space="preserve"> + <source>Delete method</source> + <target state="new">Delete method</target> + <note/> + </trans-unit> + <trans-unit id="Deleting account..." xml:space="preserve"> + <source>Deleting account...</source> + <target state="new">Deleting account...</target> + <note/> + </trans-unit> + <trans-unit id="Device is inactive" xml:space="preserve"> + <source>Device is inactive</source> + <target state="new">Device is inactive</target> + <note/> + </trans-unit> + <trans-unit id="Device name" xml:space="preserve"> + <source>Device name</source> + <target state="new">Device name</target> + <note/> + </trans-unit> + <trans-unit id="Device name: %@" xml:space="preserve"> + <source>Device name: %@</source> + <target state="new">Device name: %@</target> + <note/> + </trans-unit> + <trans-unit id="Direct" xml:space="preserve"> + <source>Direct</source> + <target state="new">Direct</target> + <note/> + </trans-unit> + <trans-unit id="Direct only" xml:space="preserve"> + <source>Direct only</source> + <target state="new">Direct only</target> + <note/> + </trans-unit> + <trans-unit id="Disable all content blockers to activate this setting." xml:space="preserve"> + <source>Disable all content blockers to activate this setting.</source> + <target state="new">Disable all content blockers to activate this setting.</target> + <note/> + </trans-unit> + <trans-unit id="Disabled" xml:space="preserve"> + <source>Disabled</source> + <target state="new">Disabled</target> + <note/> + </trans-unit> + <trans-unit id="Disabling" xml:space="preserve"> + <source>Disabling</source> + <target state="new">Disabling</target> + <note/> + </trans-unit> + <trans-unit id="Discard changes" xml:space="preserve"> + <source>Discard changes</source> + <target state="new">Discard changes</target> + <note/> + </trans-unit> + <trans-unit id="Disconnect" xml:space="preserve"> + <source>Disconnect</source> + <target state="new">Disconnect</target> + <note/> + </trans-unit> + <trans-unit id="Disconnected" xml:space="preserve"> + <source>Disconnected</source> + <target state="new">Disconnected</target> + <note/> + </trans-unit> + <trans-unit id="Disconnecting" xml:space="preserve"> + <source>Disconnecting</source> + <target state="new">Disconnecting</target> + <note/> + </trans-unit> + <trans-unit id="Disconnecting..." xml:space="preserve"> + <source>Disconnecting...</source> + <target state="new">Disconnecting...</target> + <note/> + </trans-unit> + <trans-unit id="Do you agree to remaining anonymous?" xml:space="preserve"> + <source>Do you agree to remaining anonymous?</source> + <target state="new">Do you agree to remaining anonymous?</target> + <note/> + </trans-unit> + <trans-unit id="Done" xml:space="preserve"> + <source>Done</source> + <target state="new">Done</target> + <note/> + </trans-unit> + <trans-unit id="Don’t have an account number?" xml:space="preserve"> + <source>Don’t have an account number?</source> + <target state="new">Don’t have an account number?</target> + <note/> + </trans-unit> + <trans-unit id="Edit custom list" xml:space="preserve"> + <source>Edit custom list</source> + <target state="new">Edit custom list</target> + <note/> + </trans-unit> + <trans-unit id="Edit lists" xml:space="preserve"> + <source>Edit lists</source> + <target state="new">Edit lists</target> + <note/> + </trans-unit> + <trans-unit id="Edit locations" xml:space="preserve"> + <source>Edit locations</source> + <target state="new">Edit locations</target> + <note/> + </trans-unit> + <trans-unit id="Edit message" xml:space="preserve"> + <source>Edit message</source> + <target state="new">Edit message</target> + <note/> + </trans-unit> + <trans-unit id="Enable" xml:space="preserve"> + <source>Enable</source> + <target state="new">Enable</target> + <note/> + </trans-unit> + <trans-unit id="Enable "%@"" xml:space="preserve"> + <source>Enable "%@"</source> + <target state="new">Enable "%@"</target> + <note/> + </trans-unit> + <trans-unit id="Enable method" xml:space="preserve"> + <source>Enable method</source> + <target state="new">Enable method</target> + <note/> + </trans-unit> + <trans-unit id="Enabling" xml:space="preserve"> + <source>Enabling</source> + <target state="new">Enabling</target> + <note/> + </trans-unit> + <trans-unit id="Encrypted DNS proxy" xml:space="preserve"> + <source>Encrypted DNS proxy</source> + <target state="new">Encrypted DNS proxy</target> + <note/> + </trans-unit> + <trans-unit id="Enter IP" xml:space="preserve"> + <source>Enter IP</source> + <target state="new">Enter IP</target> + <note/> + </trans-unit> + <trans-unit id="Enter voucher code" xml:space="preserve"> + <source>Enter voucher code</source> + <target state="new">Enter voucher code</target> + <note/> + </trans-unit> + <trans-unit id="Enter your account number" xml:space="preserve"> + <source>Enter your account number</source> + <target state="new">Enter your account number</target> + <note/> + </trans-unit> + <trans-unit id="Entry" xml:space="preserve"> + <source>Entry</source> + <target state="new">Entry</target> + <note/> + </trans-unit> + <trans-unit id="Exit" xml:space="preserve"> + <source>Exit</source> + <target state="new">Exit</target> + <note/> + </trans-unit> + <trans-unit id="Expands this location." xml:space="preserve"> + <source>Expands this location.</source> + <target state="new">Expands this location.</target> + <note/> + </trans-unit> + <trans-unit id="FAQs & Guides" xml:space="preserve"> + <source>FAQs & Guides</source> + <target state="new">FAQs & Guides</target> + <note/> + </trans-unit> + <trans-unit id="Failed to connect to App store, please try again later." xml:space="preserve"> + <source>Failed to connect to App store, please try again later.</source> + <target state="new">Failed to connect to App store, please try again later.</target> + <note/> + </trans-unit> + <trans-unit id="Failed to send" xml:space="preserve"> + <source>Failed to send</source> + <target state="new">Failed to send</target> + <note/> + </trans-unit> + <trans-unit id="Failed to send the receipt to server: %@" xml:space="preserve"> + <source>Failed to send the receipt to server: %@</source> + <target state="new">Failed to send the receipt to server: %@</target> + <note/> + </trans-unit> + <trans-unit id="Failed to start the tunnel." xml:space="preserve"> + <source>Failed to start the tunnel.</source> + <target state="new">Failed to start the tunnel.</target> + <note/> + </trans-unit> + <trans-unit id="Failed to start the tunnel: %@." xml:space="preserve"> + <source>Failed to start the tunnel: %@.</source> + <target state="new">Failed to start the tunnel: %@.</target> + <note/> + </trans-unit> + <trans-unit id="Failed to stop the tunnel." xml:space="preserve"> + <source>Failed to stop the tunnel.</source> + <target state="new">Failed to stop the tunnel.</target> + <note/> + </trans-unit> + <trans-unit id="Failed to stop the tunnel: %@." xml:space="preserve"> + <source>Failed to stop the tunnel: %@.</source> + <target state="new">Failed to stop the tunnel: %@.</target> + <note/> + </trans-unit> + <trans-unit id="Failed to validate account number: %@" xml:space="preserve"> + <source>Failed to validate account number: %@</source> + <target state="new">Failed to validate account number: %@</target> + <note/> + </trans-unit> + <trans-unit id="Fetching devices..." xml:space="preserve"> + <source>Fetching devices...</source> + <target state="new">Fetching devices...</target> + <note/> + </trans-unit> + <trans-unit id="Filter" xml:space="preserve"> + <source>Filter</source> + <target state="new">Filter</target> + <note/> + </trans-unit> + <trans-unit id="Filtered:" xml:space="preserve"> + <source>Filtered:</source> + <target state="new">Filtered:</target> + <note/> + </trans-unit> + <trans-unit id="Gambling" xml:space="preserve"> + <source>Gambling</source> + <target state="new">Gambling</target> + <note/> + </trans-unit> + <trans-unit id="Go ahead and start using the app to begin reclaiming your online privacy. To continue your journey as a privacy ninja, visit our website to pick up other privacy-friendly habits and tools." xml:space="preserve"> + <source>Go ahead and start using the app to begin reclaiming your online privacy. +To continue your journey as a privacy ninja, visit our website to pick up other privacy-friendly habits and tools.</source> + <target state="new">Go ahead and start using the app to begin reclaiming your online privacy. +To continue your journey as a privacy ninja, visit our website to pick up other privacy-friendly habits and tools.</target> + <note/> + </trans-unit> + <trans-unit id="Go to login" xml:space="preserve"> + <source>Go to login</source> + <target state="new">Go to login</target> + <note/> + </trans-unit> + <trans-unit id="Going to login will unblock the Internet on this device." xml:space="preserve"> + <source>Going to login will unblock the Internet on this device.</source> + <target state="new">Going to login will unblock the Internet on this device.</target> + <note/> + </trans-unit> + <trans-unit id="Got it!" xml:space="preserve"> + <source>Got it!</source> + <target state="new">Got it!</target> + <note/> + </trans-unit> + <trans-unit id="Here’s your account number. Save it!" xml:space="preserve"> + <source>Here’s your account number. Save it!</source> + <target state="new">Here’s your account number. Save it!</target> + <note/> + </trans-unit> + <trans-unit id="Hide account number" xml:space="preserve"> + <source>Hide account number</source> + <target state="new">Hide account number</target> + <note/> + </trans-unit> + <trans-unit id="If an observer monitors these data packets, DAITA makes it significantly harder for them to identify which websites you are visiting or with whom you are communicating. DAITA does this by carefully adding network noise and making all network packets the same size. Not all our servers are DAITA-enabled. Therefore, we use multihop automatically to enable DAITA with any server. " xml:space="preserve"> + <source>If an observer monitors these data packets, DAITA makes it significantly harder for them to identify which websites you are visiting or with whom you are communicating. + +DAITA does this by carefully adding network noise and making all network packets the same size. + +Not all our servers are DAITA-enabled. Therefore, we use multihop automatically to enable DAITA with any server. +</source> + <target state="new">If an observer monitors these data packets, DAITA makes it significantly harder for them to identify which websites you are visiting or with whom you are communicating. + +DAITA does this by carefully adding network noise and making all network packets the same size. + +Not all our servers are DAITA-enabled. Therefore, we use multihop automatically to enable DAITA with any server. +</target> + <note/> + </trans-unit> + <trans-unit id="If needed we will contact you at %@" xml:space="preserve"> + <source>If needed we will contact you at %@</source> + <target state="new">If needed we will contact you at %@</target> + <note/> + </trans-unit> + <trans-unit id="If you are having issues connecting to VPN servers, please contact support." xml:space="preserve"> + <source>If you are having issues connecting to VPN servers, please contact support.</source> + <target state="new">If you are having issues connecting to VPN servers, please contact support.</target> + <note/> + </trans-unit> + <trans-unit id="If you are not connected to our VPN, then the Encrypted DNS proxy will use your own non-VPN IP when connecting. The DoH servers are hosted by one of the following providers: Quad9 or Cloudflare." xml:space="preserve"> + <source>If you are not connected to our VPN, then the Encrypted DNS proxy will use your own non-VPN IP when connecting. +The DoH servers are hosted by one of the following providers: Quad9 or Cloudflare.</source> + <target state="new">If you are not connected to our VPN, then the Encrypted DNS proxy will use your own non-VPN IP when connecting. +The DoH servers are hosted by one of the following providers: Quad9 or Cloudflare.</target> + <note/> + </trans-unit> + <trans-unit id="If you disconnect now, you won’t be able to secure your connection until the device is online." xml:space="preserve"> + <source>If you disconnect now, you won’t be able to secure your connection until the device is online.</source> + <target state="new">If you disconnect now, you won’t be able to secure your connection until the device is online.</target> + <note/> + </trans-unit> + <trans-unit id="If you exit the form and try again later, the information you already entered will still be here." xml:space="preserve"> + <source>If you exit the form and try again later, the information you already entered will still be here.</source> + <target state="new">If you exit the form and try again later, the information you already entered will still be here.</target> + <note/> + </trans-unit> + <trans-unit id="If you haven’t received additional VPN time after purchasing" xml:space="preserve"> + <source>If you haven’t received additional VPN time after purchasing</source> + <target state="new">If you haven’t received additional VPN time after purchasing</target> + <note/> + </trans-unit> + <trans-unit id="If you still experience issues you can email our support directly at **%@**. Please attach your app log to your email." xml:space="preserve"> + <source>If you still experience issues you can email our support directly at **%@**. Please attach your app log to your email.</source> + <target state="new">If you still experience issues you can email our support directly at **%@**. Please attach your app log to your email.</target> + <note/> + </trans-unit> + <trans-unit id="Import" xml:space="preserve"> + <source>Import</source> + <target state="new">Import</target> + <note/> + </trans-unit> + <trans-unit id="Import %@ was successful, overrides are now active." xml:space="preserve"> + <source>Import %@ was successful, overrides are now active.</source> + <target state="new">Import %@ was successful, overrides are now active.</target> + <note/> + </trans-unit> + <trans-unit id="Import %@ was unsuccessful, please try again." xml:space="preserve"> + <source>Import %@ was unsuccessful, please try again.</source> + <target state="new">Import %@ was unsuccessful, please try again.</target> + <note/> + </trans-unit> + <trans-unit id="Import file" xml:space="preserve"> + <source>Import file</source> + <target state="new">Import file</target> + <note/> + </trans-unit> + <trans-unit id="Import files or text with the new IP addresses for the servers in the Select location view." xml:space="preserve"> + <source>Import files or text with the new IP addresses for the servers in the Select location view.</source> + <target state="new">Import files or text with the new IP addresses for the servers in the Select location view.</target> + <note/> + </trans-unit> + <trans-unit id="Import successful" xml:space="preserve"> + <source>Import successful</source> + <target state="new">Import successful</target> + <note/> + </trans-unit> + <trans-unit id="Import via text" xml:space="preserve"> + <source>Import via text</source> + <target state="new">Import via text</target> + <note/> + </trans-unit> + <trans-unit id="In" xml:space="preserve"> + <source>In</source> + <target state="new">In</target> + <note/> + </trans-unit> + <trans-unit id="In use" xml:space="preserve"> + <source>In use</source> + <target state="new">In use</target> + <note/> + </trans-unit> + <trans-unit id="Include all networks" xml:space="preserve"> + <source>Include all networks</source> + <target state="new">Include all networks</target> + <note/> + </trans-unit> + <trans-unit id="Internal error occurred. Settings will be reset to defaults and device logged out." xml:space="preserve"> + <source>Internal error occurred. Settings will be reset to defaults and device logged out.</source> + <target state="new">Internal error occurred. Settings will be reset to defaults and device logged out.</target> + <note/> + </trans-unit> + <trans-unit id="Internal error." xml:space="preserve"> + <source>Internal error.</source> + <target state="new">Internal error.</target> + <note/> + </trans-unit> + <trans-unit id="Invalid account" xml:space="preserve"> + <source>Invalid account</source> + <target state="new">Invalid account</target> + <note/> + </trans-unit> + <trans-unit id="Invalid device state." xml:space="preserve"> + <source>Invalid device state.</source> + <target state="new">Invalid device state.</target> + <note/> + </trans-unit> + <trans-unit id="Invalid purchase identifier." xml:space="preserve"> + <source>Invalid purchase identifier.</source> + <target state="new">Invalid purchase identifier.</target> + <note/> + </trans-unit> + <trans-unit id="It looks like you have entered a Mullvad account number instead of a voucher code. Do you want to log in to an existing account? If so, click log out below to log in with the other account number." xml:space="preserve"> + <source>It looks like you have entered a Mullvad account number instead of a voucher code. Do you want to log in to an existing account? +If so, click log out below to log in with the other account number.</source> + <target state="new">It looks like you have entered a Mullvad account number instead of a voucher code. Do you want to log in to an existing account? +If so, click log out below to log in with the other account number.</target> + <note/> + </trans-unit> + <trans-unit id="Language" xml:space="preserve"> + <source>Language</source> + <target state="new">Language</target> + <note/> + </trans-unit> + <trans-unit id="Last four digits of the account number are incorrect" xml:space="preserve"> + <source>Last four digits of the account number are incorrect</source> + <target state="new">Last four digits of the account number are incorrect</target> + <note/> + </trans-unit> + <trans-unit id="Last used account" xml:space="preserve"> + <source>Last used account</source> + <target state="new">Last used account</target> + <note/> + </trans-unit> + <trans-unit id="Learn about privacy" xml:space="preserve"> + <source>Learn about privacy</source> + <target state="new">Learn about privacy</target> + <note/> + </trans-unit> + <trans-unit id="Less than a day" xml:space="preserve"> + <source>Less than a day</source> + <target state="new">Less than a day</target> + <note/> + </trans-unit> + <trans-unit id="Local network sharing" xml:space="preserve"> + <source>Local network sharing</source> + <target state="new">Local network sharing</target> + <note/> + </trans-unit> + <trans-unit id="Log in" xml:space="preserve"> + <source>Log in</source> + <target state="new">Log in</target> + <note/> + </trans-unit> + <trans-unit id="Log out" xml:space="preserve"> + <source>Log out</source> + <target state="new">Log out</target> + <note/> + </trans-unit> + <trans-unit id="Logged in" xml:space="preserve"> + <source>Logged in</source> + <target state="new">Logged in</target> + <note/> + </trans-unit> + <trans-unit id="Logging in..." xml:space="preserve"> + <source>Logging in...</source> + <target state="new">Logging in...</target> + <note/> + </trans-unit> + <trans-unit id="Logging out..." xml:space="preserve"> + <source>Logging out...</source> + <target state="new">Logging out...</target> + <note/> + </trans-unit> + <trans-unit id="Login" xml:space="preserve"> + <source>Login</source> + <target state="new">Login</target> + <note/> + </trans-unit> + <trans-unit id="Login failed" xml:space="preserve"> + <source>Login failed</source> + <target state="new">Login failed</target> + <note/> + </trans-unit> + <trans-unit id="Make a purchase with StoreKit2" xml:space="preserve"> + <source>Make a purchase with StoreKit2</source> + <target state="new">Make a purchase with StoreKit2</target> + <note/> + </trans-unit> + <trans-unit id="Malware" xml:space="preserve"> + <source>Malware</source> + <target state="new">Malware</target> + <note/> + </trans-unit> + <trans-unit id="Manage default and setup custom methods to access the Mullvad API." xml:space="preserve"> + <source>Manage default and setup custom methods to access the Mullvad API.</source> + <target state="new">Manage default and setup custom methods to access the Mullvad API.</target> + <note/> + </trans-unit> + <trans-unit id="Manage default and setup custom methods to access the Mullvad API. " xml:space="preserve"> + <source>Manage default and setup custom methods to access the Mullvad API. </source> + <target state="new">Manage default and setup custom methods to access the Mullvad API. </target> + <note/> + </trans-unit> + <trans-unit id="Manage devices" xml:space="preserve"> + <source>Manage devices</source> + <target state="new">Manage devices</target> + <note/> + </trans-unit> + <trans-unit id="Method settings" xml:space="preserve"> + <source>Method settings</source> + <target state="new">Method settings</target> + <note/> + </trans-unit> + <trans-unit id="Mullvad bridges" xml:space="preserve"> + <source>Mullvad bridges</source> + <target state="new">Mullvad bridges</target> + <note/> + </trans-unit> + <trans-unit id="Multihop" xml:space="preserve"> + <source>Multihop</source> + <target state="new">Multihop</target> + <note/> + </trans-unit> + <trans-unit id="Multihop is being used to enable DAITA for your selected location." xml:space="preserve"> + <source>Multihop is being used to enable DAITA for your selected location.</source> + <target state="new">Multihop is being used to enable DAITA for your selected location.</target> + <note/> + </trans-unit> + <trans-unit id="Multihop routes your traffic into one WireGuard server and out another, making it harder to trace. This results in increased latency but increases anonymity online." xml:space="preserve"> + <source>Multihop routes your traffic into one WireGuard server and out another, making it harder to trace. +This results in increased latency but increases anonymity online.</source> + <target state="new">Multihop routes your traffic into one WireGuard server and out another, making it harder to trace. +This results in increased latency but increases anonymity online.</target> + <note/> + </trans-unit> + <trans-unit id="Multihop routes your traffic into one WireGuard server and out another, making it harder to trace. This results in increased latency but increases anonymity online." xml:space="preserve"> + <source>Multihop routes your traffic into one WireGuard server and out another, making it harder to trace. This results in increased latency but increases anonymity online.</source> + <target state="new">Multihop routes your traffic into one WireGuard server and out another, making it harder to trace. This results in increased latency but increases anonymity online.</target> + <note/> + </trans-unit> + <trans-unit id="Multiple validation errors occurred." xml:space="preserve"> + <source>Multiple validation errors occurred.</source> + <target state="new">Multiple validation errors occurred.</target> + <note/> + </trans-unit> + <trans-unit id="NETWORK ISSUES" xml:space="preserve"> + <source>NETWORK ISSUES</source> + <target state="new">NETWORK ISSUES</target> + <note/> + </trans-unit> + <trans-unit id="NEW DEVICE CREATED" xml:space="preserve"> + <source>NEW DEVICE CREATED</source> + <target state="new">NEW DEVICE CREATED</target> + <note/> + </trans-unit> + <trans-unit id="NEW VERSION INSTALLED" xml:space="preserve"> + <source>NEW VERSION INSTALLED</source> + <target state="new">NEW VERSION INSTALLED</target> + <note/> + </trans-unit> + <trans-unit id="Name" xml:space="preserve"> + <source>Name</source> + <target state="new">Name</target> + <note/> + </trans-unit> + <trans-unit id="Name should be no longer than %i characters." xml:space="preserve"> + <source>Name should be no longer than %i characters.</source> + <target state="new">Name should be no longer than %i characters.</target> + <note/> + </trans-unit> + <trans-unit id="Network error: %@" xml:space="preserve"> + <source>Network error: %@</source> + <target state="new">Network error: %@</target> + <note/> + </trans-unit> + <trans-unit id="New custom list" xml:space="preserve"> + <source>New custom list</source> + <target state="new">New custom list</target> + <note/> + </trans-unit> + <trans-unit id="Next" xml:space="preserve"> + <source>Next</source> + <target state="new">Next</target> + <note/> + </trans-unit> + <trans-unit id="No matching relays found, check your filter settings." xml:space="preserve"> + <source>No matching relays found, check your filter settings.</source> + <target state="new">No matching relays found, check your filter settings.</target> + <note/> + </trans-unit> + <trans-unit id="No matching servers" xml:space="preserve"> + <source>No matching servers</source> + <target state="new">No matching servers</target> + <note/> + </trans-unit> + <trans-unit id="No network" xml:space="preserve"> + <source>No network</source> + <target state="new">No network</target> + <note/> + </trans-unit> + <trans-unit id="No overrides imported" xml:space="preserve"> + <source>No overrides imported</source> + <target state="new">No overrides imported</target> + <note/> + </trans-unit> + <trans-unit id="OUT OF TIME" xml:space="preserve"> + <source>OUT OF TIME</source> + <target state="new">OUT OF TIME</target> + <note/> + </trans-unit> + <trans-unit id="Obfuscation" xml:space="preserve"> + <source>Obfuscation</source> + <target state="new">Obfuscation</target> + <note/> + </trans-unit> + <trans-unit id="Obfuscation hides the WireGuard traffic inside another protocol. It can be used to help circumvent censorship and other types of filtering, where a plain WireGuard connection would be blocked." xml:space="preserve"> + <source>Obfuscation hides the WireGuard traffic inside another protocol. It can be used to help circumvent censorship and other types of filtering, where a plain WireGuard connection would be blocked.</source> + <target state="new">Obfuscation hides the WireGuard traffic inside another protocol. It can be used to help circumvent censorship and other types of filtering, where a plain WireGuard connection would be blocked.</target> + <note/> + </trans-unit> + <trans-unit id="Obscured" xml:space="preserve"> + <source>Obscured</source> + <target state="new">Obscured</target> + <note/> + </trans-unit> + <trans-unit id="Off" xml:space="preserve"> + <source>Off</source> + <target state="new">Off</target> + <note/> + </trans-unit> + <trans-unit id="On" xml:space="preserve"> + <source>On</source> + <target state="new">On</target> + <note/> + </trans-unit> + <trans-unit id="On some networks, where various types of censorship are being used, our server IP addresses are sometimes blocked." xml:space="preserve"> + <source>On some networks, where various types of censorship are being used, our server IP addresses are sometimes blocked.</source> + <target state="new">On some networks, where various types of censorship are being used, our server IP addresses are sometimes blocked.</target> + <note/> + </trans-unit> + <trans-unit id="On some networks, where various types of censorship are being used, the API servers might not be directly reachable." xml:space="preserve"> + <source>On some networks, where various types of censorship are being used, the API servers might not be directly reachable.</source> + <target state="new">On some networks, where various types of censorship are being used, the API servers might not be directly reachable.</target> + <note/> + </trans-unit> + <trans-unit id="Open DAITA settings" xml:space="preserve"> + <source>Open DAITA settings</source> + <target state="new">Open DAITA settings</target> + <note/> + </trans-unit> + <trans-unit id="Optional" xml:space="preserve"> + <source>Optional</source> + <target state="new">Optional</target> + <note/> + </trans-unit> + <trans-unit id="Out IPv4" xml:space="preserve"> + <source>Out IPv4</source> + <target state="new">Out IPv4</target> + <note/> + </trans-unit> + <trans-unit id="Out IPv6" xml:space="preserve"> + <source>Out IPv6</source> + <target state="new">Out IPv6</target> + <note/> + </trans-unit> + <trans-unit id="Out of time" xml:space="preserve"> + <source>Out of time</source> + <target state="new">Out of time</target> + <note/> + </trans-unit> + <trans-unit id="Overrides active" xml:space="preserve"> + <source>Overrides active</source> + <target state="new">Overrides active</target> + <note/> + </trans-unit> + <trans-unit id="Owned" xml:space="preserve"> + <source>Owned</source> + <target state="new">Owned</target> + <note/> + </trans-unit> + <trans-unit id="Ownership" xml:space="preserve"> + <source>Ownership</source> + <target state="new">Ownership</target> + <note/> + </trans-unit> + <trans-unit id="Paid until" xml:space="preserve"> + <source>Paid until</source> + <target state="new">Paid until</target> + <note/> + </trans-unit> + <trans-unit id="Password" xml:space="preserve"> + <source>Password</source> + <target state="new">Password</target> + <note/> + </trans-unit> + <trans-unit id="Performs a connection test to a Mullvad API server via this access method." xml:space="preserve"> + <source>Performs a connection test to a Mullvad API server via this access method.</source> + <target state="new">Performs a connection test to a Mullvad API server via this access method.</target> + <note/> + </trans-unit> + <trans-unit id="Please enter a valid IPv4 or IPv6 address." xml:space="preserve"> + <source>Please enter a valid IPv4 or IPv6 address.</source> + <target state="new">Please enter a valid IPv4 or IPv6 address.</target> + <note/> + </trans-unit> + <trans-unit id="Please enter a valid port." xml:space="preserve"> + <source>Please enter a valid port.</source> + <target state="new">Please enter a valid port.</target> + <note/> + </trans-unit> + <trans-unit id="Please log out of at least one by removing it from the list below. You can find the corresponding device name under the device’s Account settings." xml:space="preserve"> + <source>Please log out of at least one by removing it from the list below. You can find the corresponding device name under the device’s Account settings.</source> + <target state="new">Please log out of at least one by removing it from the list below. You can find the corresponding device name under the device’s Account settings.</target> + <note/> + </trans-unit> + <trans-unit id="Please retry by using the "Restore purchases" button." xml:space="preserve"> + <source>Please retry by using the "Restore purchases" button.</source> + <target state="new">Please retry by using the "Restore purchases" button.</target> + <note/> + </trans-unit> + <trans-unit id="Port" xml:space="preserve"> + <source>Port</source> + <target state="new">Port</target> + <note/> + </trans-unit> + <trans-unit id="Port: %@" xml:space="preserve"> + <source>Port: %@</source> + <target state="new">Port: %@</target> + <note/> + </trans-unit> + <trans-unit id="Previous" xml:space="preserve"> + <source>Previous</source> + <target state="new">Previous</target> + <note/> + </trans-unit> + <trans-unit id="Providers" xml:space="preserve"> + <source>Providers</source> + <target state="new">Providers</target> + <note/> + </trans-unit> + <trans-unit id="Providers: %d" xml:space="preserve"> + <source>Providers: %d</source> + <target state="new">Providers: %d</target> + <note/> + </trans-unit> + <trans-unit id="QUIC" xml:space="preserve"> + <source>QUIC</source> + <target state="new">QUIC</target> + <note/> + </trans-unit> + <trans-unit id="Quantum resistance" xml:space="preserve"> + <source>Quantum resistance</source> + <target state="new">Quantum resistance</target> + <note/> + </trans-unit> + <trans-unit id="Quantum secure connection" xml:space="preserve"> + <source>Quantum secure connection</source> + <target state="new">Quantum secure connection</target> + <note/> + </trans-unit> + <trans-unit id="Quantum secure connection. Connected to %@, %@" xml:space="preserve"> + <source>Quantum secure connection. Connected to %1$@, %2$@</source> + <target state="new">Quantum secure connection. Connected to %1$@, %2$@</target> + <note/> + </trans-unit> + <trans-unit id="Quantum-resistant tunnel" xml:space="preserve"> + <source>Quantum-resistant tunnel</source> + <target state="new">Quantum-resistant tunnel</target> + <note/> + </trans-unit> + <trans-unit id="Reconnecting" xml:space="preserve"> + <source>Reconnecting</source> + <target state="new">Reconnecting</target> + <note/> + </trans-unit> + <trans-unit id="Reconnecting to %@, %@" xml:space="preserve"> + <source>Reconnecting to %1$@, %2$@</source> + <target state="new">Reconnecting to %1$@, %2$@</target> + <note/> + </trans-unit> + <trans-unit id="Redeem" xml:space="preserve"> + <source>Redeem</source> + <target state="new">Redeem</target> + <note/> + </trans-unit> + <trans-unit id="Redeem voucher" xml:space="preserve"> + <source>Redeem voucher</source> + <target state="new">Redeem voucher</target> + <note/> + </trans-unit> + <trans-unit id="Refund last purchase with StoreKit2" xml:space="preserve"> + <source>Refund last purchase with StoreKit2</source> + <target state="new">Refund last purchase with StoreKit2</target> + <note/> + </trans-unit> + <trans-unit id="Refund successful" xml:space="preserve"> + <source>Refund successful</source> + <target state="new">Refund successful</target> + <note/> + </trans-unit> + <trans-unit id="Remove" xml:space="preserve"> + <source>Remove</source> + <target state="new">Remove</target> + <note/> + </trans-unit> + <trans-unit id="Remove %@? The device will be removed from the list and logged out." xml:space="preserve"> + <source>Remove %@? +The device will be removed from the list and logged out.</source> + <target state="new">Remove %@? +The device will be removed from the list and logged out.</target> + <note/> + </trans-unit> + <trans-unit id="Remove last used account" xml:space="preserve"> + <source>Remove last used account</source> + <target state="new">Remove last used account</target> + <note/> + </trans-unit> + <trans-unit id="Rented" xml:space="preserve"> + <source>Rented</source> + <target state="new">Rented</target> + <note/> + </trans-unit> + <trans-unit id="Report a problem" xml:space="preserve"> + <source>Report a problem</source> + <target state="new">Report a problem</target> + <note/> + </trans-unit> + <trans-unit id="Required" xml:space="preserve"> + <source>Required</source> + <target state="new">Required</target> + <note/> + </trans-unit> + <trans-unit id="Restore purchases" xml:space="preserve"> + <source>Restore purchases</source> + <target state="new">Restore purchases</target> + <note/> + </trans-unit> + <trans-unit id="Save" xml:space="preserve"> + <source>Save</source> + <target state="new">Save</target> + <note/> + </trans-unit> + <trans-unit id="Save anyway" xml:space="preserve"> + <source>Save anyway</source> + <target state="new">Save anyway</target> + <note/> + </trans-unit> + <trans-unit id="Saving changes..." xml:space="preserve"> + <source>Saving changes...</source> + <target state="new">Saving changes...</target> + <note/> + </trans-unit> + <trans-unit id="Search for..." xml:space="preserve"> + <source>Search for...</source> + <target state="new">Search for...</target> + <note/> + </trans-unit> + <trans-unit id="Secure connection. Connected to %@, %@" xml:space="preserve"> + <source>Secure connection. Connected to %1$@, %2$@</source> + <target state="new">Secure connection. Connected to %1$@, %2$@</target> + <note/> + </trans-unit> + <trans-unit id="Select location" xml:space="preserve"> + <source>Select location</source> + <target state="new">Select location</target> + <note/> + </trans-unit> + <trans-unit id="Selected" xml:space="preserve"> + <source>Selected</source> + <target state="new">Selected</target> + <note/> + </trans-unit> + <trans-unit id="Send" xml:space="preserve"> + <source>Send</source> + <target state="new">Send</target> + <note/> + </trans-unit> + <trans-unit id="Send anyway" xml:space="preserve"> + <source>Send anyway</source> + <target state="new">Send anyway</target> + <note/> + </trans-unit> + <trans-unit id="Sending..." xml:space="preserve"> + <source>Sending...</source> + <target state="new">Sending...</target> + <note/> + </trans-unit> + <trans-unit id="Sent" xml:space="preserve"> + <source>Sent</source> + <target state="new">Sent</target> + <note/> + </trans-unit> + <trans-unit id="Server" xml:space="preserve"> + <source>Server</source> + <target state="new">Server</target> + <note/> + </trans-unit> + <trans-unit id="Server IP Override" xml:space="preserve"> + <source>Server IP Override</source> + <target state="new">Server IP Override</target> + <note/> + </trans-unit> + <trans-unit id="Server IP override" xml:space="preserve"> + <source>Server IP override</source> + <target state="new">Server IP override</target> + <note/> + </trans-unit> + <trans-unit id="Server details" xml:space="preserve"> + <source>Server details</source> + <target state="new">Server details</target> + <note/> + </trans-unit> + <trans-unit id="Setting: DAITA" xml:space="preserve"> + <source>Setting: DAITA</source> + <target state="new">Setting: DAITA</target> + <note/> + </trans-unit> + <trans-unit id="Setting: Obfuscation" xml:space="preserve"> + <source>Setting: Obfuscation</source> + <target state="new">Setting: Obfuscation</target> + <note/> + </trans-unit> + <trans-unit id="Settings" xml:space="preserve"> + <source>Settings</source> + <target state="new">Settings</target> + <note/> + </trans-unit> + <trans-unit id="Settings migration error" xml:space="preserve"> + <source>Settings migration error</source> + <target state="new">Settings migration error</target> + <note/> + </trans-unit> + <trans-unit id="Shadowsocks" xml:space="preserve"> + <source>Shadowsocks</source> + <target state="new">Shadowsocks</target> + <note/> + </trans-unit> + <trans-unit id="Show account number" xml:space="preserve"> + <source>Show account number</source> + <target state="new">Show account number</target> + <note/> + </trans-unit> + <trans-unit id="Social media" xml:space="preserve"> + <source>Social media</source> + <target state="new">Social media</target> + <note/> + </trans-unit> + <trans-unit id="Start using the app" xml:space="preserve"> + <source>Start using the app</source> + <target state="new">Start using the app</target> + <note/> + </trans-unit> + <trans-unit id="Super!" xml:space="preserve"> + <source>Super!</source> + <target state="new">Super!</target> + <note/> + </trans-unit> + <trans-unit id="Switch location" xml:space="preserve"> + <source>Switch location</source> + <target state="new">Switch location</target> + <note/> + </trans-unit> + <trans-unit id="TUNNEL ERROR" xml:space="preserve"> + <source>TUNNEL ERROR</source> + <target state="new">TUNNEL ERROR</target> + <note/> + </trans-unit> + <trans-unit id="Tap **Edit** to add at least one DNS server." xml:space="preserve"> + <source>Tap **Edit** to add at least one DNS server.</source> + <target state="new">Tap **Edit** to add at least one DNS server.</target> + <note>Foot note displayed if there are no DNS entries, but table view is not in editing mode.</note> + </trans-unit> + <trans-unit id="Test method" xml:space="preserve"> + <source>Test method</source> + <target state="new">Test method</target> + <note/> + </trans-unit> + <trans-unit id="Testing..." xml:space="preserve"> + <source>Testing...</source> + <target state="new">Testing...</target> + <note/> + </trans-unit> + <trans-unit id="Thanks for your purchase" xml:space="preserve"> + <source>Thanks for your purchase</source> + <target state="new">Thanks for your purchase</target> + <note/> + </trans-unit> + <trans-unit id="Thanks!" xml:space="preserve"> + <source>Thanks!</source> + <target state="new">Thanks!</target> + <note/> + </trans-unit> + <trans-unit id="The app communicates with a Mullvad API server directly." xml:space="preserve"> + <source>The app communicates with a Mullvad API server directly.</source> + <target state="new">The app communicates with a Mullvad API server directly.</target> + <note/> + </trans-unit> + <trans-unit id="The app communicates with a Mullvad API server via a Mullvad bridge server." xml:space="preserve"> + <source>The app communicates with a Mullvad API server via a Mullvad bridge server.</source> + <target state="new">The app communicates with a Mullvad API server via a Mullvad bridge server.</target> + <note/> + </trans-unit> + <trans-unit id="The app communicates with a Mullvad API server via a proxy address." xml:space="preserve"> + <source>The app communicates with a Mullvad API server via a proxy address.</source> + <target state="new">The app communicates with a Mullvad API server via a proxy address.</target> + <note/> + </trans-unit> + <trans-unit id="The app needs to communicate with a Mullvad API server to log you in, fetch server lists, and other critical operations." xml:space="preserve"> + <source>The app needs to communicate with a Mullvad API server to log you in, fetch server lists, and other critical operations.</source> + <target state="new">The app needs to communicate with a Mullvad API server to log you in, fetch server lists, and other critical operations.</target> + <note/> + </trans-unit> + <trans-unit id="The app will test the method before saving." xml:space="preserve"> + <source>The app will test the method before saving.</source> + <target state="new">The app will test the method before saving.</target> + <note/> + </trans-unit> + <trans-unit id="The automatic setting will randomly choose from the valid port ranges shown below. The custom port can be any value inside the valid ranges: %@" xml:space="preserve"> + <source>The automatic setting will randomly choose from the valid port ranges shown below. +The custom port can be any value inside the valid ranges: +%@</source> + <target state="new">The automatic setting will randomly choose from the valid port ranges shown below. +The custom port can be any value inside the valid ranges: +%@</target> + <note/> + </trans-unit> + <trans-unit id="The entry server for multihop is currently overridden by DAITA. To select an entry server, please first enable “Direct only” or disable “DAITA” in the settings." xml:space="preserve"> + <source>The entry server for multihop is currently overridden by DAITA. To select an entry server, please first enable “Direct only” or disable “DAITA” in the settings.</source> + <target state="new">The entry server for multihop is currently overridden by DAITA. To select an entry server, please first enable “Direct only” or disable “DAITA” in the settings.</target> + <note/> + </trans-unit> + <trans-unit id="The payment request was cancelled." xml:space="preserve"> + <source>The payment request was cancelled.</source> + <target state="new">The payment request was cancelled.</target> + <note/> + </trans-unit> + <trans-unit id="The version of settings stored on device is unrecognized.Settings will be reset to defaults and the device will be logged out." xml:space="preserve"> + <source>The version of settings stored on device is unrecognized.Settings will be reset to defaults and the device will be logged out.</source> + <target state="new">The version of settings stored on device is unrecognized.Settings will be reset to defaults and the device will be logged out.</target> + <note/> + </trans-unit> + <trans-unit id="This can be useful if the API is censored but Mullvad’s bridge servers are not." xml:space="preserve"> + <source>This can be useful if the API is censored but Mullvad’s bridge servers are not.</source> + <target state="new">This can be useful if the API is censored but Mullvad’s bridge servers are not.</target> + <note/> + </trans-unit> + <trans-unit id="This can be useful when you are not affected by censorship." xml:space="preserve"> + <source>This can be useful when you are not affected by censorship.</source> + <target state="new">This can be useful when you are not affected by censorship.</target> + <note/> + </trans-unit> + <trans-unit id="This device is not allowed to make the payment." xml:space="preserve"> + <source>This device is not allowed to make the payment.</source> + <target state="new">This device is not allowed to make the payment.</target> + <note/> + </trans-unit> + <trans-unit id="This feature allows access to other devices on the local network, such as for sharing, printing, streaming, etc. Attention: toggling “Local network sharing” requires restarting the VPN connection." xml:space="preserve"> + <source>This feature allows access to other devices on the local network, such as for sharing, printing, streaming, etc. +Attention: toggling “Local network sharing” requires restarting the VPN connection.</source> + <target state="new">This feature allows access to other devices on the local network, such as for sharing, printing, streaming, etc. +Attention: toggling “Local network sharing” requires restarting the VPN connection.</target> + <note/> + </trans-unit> + <trans-unit id="This feature allows you to circumvent that censorship by adding custom ways to access the API via proxies and similar methods." xml:space="preserve"> + <source>This feature allows you to circumvent that censorship by adding custom ways to access the API via proxies and similar methods.</source> + <target state="new">This feature allows you to circumvent that censorship by adding custom ways to access the API via proxies and similar methods.</target> + <note/> + </trans-unit> + <trans-unit id="This feature makes the WireGuard tunnel resistant to potential attacks from quantum computers. It does this by performing an extra key exchange using a quantum safe algorithm and mixing the result into WireGuard’s regular encryption. This extra step uses approximately 500 kiB of traffic every time a new tunnel is established." xml:space="preserve"> + <source>This feature makes the WireGuard tunnel resistant to potential attacks from quantum computers. +It does this by performing an extra key exchange using a quantum safe algorithm and mixing the result into WireGuard’s regular encryption. +This extra step uses approximately 500 kiB of traffic every time a new tunnel is established.</source> + <target state="new">This feature makes the WireGuard tunnel resistant to potential attacks from quantum computers. +It does this by performing an extra key exchange using a quantum safe algorithm and mixing the result into WireGuard’s regular encryption. +This extra step uses approximately 500 kiB of traffic every time a new tunnel is established.</target> + <note/> + </trans-unit> + <trans-unit id="This is the name assigned to the device. Each device logged in on a Mullvad account gets a unique name that helps you identify it when you manage your devices in the app or on the website. You can have up to 5 devices logged in on one Mullvad account. If you log out, the device and the device name is removed. When you log back in again, the device will get a new name." xml:space="preserve"> + <source>This is the name assigned to the device. Each device logged in on a Mullvad account gets a unique name that helps you identify it when you manage your devices in the app or on the website. +You can have up to 5 devices logged in on one Mullvad account. +If you log out, the device and the device name is removed. When you log back in again, the device will get a new name.</source> + <target state="new">This is the name assigned to the device. Each device logged in on a Mullvad account gets a unique name that helps you identify it when you manage your devices in the app or on the website. +You can have up to 5 devices logged in on one Mullvad account. +If you log out, the device and the device name is removed. When you log back in again, the device will get a new name.</target> + <note/> + </trans-unit> + <trans-unit id="This logs out all devices using this account and all VPN access will be denied even if there is time left on the account. Enter the last 4 digits of the account number and hit "Delete account" if you really want to delete the account:" xml:space="preserve"> + <source>This logs out all devices using this account and all VPN access will be denied even if there is time left on the account. Enter the last 4 digits of the account number and hit "Delete account" if you really want to delete the account:</source> + <target state="new">This logs out all devices using this account and all VPN access will be denied even if there is time left on the account. Enter the last 4 digits of the account number and hit "Delete account" if you really want to delete the account:</target> + <note/> + </trans-unit> + <trans-unit id="This voucher code has already been used." xml:space="preserve"> + <source>This voucher code has already been used.</source> + <target state="new">This voucher code has already been used.</target> + <note/> + </trans-unit> + <trans-unit id="Time left: %@" xml:space="preserve"> + <source>Time left: %@</source> + <target state="new">Time left: %@</target> + <note/> + </trans-unit> + <trans-unit id="To assist you better, please write in English or Swedish and include which country you are connecting from." xml:space="preserve"> + <source>To assist you better, please write in English or Swedish and include which country you are connecting from.</source> + <target state="new">To assist you better, please write in English or Swedish and include which country you are connecting from.</target> + <note/> + </trans-unit> + <trans-unit id="To circumvent this you can import a file or a text, provided by our support team, with new IP addresses that override the default addresses of the servers in the Select location view." xml:space="preserve"> + <source>To circumvent this you can import a file or a text, provided by our support team, with new IP addresses that override the default addresses of the servers in the Select location view.</source> + <target state="new">To circumvent this you can import a file or a text, provided by our support team, with new IP addresses that override the default addresses of the servers in the Select location view.</target> + <note/> + </trans-unit> + <trans-unit id="To create a custom list, tap on "..." " xml:space="preserve"> + <source>To create a custom list, tap on "..." </source> + <target state="new">To create a custom list, tap on "..." </target> + <note/> + </trans-unit> + <trans-unit id="To enable this setting, add at least one server." xml:space="preserve"> + <source>To enable this setting, add at least one server.</source> + <target state="new">To enable this setting, add at least one server.</target> + <note>Foot note displayed if there are no DNS entries and table view is in editing mode.</note> + </trans-unit> + <trans-unit id="To help you more effectively, your app’s log file will be attached to this message. Your data will remain secure and private, as it is anonymised before being sent over an encrypted channel." xml:space="preserve"> + <source>To help you more effectively, your app’s log file will be attached to this message. Your data will remain secure and private, as it is anonymised before being sent over an encrypted channel.</source> + <target state="new">To help you more effectively, your app’s log file will be attached to this message. Your data will remain secure and private, as it is anonymised before being sent over an encrypted channel.</target> + <note/> + </trans-unit> + <trans-unit id="To start using the app, you first need to add time to your account. Either buy credit on our website or redeem a voucher." xml:space="preserve"> + <source>To start using the app, you first need to add time to your account. Either buy credit on our website or redeem a voucher.</source> + <target state="new">To start using the app, you first need to add time to your account. Either buy credit on our website or redeem a voucher.</target> + <note/> + </trans-unit> + <trans-unit id="Too many devices" xml:space="preserve"> + <source>Too many devices</source> + <target state="new">Too many devices</target> + <note/> + </trans-unit> + <trans-unit id="Too many devices registered with account" xml:space="preserve"> + <source>Too many devices registered with account</source> + <target state="new">Too many devices registered with account</target> + <note/> + </trans-unit> + <trans-unit id="Trackers" xml:space="preserve"> + <source>Trackers</source> + <target state="new">Trackers</target> + <note/> + </trans-unit> + <trans-unit id="Try again" xml:space="preserve"> + <source>Try again</source> + <target state="new">Try again</target> + <note/> + </trans-unit> + <trans-unit id="Tunnel is unset." xml:space="preserve"> + <source>Tunnel is unset.</source> + <target state="new">Tunnel is unset.</target> + <note/> + </trans-unit> + <trans-unit id="Type" xml:space="preserve"> + <source>Type</source> + <target state="new">Type</target> + <note/> + </trans-unit> + <trans-unit id="UDP-over-TCP" xml:space="preserve"> + <source>UDP-over-TCP</source> + <target state="new">UDP-over-TCP</target> + <note/> + </trans-unit> + <trans-unit id="Unexpected server response: %1$@ (HTTP status: %2$d)" xml:space="preserve"> + <source>Unexpected server response: %1$@ (HTTP status: %2$d)</source> + <target state="new">Unexpected server response: %1$@ (HTTP status: %2$d)</target> + <note/> + </trans-unit> + <trans-unit id="Unexpected server response: %d" xml:space="preserve"> + <source>Unexpected server response: %d</source> + <target state="new">Unexpected server response: %d</target> + <note/> + </trans-unit> + <trans-unit id="Unknown error." xml:space="preserve"> + <source>Unknown error.</source> + <target state="new">Unknown error.</target> + <note/> + </trans-unit> + <trans-unit id="Unsecured connection" xml:space="preserve"> + <source>Unsecured connection</source> + <target state="new">Unsecured connection</target> + <note/> + </trans-unit> + <trans-unit id="Use custom DNS server" xml:space="preserve"> + <source>Use custom DNS server</source> + <target state="new">Use custom DNS server</target> + <note/> + </trans-unit> + <trans-unit id="Username" xml:space="preserve"> + <source>Username</source> + <target state="new">Username</target> + <note/> + </trans-unit> + <trans-unit id="VPN settings" xml:space="preserve"> + <source>VPN settings</source> + <target state="new">VPN settings</target> + <note/> + </trans-unit> + <trans-unit id="Valid range: 1 - 65535" xml:space="preserve"> + <source>Valid range: 1 - 65535</source> + <target state="new">Valid range: 1 - 65535</target> + <note/> + </trans-unit> + <trans-unit id="Verifying voucher..." xml:space="preserve"> + <source>Verifying voucher...</source> + <target state="new">Verifying voucher...</target> + <note/> + </trans-unit> + <trans-unit id="View and manage all your logged in devices. You can have up to 5 devices on one account at a time. Each device gets a name when logged in to help you tell them apart easily." xml:space="preserve"> + <source>View and manage all your logged in devices. You can have up to 5 devices on one account at a time. Each device gets a name when logged in to help you tell them apart easily.</source> + <target state="new">View and manage all your logged in devices. You can have up to 5 devices on one account at a time. Each device gets a name when logged in to help you tell them apart easily.</target> + <note/> + </trans-unit> + <trans-unit id="View app logs" xml:space="preserve"> + <source>View app logs</source> + <target state="new">View app logs</target> + <note/> + </trans-unit> + <trans-unit id="Voucher code is invalid." xml:space="preserve"> + <source>Voucher code is invalid.</source> + <target state="new">Voucher code is invalid.</target> + <note/> + </trans-unit> + <trans-unit id="Voucher was successfully redeemed." xml:space="preserve"> + <source>Voucher was successfully redeemed.</source> + <target state="new">Voucher was successfully redeemed.</target> + <note/> + </trans-unit> + <trans-unit id="Warning: The malware blocker is not an anti-virus and should not be treated as such, this is just an extra layer of protection." xml:space="preserve"> + <source>Warning: The malware blocker is not an anti-virus and should not be treated as such, this is just an extra layer of protection.</source> + <target state="new">Warning: The malware blocker is not an anti-virus and should not be treated as such, this is just an extra layer of protection.</target> + <note/> + </trans-unit> + <trans-unit id="We are having some issues, please try again later" xml:space="preserve"> + <source>We are having some issues, please try again later</source> + <target state="new">We are having some issues, please try again later</target> + <note/> + </trans-unit> + <trans-unit id="We will look into this." xml:space="preserve"> + <source>We will look into this.</source> + <target state="new">We will look into this.</target> + <note/> + </trans-unit> + <trans-unit id="Welcome, this device is now called **%@**. For more details see the info button in Account." xml:space="preserve"> + <source>Welcome, this device is now called **%@**. For more details see the info button in Account.</source> + <target state="new">Welcome, this device is now called **%@**. For more details see the info button in Account.</target> + <note/> + </trans-unit> + <trans-unit id="What's new" xml:space="preserve"> + <source>What's new</source> + <target state="new">What's new</target> + <note/> + </trans-unit> + <trans-unit id="When this feature is enabled it stops the device from contacting certain domains or websites known for distributing ads, malware, trackers and more. This might cause issues on certain websites, services, and apps. Attention: this setting cannot be used in combination with **Use custom DNS server**." xml:space="preserve"> + <source>When this feature is enabled it stops the device from contacting certain domains or websites known for distributing ads, malware, trackers and more. +This might cause issues on certain websites, services, and apps. +Attention: this setting cannot be used in combination with **Use custom DNS server**.</source> + <target state="new">When this feature is enabled it stops the device from contacting certain domains or websites known for distributing ads, malware, trackers and more. +This might cause issues on certain websites, services, and apps. +Attention: this setting cannot be used in combination with **Use custom DNS server**.</target> + <note/> + </trans-unit> + <trans-unit id="When using DAITA, one provider with DAITA-enabled servers is required." xml:space="preserve"> + <source>When using DAITA, one provider with DAITA-enabled servers is required.</source> + <target state="new">When using DAITA, one provider with DAITA-enabled servers is required.</target> + <note/> + </trans-unit> + <trans-unit id="Which TCP port the UDP-over-TCP obfuscation protocol should connect to on the VPN server." xml:space="preserve"> + <source>Which TCP port the UDP-over-TCP obfuscation protocol should connect to on the VPN server.</source> + <target state="new">Which TCP port the UDP-over-TCP obfuscation protocol should connect to on the VPN server.</target> + <note/> + </trans-unit> + <trans-unit id="WireGuard Obfuscation" xml:space="preserve"> + <source>WireGuard Obfuscation</source> + <target state="new">WireGuard Obfuscation</target> + <note/> + </trans-unit> + <trans-unit id="WireGuard ports" xml:space="preserve"> + <source>WireGuard ports</source> + <target state="new">WireGuard ports</target> + <note/> + </trans-unit> + <trans-unit id="With the "Direct" method, the app communicates with a Mullvad API server directly without any intermediate proxies." xml:space="preserve"> + <source>With the "Direct" method, the app communicates with a Mullvad API server directly without any intermediate proxies.</source> + <target state="new">With the "Direct" method, the app communicates with a Mullvad API server directly without any intermediate proxies.</target> + <note/> + </trans-unit> + <trans-unit id="With the "Encrypted DNS proxy" method, the app will communicate with our Mullvad API through a proxy address. It does this by retrieving an address from a DNS over HTTPS (DoH) server and then using that to reach our API servers." xml:space="preserve"> + <source>With the "Encrypted DNS proxy" method, the app will communicate with our Mullvad API through a proxy address. +It does this by retrieving an address from a DNS over HTTPS (DoH) server and then using that to reach our API servers.</source> + <target state="new">With the "Encrypted DNS proxy" method, the app will communicate with our Mullvad API through a proxy address. +It does this by retrieving an address from a DNS over HTTPS (DoH) server and then using that to reach our API servers.</target> + <note/> + </trans-unit> + <trans-unit id="With the "Mullvad bridges" method, the app communicates with a Mullvad API server via a Mullvad bridge server. It does this by sending the traffic obfuscated by Shadowsocks." xml:space="preserve"> + <source>With the "Mullvad bridges" method, the app communicates with a Mullvad API server via a Mullvad bridge server. It does this by sending the traffic obfuscated by Shadowsocks.</source> + <target state="new">With the "Mullvad bridges" method, the app communicates with a Mullvad API server via a Mullvad bridge server. It does this by sending the traffic obfuscated by Shadowsocks.</target> + <note/> + </trans-unit> + <trans-unit id="Yes, continue" xml:space="preserve"> + <source>Yes, continue</source> + <target state="new">Yes, continue</target> + <note/> + </trans-unit> + <trans-unit id="Yes, log out device" xml:space="preserve"> + <source>Yes, log out device</source> + <target state="new">Yes, log out device</target> + <note/> + </trans-unit> + <trans-unit id="You are about to send the problem report without a way for us to get back to you. If you want an answer to your report you will have to enter an email address." xml:space="preserve"> + <source>You are about to send the problem report without a way for us to get back to you. If you want an answer to your report you will have to enter an email address.</source> + <target state="new">You are about to send the problem report without a way for us to get back to you. If you want an answer to your report you will have to enter an email address.</target> + <note/> + </trans-unit> + <trans-unit id="You can add more time via the account view or website to continue using the VPN." xml:space="preserve"> + <source>You can add more time via the account view or website to continue using the VPN.</source> + <target state="new">You can add more time via the account view or website to continue using the VPN.</target> + <note/> + </trans-unit> + <trans-unit id="You can now continue logging in on this device." xml:space="preserve"> + <source>You can now continue logging in on this device.</source> + <target state="new">You can now continue logging in on this device.</target> + <note/> + </trans-unit> + <trans-unit id="You can use the "restore purchases" function to check for any in-app payments made via Apple services. If there is a payment that has not been credited, it will add the time to the currently logged in Mullvad account." xml:space="preserve"> + <source>You can use the "restore purchases" function to check for any in-app payments made via Apple services. If there is a payment that has not been credited, it will add the time to the currently logged in Mullvad account.</source> + <target state="new">You can use the "restore purchases" function to check for any in-app payments made via Apple services. If there is a payment that has not been credited, it will add the time to the currently logged in Mullvad account.</target> + <note/> + </trans-unit> + <trans-unit id="You have %@ left on this account." xml:space="preserve"> + <source>You have %@ left on this account.</source> + <target state="new">You have %@ left on this account.</target> + <note/> + </trans-unit> + <trans-unit id="You have a right to privacy. That’s why we never store activity logs, don’t ask for personal information, and encourage anonymous payments. In some situations, as outlined in our privacy policy, we might process personal data that you choose to send, for example if you email us. We strongly believe in retaining as little data as possible because we want you to remain anonymous." xml:space="preserve"> + <source>You have a right to privacy. That’s why we never store activity logs, don’t ask for personal information, and encourage anonymous payments. + +In some situations, as outlined in our privacy policy, we might process personal data that you choose to send, for example if you email us. + +We strongly believe in retaining as little data as possible because we want you to remain anonymous.</source> + <target state="new">You have a right to privacy. That’s why we never store activity logs, don’t ask for personal information, and encourage anonymous payments. + +In some situations, as outlined in our privacy policy, we might process personal data that you choose to send, for example if you email us. + +We strongly believe in retaining as little data as possible because we want you to remain anonymous.</target> + <note/> + </trans-unit> + <trans-unit id="You have no more VPN time left on this account. Either buy credit on our website or make an in-app purchase via the **Add time** button below." xml:space="preserve"> + <source>You have no more VPN time left on this account. Either buy credit on our website or make an in-app purchase via the **Add time** button below.</source> + <target state="new">You have no more VPN time left on this account. Either buy credit on our website or make an in-app purchase via the **Add time** button below.</target> + <note/> + </trans-unit> + <trans-unit id="You have no more VPN time left on this account. To add more, you will need to disconnect and access the Internet with an unsecure connection." xml:space="preserve"> + <source>You have no more VPN time left on this account. To add more, you will need to disconnect and access the Internet with an unsecure connection.</source> + <target state="new">You have no more VPN time left on this account. To add more, you will need to disconnect and access the Internet with an unsecure connection.</target> + <note/> + </trans-unit> + <trans-unit id="You have one day left on this account. Please add more time to continue using the VPN." xml:space="preserve"> + <source>You have one day left on this account. Please add more time to continue using the VPN.</source> + <target state="new">You have one day left on this account. Please add more time to continue using the VPN.</target> + <note/> + </trans-unit> + <trans-unit id="You have removed this device. To connect again, you will need to log back in." xml:space="preserve"> + <source>You have removed this device. To connect again, you will need to log back in.</source> + <target state="new">You have removed this device. To connect again, you will need to log back in.</target> + <note/> + </trans-unit> + <trans-unit id="You have unsaved changes." xml:space="preserve"> + <source>You have unsaved changes.</source> + <target state="new">You have unsaved changes.</target> + <note/> + </trans-unit> + <trans-unit id="Your device is offline. The tunnel will automatically connect once your device is back online." xml:space="preserve"> + <source>Your device is offline. The tunnel will automatically connect once your device is back online.</source> + <target state="new">Your device is offline. The tunnel will automatically connect once your device is back online.</target> + <note/> + </trans-unit> + <trans-unit id="Your device is offline. Try connecting again when the device has access to Internet." xml:space="preserve"> + <source>Your device is offline. Try connecting again when the device has access to Internet.</source> + <target state="new">Your device is offline. Try connecting again when the device has access to Internet.</target> + <note/> + </trans-unit> + <trans-unit id="Your email (optional)" xml:space="preserve"> + <source>Your email (optional)</source> + <target state="new">Your email (optional)</target> + <note/> + </trans-unit> + <trans-unit id="Your previous purchases have already been added to this account." xml:space="preserve"> + <source>Your previous purchases have already been added to this account.</source> + <target state="new">Your previous purchases have already been added to this account.</target> + <note/> + </trans-unit> + <trans-unit id="Your purchase was successfully refunded." xml:space="preserve"> + <source>Your purchase was successfully refunded.</source> + <target state="new">Your purchase was successfully refunded.</target> + <note/> + </trans-unit> + <trans-unit id="You’re all set!!" xml:space="preserve"> + <source>You’re all set!!</source> + <target state="new">You’re all set!!</target> + <note/> + </trans-unit> + <trans-unit id="method" xml:space="preserve"> + <source>method</source> + <target state="new">method</target> + <note/> + </trans-unit> + <trans-unit id="value" xml:space="preserve"> + <source>value</source> + <target state="new">value</target> + <note/> + </trans-unit> + <trans-unit id="“%@ Local network sharing” requires restarting the VPN connection, which will disconnect you and briefly expose your traffic. To prevent this, manually enable Airplane Mode and turn off Wi-Fi before continuing. Would you like to continue to enable “Local network sharing”?" xml:space="preserve"> + <source>“%@ Local network sharing” requires restarting the VPN connection, which will disconnect you and briefly expose your traffic. +To prevent this, manually enable Airplane Mode and turn off Wi-Fi before continuing. +Would you like to continue to enable “Local network sharing”?</source> + <target state="new">“%@ Local network sharing” requires restarting the VPN connection, which will disconnect you and briefly expose your traffic. +To prevent this, manually enable Airplane Mode and turn off Wi-Fi before continuing. +Would you like to continue to enable “Local network sharing”?</target> + <note/> + </trans-unit> + </body> + </file> + <file original="en.lproj/Localizable.strings" source-language="en" target-language="en" datatype="plaintext"> + <header> + <tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="16.1" build-num="16B40"/> + </header> + <body> + <trans-unit id="A custom list with this name exists, please choose a unique name." xml:space="preserve"> + <source>A custom list with this name exists, please choose a unique name.</source> + <target>A custom list with this name exists, please choose a unique name.</target> + <note>No comment provided by engineer.</note> + </trans-unit> + <trans-unit id="Automatic" xml:space="preserve"> + <source>Automatic</source> + <target>Automatic</target> + <note>No comment provided by engineer.</note> + </trans-unit> + <trans-unit id="Name should be no longer than %i characters." xml:space="preserve"> + <source>Name should be no longer than %i characters.</source> + <target>Name should be no longer than %i characters.</target> + <note>No comment provided by engineer.</note> + </trans-unit> + <trans-unit id="Shadowsocks" xml:space="preserve"> + <source>Shadowsocks</source> + <target>Shadowsocks</target> + <note>No comment provided by engineer.</note> + </trans-unit> + <trans-unit id="Socks5" xml:space="preserve"> + <source>Socks5</source> + <target>Socks5</target> + <note>No comment provided by engineer.</note> + </trans-unit> + </body> + </file> + <file original="MullvadVPN/Supporting Files/en.lproj/InfoPlist.strings" source-language="en" target-language="en" datatype="plaintext"> + <header> + <tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="16.1" build-num="16B40"/> + </header> + <body> + <trans-unit id="CFBundleDisplayName" xml:space="preserve"> + <source>Mullvad VPN</source> + <target>Mullvad VPN</target> + <note>Bundle display name</note> + </trans-unit> + <trans-unit id="CFBundleName" xml:space="preserve"> + <source>MullvadVPN</source> + <target>MullvadVPN</target> + <note>Bundle name</note> + </trans-unit> + <trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve"> + <source>The app needs this to connect and test a new method.</source> + <target>The app needs this to connect and test a new method.</target> + <note>Privacy - Local Network Usage Description</note> + </trans-unit> + </body> + </file> + <file original="PacketTunnel/en.lproj/InfoPlist.strings" source-language="en" target-language="en" datatype="plaintext"> + <header> + <tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="16.1" build-num="16B40"/> + </header> + <body> + <trans-unit id="CFBundleDisplayName" xml:space="preserve"> + <source>PacketTunnel</source> + <target>PacketTunnel</target> + <note>Bundle display name</note> + </trans-unit> + <trans-unit id="CFBundleName" xml:space="preserve"> + <source>PacketTunnel</source> + <target>PacketTunnel</target> + <note>Bundle name</note> + </trans-unit> + </body> + </file> + <file original="PacketTunnel/en.lproj/Localizable.strings" source-language="en" target-language="en" datatype="plaintext"> + <header> + <tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="16.1" build-num="16B40"/> + </header> + <body> + <trans-unit id="%@ have been added to your account" xml:space="preserve"> + <source>%@ have been added to your account</source> + <target>%@ have been added to your account</target> + <note>No comment provided by engineer.</note> + </trans-unit> + <trans-unit id="Cannot complete the purchase" xml:space="preserve"> + <source>Cannot complete the purchase</source> + <target>Cannot complete the purchase</target> + <note>No comment provided by engineer.</note> + </trans-unit> + <trans-unit id="Cannot restore purchases" xml:space="preserve"> + <source>Cannot restore purchases</source> + <target>Cannot restore purchases</target> + <note>No comment provided by engineer.</note> + </trans-unit> + <trans-unit id="Restore purchases" xml:space="preserve"> + <source>Restore purchases</source> + <target>Restore purchases</target> + <note>No comment provided by engineer.</note> + </trans-unit> + <trans-unit id="Thanks for your purchase" xml:space="preserve"> + <source>Thanks for your purchase</source> + <target>Thanks for your purchase</target> + <note>No comment provided by engineer.</note> + </trans-unit> + <trans-unit id="Your previous purchases have already been added to this account." xml:space="preserve"> + <source>Your previous purchases have already been added to this account.</source> + <target>Your previous purchases have already been added to this account.</target> + <note>No comment provided by engineer.</note> + </trans-unit> + </body> + </file> +</xliff> diff --git a/ios/translation/scripts/.gitignore b/ios/translation/scripts/.gitignore new file mode 100644 index 0000000000..ea198f6a2c --- /dev/null +++ b/ios/translation/scripts/.gitignore @@ -0,0 +1,2 @@ +logs/ +build/ diff --git a/ios/translation/scripts/Readme.md b/ios/translation/scripts/Readme.md new file mode 100644 index 0000000000..26e8d78ee3 --- /dev/null +++ b/ios/translation/scripts/Readme.md @@ -0,0 +1,77 @@ +# Localization Export Tool + +Automate exporting localizable strings (XLIFF) from the MullvadVPN iOS project using `xcodebuild`. + +This folder contains a Bash workflow that: + +1. Builds the Xcode project (to emit/verify localized resources). +2. Exports localizations for one or more languages. +3. Logs each failed run (timestamped) to a git‑ignored `logs/` directory. +4. Uses a throwaway build output directory (`build/`, also git‑ignored). +5. Cleans up Derived Data artifacts after export (configurable). + +--- + +## Folder Structure + +``` +/mullvadvpn-app/ios/translation +├── locales +│ └── en.xliff +└── scripts + ├── export_localizations.sh # Main Bash script + ├── build # Ephemeral DerivedData or build scratch dir (ignored) + ├── logs # Timestamped run logs (ignored) + └── README.md # You're here + +``` + +> **Important:** Ensure `build/` and `logs/` are ignored by Git (see [Git Ignore](#git-ignore)). + +--- + +## Quick Start + +```bash +cd Locale +chmod +x export-localizations.sh +./export-localizations.sh +``` + +By default the script uses values set near the top of the file (edit them before first run). You can override most settings via environment variables or CLI flags (see below). + + +## Multi‑Language Export + +The script can loop languages. Set `EXPORT_LANGUAGES` to a comma‑separated list, e.g.: + +```bash +EXPORT_LANGUAGES="da,de,en,es,fi,fr,it,ja,ko,my,nb,nl,pl,pt-PT,ru,sv,th,tr,zh-Hans,zh-Hant" ./export_localizations.sh +``` + +XLIFF output will be placed under: + +``` +locales/ + en.xliff + sv.xliff + de.xliff + fr.xliff +``` + +(Actual filenames depend on what `xcodebuild -exportLocalizations` emits.) + +--- + +## Logs + +All stdout/stderr from each run is captured using `tee` into `logs/` with a timestamped filename, e.g.: + +``` +logs/ + build_20250723_142915.log + build_20250724_094401.log +``` + +To prune logs older than 7 days automatically, the script includes an optional cleanup step (disabled by default; enable by setting `PRUNE_LOGS_DAYS`). + diff --git a/ios/translation/scripts/export-localizations.sh b/ios/translation/scripts/export-localizations.sh new file mode 100755 index 0000000000..6b855ec0c1 --- /dev/null +++ b/ios/translation/scripts/export-localizations.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +# export-localizations.sh +# Exports Swift/SwiftUI localization files (.xliff) from an Xcode project. + +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LOG_DIR="$SCRIPT_DIR/logs" +mkdir -p "$LOG_DIR" +LOG_FILE="$LOG_DIR/export-localization_$(date +%Y%m%d_%H%M%S).log" +TMP_LOG="$(mktemp)" + +PROJECT_NAME="MullvadVPN" +SCHEME_NAME="$PROJECT_NAME" +XCODE_PROJECT_PATH="$SCRIPT_DIR/../../$PROJECT_NAME.xcodeproj" + +EXPORT_LOCALIZATION_DIR="$SCRIPT_DIR/../locales" +TMP_EXPORT_DIR="${EXPORT_LOCALIZATION_DIR}/all_tmp_languages" + +EXPORT_LANGUAGES=${EXPORT_LANGUAGES:-"en"} +CONFIGURATION="Debug" +BUILD_OUTPUT_DIR="$SCRIPT_DIR/build" +DERIVED_DATA_DIR="$BUILD_OUTPUT_DIR/derivedData" + +trap 'on_fail' ERR + +on_fail() { + set +e + echo "❌ Export failed. Cleaning up and saving log..." + cleanup_build_folder + cleanup_temp_folder + mkdir -p "$(dirname "$LOG_FILE")" + cat "$TMP_LOG" >"$LOG_FILE" + echo "💥 Full log saved to: $LOG_FILE" + exit 1 +} + +cleanup_build_folder() { + echo "🧹 Cleaning build folder at: $BUILD_OUTPUT_DIR" + rm -rf "$BUILD_OUTPUT_DIR" +} + +cleanup_temp_folder() { + echo "🧹 Cleaning temp folder at: $TMP_EXPORT_DIR" + rm -rf "$TMP_EXPORT_DIR" +} + +exec > >(tee "$TMP_LOG") 2>&1 + +build_project() { + echo "👉 Building project..." + xcodebuild \ + -project "$XCODE_PROJECT_PATH" \ + -scheme "$SCHEME_NAME" \ + -destination 'generic/platform=iOS' \ + -configuration "$CONFIGURATION" \ + -derivedDataPath "$DERIVED_DATA_DIR" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO \ + clean build + echo "✅ Build succeeded" +} + +export_localizations() { + echo "🌍 Exporting localizations for languages: $EXPORT_LANGUAGES" + + IFS=',' read -r -a LANG_ARRAY <<<"$EXPORT_LANGUAGES" + + for lang in "${LANG_ARRAY[@]}"; do + echo "➡️ Exporting $lang" + xcodebuild -exportLocalizations \ + -project "$XCODE_PROJECT_PATH" \ + -scheme "$SCHEME_NAME" \ + -derivedDataPath "$DERIVED_DATA_DIR" \ + -localizationPath "$TMP_EXPORT_DIR" \ + -exportLanguage "$lang" + + local xcloc_dir="${TMP_EXPORT_DIR}/${lang}.xcloc" + + if [[ -d "$xcloc_dir" ]]; then + local xliff_file + xliff_file=$(find "$xcloc_dir" -name '*.xliff' | head -n 1) + if [[ -f "$xliff_file" ]]; then + cp "$xliff_file" "$EXPORT_LOCALIZATION_DIR/${lang}.xliff" + echo "✔️ Extracted $lang.xliff for Crowdin upload" + else + echo "❌ No .xliff file found in $xcloc_dir" + false + fi + else + echo "❌ .xcloc bundle not found for $lang" + false + fi + done +} + +main() { + echo "📝 Export script started at: $(date)" + build_project + export_localizations + cleanup_build_folder + cleanup_temp_folder + echo "🎉 Export complete. Crowdin-ready .xliff files are in: $EXPORT_LOCALIZATION_DIR" + echo "✅ Script finished at: $(date)" + rm -f "$TMP_LOG" +} + +main |
