From fc0ea9b681d42d5e1f8c7c41c2b9678cee5c25a3 Mon Sep 17 00:00:00 2001 From: Daniel Bernal Date: Wed, 28 Aug 2024 14:38:33 +0200 Subject: [PATCH] [DuckPlayer] 24. FrontEnd Translation (#3281) Task/Issue URL: https://app.asana.com/0/1204099484721401/1208149666429213/f Description: Translates Duckplayer FrontEnd and updates copy based on Ship Review Removes copy from DP footer in settings Updates Copy for DuckPlayer Prompt and Settings to be new, and the same --- DuckDuckGo/DuckPlayer/DuckPlayer.swift | 37 +++++++++++++++++-------- DuckDuckGo/SettingsDuckPlayerView.swift | 4 --- DuckDuckGo/UserText.swift | 6 ++-- DuckDuckGo/en.lproj/Localizable.strings | 6 ++-- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/DuckDuckGo/DuckPlayer/DuckPlayer.swift b/DuckDuckGo/DuckPlayer/DuckPlayer.swift index 2a74174274..a861d7b478 100644 --- a/DuckDuckGo/DuckPlayer/DuckPlayer.swift +++ b/DuckDuckGo/DuckPlayer/DuckPlayer.swift @@ -24,6 +24,7 @@ import Foundation import WebKit import UserScript import Core +import ContentScopeScripts /// Values that the Frontend can use to determine the current state. struct InitialPlayerSettings: Codable { @@ -48,16 +49,13 @@ struct InitialPlayerSettings: Codable { case development case production } - - enum Locale: String, Codable { - case en - } let userValues: UserValues let ui: UIValues let settings: PlayerSettings let platform: Platform - let locale: Locale + let locale: String + let localeStrings: String? } /// Values that the Frontend can use to determine user settings @@ -105,11 +103,25 @@ final class DuckPlayer: DuckPlayerProtocol { struct Constants { static let duckPlayerHost: String = "player" static let commonName = "Duck Player" + static let translationFile = "duckplayer" + static let translationFileExtension = "json" + static let defaultLocale = "en" + static let translationPath = "pages/duckplayer/locales/" } private(set) var settings: DuckPlayerSettingsProtocol private(set) weak var hostView: UIViewController? + private lazy var localeStrings: String? = { + let languageCode = Locale.current.languageCode ?? Constants.defaultLocale + if let localizedFile = ContentScopeScripts.Bundle.path(forResource: Constants.translationFile, + ofType: Constants.translationFileExtension, + inDirectory: "\(Constants.translationPath)\(languageCode)") { + return try? String(contentsOfFile: localizedFile) + } + return nil + }() + private struct WKMessageData: Codable { var context: String? var featureName: String? @@ -213,16 +225,17 @@ final class DuckPlayer: DuckPlayerProtocol { let isPiPEnabled = webView?.configuration.allowsPictureInPictureMediaPlayback == true let pip = InitialPlayerSettings.PIP(status: isPiPEnabled ? .enabled : .disabled) let platform = InitialPlayerSettings.Platform(name: "ios") -// let environment = InitialPlayerSettings.Environment.development - let locale = InitialPlayerSettings.Locale.en + let locale = Locale.current.languageCode ?? "en" let playerSettings = InitialPlayerSettings.PlayerSettings(pip: pip) let userValues = encodeUserValues() let uiValues = encodeUIValues() - return InitialPlayerSettings(userValues: userValues, - ui: uiValues, - settings: playerSettings, - platform: platform, - locale: locale) + let settings = InitialPlayerSettings(userValues: userValues, + ui: uiValues, + settings: playerSettings, + platform: platform, + locale: locale, + localeStrings: localeStrings) + return settings } // Accessing WKMessage needs main thread diff --git a/DuckDuckGo/SettingsDuckPlayerView.swift b/DuckDuckGo/SettingsDuckPlayerView.swift index d9ef668ad1..8df6eb7678 100644 --- a/DuckDuckGo/SettingsDuckPlayerView.swift +++ b/DuckDuckGo/SettingsDuckPlayerView.swift @@ -72,10 +72,6 @@ struct SettingsDuckPlayerView: View { options: DuckPlayerMode.allCases, selectedOption: viewModel.duckPlayerModeBinding) .disabled(viewModel.shouldDisplayDuckPlayerContingencyMessage) - } footer: { - Text(UserText.settingsDuckPlayerFooter) - .daxFootnoteRegular() - .multilineTextAlignment(.center) } } .applySettingsListModifiers(title: UserText.duckPlayerFeatureName, diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index c3f08921e0..31e83f13d1 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -1267,10 +1267,10 @@ But if you *do* want a peek under the hood, you can find more information about public static let settingsOpenVideosInDuckPlayerTitle = NSLocalizedString("duckplayer.settings.title", value: "Duck Player", comment: "Settings screen cell text for DuckPlayer settings") public static let settingsDuckPlayerFooter = NSLocalizedString("duckplayer.settings.footer", value: "DuckDuckGo provides all the privacy essentials you need to protect yourself as you browse the web.", comment: "Footer label in the settings screen for Duck Player") public static let settingsDuckPlayerLearnMore = NSLocalizedString("duckplayer.settings.learn-more", value: "Learn More", comment: "Button that takes the user to learn more about Duck Player.") - public static let settingsDuckPlayerInfoText = NSLocalizedString("duckplayer.settings.info-text", value: "Duck Player provides a clean viewing experience without personalized ads and prevents viewing activity from influencing your YouTube recommendations.", comment: "Text explaining what Duck Player is in the settings screen.") + public static let settingsDuckPlayerInfoText = NSLocalizedString("duckplayer.settings.info-text", value: "Duck Player lets you watch YouTube without targeted ads in DuckDuckGo and what you watch won’t influence your recommendations.", comment: "Text explaining what Duck Player is in the settings screen.") - public static let duckPlayerPresentationModalTitle = NSLocalizedString("duckplayer.presentation.modal.title", value: "Drowning in ads on YouTube? Try Duck Player!", comment: "Two line title (separated by \n) for the feature explanation") - public static let duckPlayerPresentationModalBody = NSLocalizedString("duckplayer.presentation.modal.body", value: "Duck Player lets you watch YouTube without targeted ads in a theater-like experience in DuckDuckGo and what you watch won’t influence your recommendations.", comment: "Body text for the modal feature explanation") + public static let duckPlayerPresentationModalTitle = NSLocalizedString("duckplayer.presentation.modal.title", value: "Drowning in ads on YouTube? Not with Duck Player!", comment: "Two line title (separated by \n) for the feature explanation") + public static let duckPlayerPresentationModalBody = NSLocalizedString("duckplayer.presentation.modal.body", value: "Duck Player lets you watch YouTube without targeted ads in DuckDuckGo and what you watch won’t influence your recommendations.", comment: "Body text for the modal feature explanation") public static let duckPlayerPresentationModalDismissButton = NSLocalizedString("duckplayer.presentation.modal.dismiss-button", value: "Got it!", comment: "Button that will dismiss the modal") static let duckPlayerContingencyMessageTitle = NSLocalizedString("duck-player.contingency-title", value: "Duck Player Unavailable", comment: "Title for message explaining to the user that Duck Player is not available") diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index b38a28e564..1ff95f6617 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -1002,19 +1002,19 @@ "duckPlayer.never.label" = "Never"; /* Body text for the modal feature explanation */ -"duckplayer.presentation.modal.body" = "Duck Player lets you watch YouTube without targeted ads in a theater-like experience in DuckDuckGo and what you watch won’t influence your recommendations."; +"duckplayer.presentation.modal.body" = "Duck Player lets you watch YouTube without targeted ads in DuckDuckGo and what you watch won’t influence your recommendations."; /* Button that will dismiss the modal */ "duckplayer.presentation.modal.dismiss-button" = "Got it!"; /* Two line title (separated by \n) for the feature explanation */ -"duckplayer.presentation.modal.title" = "Drowning in ads on YouTube? Try Duck Player!"; +"duckplayer.presentation.modal.title" = "Drowning in ads on YouTube? Not with Duck Player!"; /* Footer label in the settings screen for Duck Player */ "duckplayer.settings.footer" = "DuckDuckGo provides all the privacy essentials you need to protect yourself as you browse the web."; /* Text explaining what Duck Player is in the settings screen. */ -"duckplayer.settings.info-text" = "Duck Player provides a clean viewing experience without personalized ads and prevents viewing activity from influencing your YouTube recommendations."; +"duckplayer.settings.info-text" = "Duck Player lets you watch YouTube without targeted ads in DuckDuckGo and what you watch won’t influence your recommendations."; /* Button that takes the user to learn more about Duck Player. */ "duckplayer.settings.learn-more" = "Learn More";