From 1aa4e5105fedd996026f7f81bd6fb7b24adb6382 Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Wed, 18 Dec 2024 17:42:46 -0800 Subject: [PATCH 1/3] [Release PR] Update VPN localization (#3675) Task/Issue URL: https://app.asana.com/0/1207941519901927/1209009536812109/f Tech Design URL: CC: Description: This PR updates VPN localization to fix an issue on macOS 11 and 12. --- .../Localizable.xcstrings | 6 ++++++ DuckDuckGoVPN/Localizable.xcstrings | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/Localizable.xcstrings b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/Localizable.xcstrings index a4d7368f52..b3cab01392 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/Localizable.xcstrings +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/Localizable.xcstrings @@ -557,6 +557,12 @@ "value" : "Reconnect" } }, + "en-US" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reconnect" + } + }, "es" : { "stringUnit" : { "state" : "translated", diff --git a/DuckDuckGoVPN/Localizable.xcstrings b/DuckDuckGoVPN/Localizable.xcstrings index c18410e568..43636be9c4 100644 --- a/DuckDuckGoVPN/Localizable.xcstrings +++ b/DuckDuckGoVPN/Localizable.xcstrings @@ -557,6 +557,12 @@ "value" : "DuckDuckGo VPN" } }, + "en-US" : { + "stringUnit" : { + "state" : "translated", + "value" : "DuckDuckGo VPN" + } + }, "es" : { "stringUnit" : { "state" : "translated", From 8c0d8495fb6164700f25465f16baf9e5e7726f9e Mon Sep 17 00:00:00 2001 From: Michal Smaga Date: Thu, 19 Dec 2024 17:49:59 +0100 Subject: [PATCH 2/3] Update to Privacy Pro settings footer (#3679) Task/Issue URL: https://app.asana.com/0/1142021229838617/1209014429605257/f Description: Following https://app.asana.com/0/1142021229838617/1208961863805375/f: Update the Privacy Pro settings to include link to Privacy Policy. Restore right alignment fro buttons on subscription dialogs. --- DuckDuckGo/Localizable.xcstrings | 112 +++++++++++++----- .../PreferencesSubscriptionModel.swift | 5 + .../PreferencesSubscriptionView.swift | 35 +++--- .../Resources/Localizable.xcstrings | 60 ++++++++++ .../Sources/SubscriptionUI/UserText.swift | 1 + 5 files changed, 160 insertions(+), 53 deletions(-) diff --git a/DuckDuckGo/Localizable.xcstrings b/DuckDuckGo/Localizable.xcstrings index ba0c0a8fe9..f0dbc2e23a 100644 --- a/DuckDuckGo/Localizable.xcstrings +++ b/DuckDuckGo/Localizable.xcstrings @@ -37013,11 +37013,59 @@ "comment" : "Title shown in an error page tab that warn users of security risks on a website that has been flagged as Malware.", "extractionState" : "extracted_with_value", "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warnung: Website ist möglicherweise bösartig" + } + }, "en" : { "stringUnit" : { "state" : "new", "value" : "Warning: Site May Be Malicious" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Advertencia: el sitio puede ser malicioso" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avertissement : le site est peut-être malveillant" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Attenzione: il sito potrebbe essere dannoso" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Opgelet: Deze website kan schadelijk zijn" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ostrzeżenie: witryna może być złośliwa" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aviso: o site pode ser malicioso" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Внимание! Потенциально вредоносный сайт" + } } } }, @@ -47104,8 +47152,8 @@ "localizations" : { "de" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Erlaube DuckDuckGo, dich zu warnen, bevor eine Webseite geladen wird, die als bösartig oder betrügerisch gekennzeichnet wurde." + "state" : "translated", + "value" : "Warne mich auf Websites, die als Phishing- oder Malware-Websites gekennzeichnet sind." } }, "en" : { @@ -47116,44 +47164,44 @@ }, "es" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Permite que DuckDuckGo te avise antes de cargar una página web que se haya marcado como maliciosa o fraudulenta." + "state" : "translated", + "value" : "Avisarme sobre sitios marcados como phishing o malware." } }, "fr" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Autorisez DuckDuckGo à vous avertir avant de charger une page Web signalée comme malveillante ou frauduleuse." + "state" : "translated", + "value" : "Mettez-moi en garde contre les sites signalés pour hameçonnage ou comme étant des logiciels malveillants." } }, "it" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Consenti a DuckDuckGo di avvisarti prima di caricare una pagina web contrassegnata come dannosa o fraudolenta." + "state" : "translated", + "value" : "Avvisami sui siti contrassegnati per phishing o malware." } }, "nl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Laat DuckDuckGo je waarschuwen voordat je een webpagina laadt die als kwaadaardig of frauduleus is gemarkeerd." + "state" : "translated", + "value" : "Waarschuw me op websites die zijn aangeduid als phishing of malware." } }, "pl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Zezwól DuckDuckGo na ostrzeganie przed załadowaniem strony internetowej, która została oznaczona jako złośliwa lub jako oszustwo." + "state" : "translated", + "value" : "Ostrzegaj mnie przed witrynami oznaczonymi jako wyłudzanie informacji lub złośliwe oprogramowanie." } }, "pt" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Permitir que o DuckDuckGo te avise antes de carregar uma página que foi sinalizada como maliciosa ou fraudulenta." + "state" : "translated", + "value" : "Avisar-me sobre sites sinalizados como phishing ou malware." } }, "ru" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Разрешить DuckDuckGo предупреждать вас о потенциально вредоносных или мошеннических сайтах перед загрузкой страницы." + "state" : "translated", + "value" : "Предупреждать о вредоносных и фишинговых сайтах" } } } @@ -47224,8 +47272,8 @@ "localizations" : { "de" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Das Deaktivieren dieser Funktion kann deine persönlichen Daten gefährden. Wenn du dir über die damit verbundenen Risiken im Klaren bist, kannst du trotzdem fortfahren." + "state" : "translated", + "value" : "Das Deaktivieren dieser Funktion kann deine persönlichen Daten gefährden." } }, "en" : { @@ -47236,44 +47284,44 @@ }, "es" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Desactivar esta función puede poner en riesgo tu información personal. Hazlo solo si entiendes completamente el riesgo que implica." + "state" : "translated", + "value" : "Desactivar esta función puede poner en riesgo tu información personal." } }, "fr" : { "stringUnit" : { - "state" : "needs_review", - "value" : "La désactivation de cette fonctionnalité peut mettre vos informations personnelles en danger. Faites-le uniquement si vous comprenez parfaitement les risques encourus." + "state" : "translated", + "value" : "La désactivation de cette fonctionnalité peut mettre vos informations personnelles en danger." } }, "it" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Disabilitando questa funzione, potresti mettere a rischio i tuoi dati personali. Fallo solo se comprendi appieno il rischio che comporta." + "state" : "translated", + "value" : "Disabilitando questa funzione, potresti mettere a rischio i tuoi dati personali." } }, "nl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Als je deze functie uitschakelt, kunnen je persoonlijke gegevens in gevaar komen. Doe dit alleen als je het risico volledig begrijpt." + "state" : "translated", + "value" : "Als je deze functie uitschakelt, kunnen je persoonlijke gegevens in gevaar komen." } }, "pl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Wyłączenie tej funkcji może narazić Twoje dane osobowe na ryzyko. Rób to tylko wtedy, gdy rozumiesz związane z tym zagrożenie." + "state" : "translated", + "value" : "Wyłączenie tej funkcji może narazić Twoje dane osobowe na ryzyko." } }, "pt" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Desativar esta funcionalidade pode pôr em risco as tuas informações pessoais. Não desatives a menos que compreendas os riscos." + "state" : "translated", + "value" : "Desativar esta funcionalidade pode pôr em risco as tuas informações pessoais." } }, "ru" : { "stringUnit" : { - "state" : "needs_review", - "value" : "При отключении этой функции ваши личные данные могут оказаться под угрозой. Эту функцию следует деактивировать только в том случае, если вы осознаете связанные с этим риски." + "state" : "translated", + "value" : "При отключении этой функции ваши личные данные могут оказаться под угрозой." } } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift index dfed042d42..e0a7bab18c 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift @@ -315,6 +315,11 @@ public final class PreferencesSubscriptionModel: ObservableObject { userEventHandler(.openFeedback) } + @MainActor + func openPrivacyPolicy() { + openURLHandler(URL(string: "https://duckduckgo.com/pro/privacy-terms")!) + } + @MainActor func refreshSubscriptionPendingState() { if subscriptionManager.currentEnvironment.purchasePlatform == .appStore { diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionView.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionView.swift index ec66c0b134..8bcc0f4ba0 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionView.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionView.swift @@ -101,11 +101,6 @@ public struct PreferencesSubscriptionView: View { // Help section helpSection - - // Feedback section - if subscriptionFeatureAvailability.usesUnifiedFeedbackForm, state == .subscriptionActive { - feedbackSection - } } .onAppear(perform: { model.didAppear() @@ -303,24 +298,21 @@ public struct PreferencesSubscriptionView: View { private var helpSection: some View { PreferencePaneSection { TextMenuItemHeader(UserText.preferencesSubscriptionFooterTitle, bottomPadding: 0) - HStack(alignment: .top, spacing: 6) { - if !model.isROWLaunched { - TextMenuItemCaption(UserText.preferencesSubscriptionFooterCaption) - } else { - TextMenuItemCaption(UserText.preferencesSubscriptionHelpFooterCaption) - } - Button(UserText.viewFaqsButton) { model.openFAQ() } + if !model.isROWLaunched { + TextMenuItemCaption(UserText.preferencesSubscriptionFooterCaption) + .padding(.bottom, 8) + } else { + TextMenuItemCaption(UserText.preferencesSubscriptionHelpFooterCaption) + .padding(.bottom, 8) } - } - } + VStack(alignment: .leading, spacing: 16) { + TextButton(UserText.viewFaqsButton, weight: .semibold) { model.openFAQ() } - @ViewBuilder - private var feedbackSection: some View { - PreferencePaneSection { - TextMenuItemHeader(UserText.preferencesSubscriptionFeedbackTitle, bottomPadding: 0) - HStack(alignment: .top, spacing: 6) { - TextMenuItemCaption(UserText.preferencesSubscriptionFeedbackCaption) - Button(UserText.preferencesSubscriptionFeedbackButton) { model.openUnifiedFeedbackForm() } + if subscriptionFeatureAvailability.usesUnifiedFeedbackForm, state == .subscriptionActive { + TextButton(UserText.preferencesSubscriptionFeedbackButton, weight: .semibold) { model.openUnifiedFeedbackForm() } + } + + TextButton(UserText.preferencesPrivacyPolicyButton, weight: .semibold) { model.openPrivacyPolicy() } } } } @@ -495,6 +487,7 @@ private struct SubscriptionDialog: View where Buttons: View { .fixMultilineScrollableText() .foregroundColor(Color(.textPrimary)) } buttons: { + Spacer() buttons() } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Resources/Localizable.xcstrings b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Resources/Localizable.xcstrings index c7836d0be0..f909d5486a 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Resources/Localizable.xcstrings +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Resources/Localizable.xcstrings @@ -2265,6 +2265,66 @@ } } }, + "subscription.preferences.privacypolicy.button" : { + "comment" : "Title for the privacy policy button", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datenschutzerklärung und Nutzungsbedingungen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Privacy Policy and Terms of Service" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Política de privacidad y condiciones del servicio" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Politique de confidentialité et conditions d'utilisation" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy policy e Termini del servizio" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacybeleid en servicevoorwaarden" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Polityka prywatności i warunki użytkowania" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Política de Privacidade e Termos de Serviço" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Политика конфиденциальности и условия обслуживания" + } + } + } + }, "subscription.preferences.purchase.button" : { "comment" : "Button to open a page where user can learn more and purchase the subscription", "extractionState" : "extracted_with_value", diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/UserText.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/UserText.swift index a0c9d163a0..8f4e5a018a 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/UserText.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/UserText.swift @@ -54,6 +54,7 @@ enum UserText { static let preferencesSubscriptionFeedbackTitle = NSLocalizedString("subscription.preferences.feedback.title", bundle: Bundle.module, value: "Send Feedback", comment: "Title for the subscription feedback section") static let preferencesSubscriptionFeedbackCaption = NSLocalizedString("subscription.preferences.feedback.caption", bundle: Bundle.module, value: "Help improve Privacy Pro. Your feedback matters to us. Feel free to report any issues or provide general feedback.", comment: "Caption for the subscription feedback section") static let preferencesSubscriptionFeedbackButton = NSLocalizedString("subscription.preferences.feedback.button", bundle: Bundle.module, value: "Send Feedback", comment: "Title for the subscription feedback button") + static let preferencesPrivacyPolicyButton = NSLocalizedString("subscription.preferences.privacypolicy.button", bundle: Bundle.module, value: "Privacy Policy and Terms of Service", comment: "Title for the privacy policy button") static func preferencesSubscriptionRenewingCaption(billingPeriod: Subscription.BillingPeriod, formattedDate: String) -> String { let localized: String From f8fda48c2670e96be07de56ecba824a988f85e04 Mon Sep 17 00:00:00 2001 From: Anka Date: Thu, 19 Dec 2024 18:25:24 +0000 Subject: [PATCH 3/3] Bump version to 1.119.0 (332) --- Configuration/BuildNumber.xcconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Configuration/BuildNumber.xcconfig b/Configuration/BuildNumber.xcconfig index 610113ea86..78ac15dc98 100644 --- a/Configuration/BuildNumber.xcconfig +++ b/Configuration/BuildNumber.xcconfig @@ -1 +1 @@ -CURRENT_PROJECT_VERSION = 330 +CURRENT_PROJECT_VERSION = 332