diff --git a/browser/net/brave_translate_redirect_network_delegate_helper.cc b/browser/net/brave_translate_redirect_network_delegate_helper.cc index 09d135bde310b..1d98e722ee543 100644 --- a/browser/net/brave_translate_redirect_network_delegate_helper.cc +++ b/browser/net/brave_translate_redirect_network_delegate_helper.cc @@ -8,8 +8,10 @@ #include #include #include + #include "brave/common/translate_network_constants.h" #include "extensions/common/url_pattern.h" +#include "net/base/net_errors.h" namespace { const char kTranslateElementLibQuery[] = "client=te_lib"; diff --git a/browser/net/brave_translate_redirect_network_delegate_helper_unittest.cc b/browser/net/brave_translate_redirect_network_delegate_helper_unittest.cc index c57feb02a5590..fee7da292c840 100644 --- a/browser/net/brave_translate_redirect_network_delegate_helper_unittest.cc +++ b/browser/net/brave_translate_redirect_network_delegate_helper_unittest.cc @@ -15,7 +15,6 @@ #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/url_request_test_util.h" #include "url/gurl.h" -// #include "url/url_constants.h" namespace { @@ -23,14 +22,13 @@ class BraveTranslateRedirectNetworkDelegateHelperTest : public testing::Test { public: BraveTranslateRedirectNetworkDelegateHelperTest() - : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), - context_(new net::TestURLRequestContext(true)) {} + : context_(new net::TestURLRequestContext(true)) {} ~BraveTranslateRedirectNetworkDelegateHelperTest() override {} void SetUp() override { context_->Init(); } net::TestURLRequestContext* context() { return context_.get(); } private: - content::TestBrowserThreadBundle thread_bundle_; + content::BrowserTaskEnvironment task_environment_; std::unique_ptr context_; }; @@ -52,8 +50,8 @@ TEST_F(BraveTranslateRedirectNetworkDelegateHelperTest, std::shared_ptr before_url_context( new brave::BraveRequestInfo()); - brave::BraveRequestInfo::FillCTXFromRequest(request.get(), - before_url_context); + before_url_context->initiator_url = GURL(kTranslateInitiatorURL); + before_url_context->request_url = url; brave::ResponseCallback callback; GURL expected_url(kBraveTranslateServer + path_string); @@ -81,8 +79,7 @@ TEST_F(BraveTranslateRedirectNetworkDelegateHelperTest, std::shared_ptr before_url_context( new brave::BraveRequestInfo()); - brave::BraveRequestInfo::FillCTXFromRequest(request.get(), - before_url_context); + before_url_context->request_url = url; brave::ResponseCallback callback; int ret = OnBeforeURLRequest_TranslateRedirectWork(callback, @@ -110,8 +107,7 @@ TEST_F(BraveTranslateRedirectNetworkDelegateHelperTest, std::shared_ptr before_url_context( new brave::BraveRequestInfo()); - brave::BraveRequestInfo::FillCTXFromRequest(request.get(), - before_url_context); + before_url_context->request_url = url; brave::ResponseCallback callback; GURL expected_url(kBraveTranslateServer + url.path()); @@ -137,8 +133,8 @@ TEST_F(BraveTranslateRedirectNetworkDelegateHelperTest, std::shared_ptr before_url_context( new brave::BraveRequestInfo()); - brave::BraveRequestInfo::FillCTXFromRequest(request.get(), - before_url_context); + before_url_context->initiator_url = GURL(kTranslateInitiatorURL); + before_url_context->request_url = url; brave::ResponseCallback callback; GURL expected_url(kBraveTranslateEndpoint + std::string("?") + url.query()); @@ -162,8 +158,7 @@ TEST_F(BraveTranslateRedirectNetworkDelegateHelperTest, std::shared_ptr before_url_context( new brave::BraveRequestInfo()); - brave::BraveRequestInfo::FillCTXFromRequest(request.get(), - before_url_context); + before_url_context->request_url = url; brave::ResponseCallback callback; GURL expected_url(kBraveTranslateServer + url.path()); @@ -186,8 +181,7 @@ TEST_F(BraveTranslateRedirectNetworkDelegateHelperTest, std::shared_ptr before_url_context( new brave::BraveRequestInfo()); - brave::BraveRequestInfo::FillCTXFromRequest(request.get(), - before_url_context); + before_url_context->request_url = url; brave::ResponseCallback callback; int ret = OnBeforeURLRequest_TranslateRedirectWork(callback, @@ -210,8 +204,7 @@ TEST_F(BraveTranslateRedirectNetworkDelegateHelperTest, std::shared_ptr before_url_context( new brave::BraveRequestInfo()); - brave::BraveRequestInfo::FillCTXFromRequest(request.get(), - before_url_context); + before_url_context->request_url = url; brave::ResponseCallback callback; int ret = OnBeforeURLRequest_TranslateRedirectWork(callback, diff --git a/chromium_src/chrome/browser/ui/translate/DEPS b/chromium_src/chrome/browser/ui/translate/DEPS new file mode 100644 index 0000000000000..c4f1c33d02487 --- /dev/null +++ b/chromium_src/chrome/browser/ui/translate/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+../../../../../../chrome/browser/ui/translate", +] diff --git a/chromium_src/chrome/browser/ui/translate/translate_bubble_model_impl.cc b/chromium_src/chrome/browser/ui/translate/translate_bubble_model_impl.cc new file mode 100644 index 0000000000000..b1a13ee762bcc --- /dev/null +++ b/chromium_src/chrome/browser/ui/translate/translate_bubble_model_impl.cc @@ -0,0 +1,135 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "chrome/browser/ui/translate/translate_bubble_model_impl.h" + +#define TranslateBubbleModelImpl ChromiumTranslateBubbleModelImpl +#include "../../../../../../chrome/browser/ui/translate/translate_bubble_model_impl.cc" +#undef TranslateBubbleModelImpl + +#include "base/containers/contains.h" +#include "brave/components/translate/core/browser/brave_translate_language_filter.h" + +namespace { +const int kNoIndex = static_cast(translate::TranslateUIDelegate::kNoIndex); +} // namespace + +// A mapping between a chromium languages list in |ui_delegate| and a brave +// languages list (a limited subset of chromium list preassigned by |filter|). +// Note: mixin of int/size_t types is used because of chromium implementation. +class BraveLanguageMap { + public: + BraveLanguageMap(const translate::TranslateUIDelegate* ui_delegate, + base::RepeatingCallback filter) { + int ui_index = 0; + for (size_t core_index = 0; + core_index < ui_delegate->GetNumberOfLanguages(); ++core_index) { + const auto lang = ui_delegate->GetLanguageCodeAt(core_index); + if (!filter.Run(lang)) + continue; + to_core_index_[ui_index] = core_index; + to_ui_index_[core_index] = ui_index; + ++ui_index; + } + DCHECK_EQ(to_ui_index_.size(), to_core_index_.size()); +#if DCHECK_IS_ON() + for (int i = 0; i < static_cast(to_core_index_.size()); ++i) { + const auto core_ind = to_core_index_[i]; + DCHECK_EQ(to_ui_index_[to_core_index_[i]], i); + DCHECK_EQ(to_core_index_[to_ui_index_[core_ind]], core_ind); + } +#endif // DCHECK_IS_ON() + } + + // Coverts index in brave list (index in [0, GetSize() - 1]) to a correspoding + // chromium index. + size_t ToCoreIndex(int index) const { + if (index == kNoIndex) + return translate::TranslateUIDelegate::kNoIndex; + const auto it = to_core_index_.find(index); + return it != to_core_index_.end() + ? it->second + : translate::TranslateUIDelegate::kNoIndex; + } + + // An inverse function to ToCoreIndex(). Coverts chromium index + // (form [0, ui_delegate->GetNumberOfLanguages()] to a + // correspoding index in brave list. + int FromCoreIndex(size_t index) const { + if (index == translate::TranslateUIDelegate::kNoIndex) + return kNoIndex; + const auto it = to_ui_index_.find(index); + return it != to_ui_index_.end() ? it->second : kNoIndex; + } + + int GetSize() const { return to_core_index_.size(); } + + private: + std::map to_core_index_; + std::map to_ui_index_; +}; + +TranslateBubbleModelImpl::TranslateBubbleModelImpl( + translate::TranslateStep step, + std::unique_ptr ui_delegate) + : ChromiumTranslateBubbleModelImpl(step, std::move(ui_delegate)) { + source_language_map_ = std::make_unique( + ui_delegate_.get(), + base::BindRepeating(&translate::IsSourceLanguageCodeSupported)); + target_language_map_ = std::make_unique( + ui_delegate_.get(), + base::BindRepeating(&translate::IsTargetLanguageCodeSupported)); + + // If the source language is unsupported then drop it to "und". + // Theoretically it isn't the same as creating ui_delegate with source_lang == + // und, because |initial_source_language_index_| hasn't been updated. But in + // fact chromium doesn't use |initial_source_language_index_| at all. + if (!translate::IsSourceLanguageCodeSupported( + ui_delegate_->GetSourceLanguageCode())) { + ui_delegate_->UpdateSourceLanguageIndex(0u); + } +} + +TranslateBubbleModelImpl::~TranslateBubbleModelImpl() = default; + +int TranslateBubbleModelImpl::GetNumberOfSourceLanguages() const { + return source_language_map_->GetSize(); +} + +int TranslateBubbleModelImpl::GetNumberOfTargetLanguages() const { + return target_language_map_->GetSize(); +} + +std::u16string TranslateBubbleModelImpl::GetSourceLanguageNameAt( + int index) const { + return ui_delegate_->GetLanguageNameAt( + source_language_map_->ToCoreIndex(index)); +} + +std::u16string TranslateBubbleModelImpl::GetTargetLanguageNameAt( + int index) const { + return ui_delegate_->GetLanguageNameAt( + target_language_map_->ToCoreIndex(index)); +} + +int TranslateBubbleModelImpl::GetSourceLanguageIndex() const { + return source_language_map_->FromCoreIndex( + ui_delegate_->GetSourceLanguageIndex()); +} + +int TranslateBubbleModelImpl::GetTargetLanguageIndex() const { + return target_language_map_->FromCoreIndex( + ui_delegate_->GetTargetLanguageIndex()); +} + +void TranslateBubbleModelImpl::UpdateSourceLanguageIndex(int index) { + ui_delegate_->UpdateSourceLanguageIndex( + source_language_map_->ToCoreIndex(index)); +} + +void TranslateBubbleModelImpl::UpdateTargetLanguageIndex(int index) { + ui_delegate_->UpdateTargetLanguageIndex( + target_language_map_->ToCoreIndex(index)); +} diff --git a/chromium_src/chrome/browser/ui/translate/translate_bubble_model_impl.h b/chromium_src/chrome/browser/ui/translate/translate_bubble_model_impl.h new file mode 100644 index 0000000000000..42f78b3893f6f --- /dev/null +++ b/chromium_src/chrome/browser/ui/translate/translate_bubble_model_impl.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_CHROMIUM_SRC_CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_MODEL_IMPL_H_ +#define BRAVE_CHROMIUM_SRC_CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_MODEL_IMPL_H_ + +class TranslateBubbleModelImpl; +using BraveTranslateBubbleModelImpl = TranslateBubbleModelImpl; + +#define TranslateBubbleModelImpl ChromiumTranslateBubbleModelImpl +#define translate_executed_ \ + translate_executed_; \ + friend BraveTranslateBubbleModelImpl +#include "../../../../../../chrome/browser/ui/translate/translate_bubble_model_impl.h" +#undef translate_executed_ +#undef TranslateBubbleModelImpl + +class BraveLanguageMap; + +// Brave customization of TranslateBubbleModelImpl that uses separated lists for +// source and target languages. Holds two mappings between chromium languages +// list in |ui_delegate| and brave lists. +class TranslateBubbleModelImpl : public ChromiumTranslateBubbleModelImpl { + public: + TranslateBubbleModelImpl( + translate::TranslateStep step, + std::unique_ptr ui_delegate); + + ~TranslateBubbleModelImpl() override; + + int GetNumberOfSourceLanguages() const override; + int GetNumberOfTargetLanguages() const override; + std::u16string GetSourceLanguageNameAt(int index) const override; + std::u16string GetTargetLanguageNameAt(int index) const override; + int GetSourceLanguageIndex() const override; + int GetTargetLanguageIndex() const override; + void UpdateSourceLanguageIndex(int index) override; + void UpdateTargetLanguageIndex(int index) override; + + private: + std::unique_ptr source_language_map_; + std::unique_ptr target_language_map_; +}; + +#endif // BRAVE_CHROMIUM_SRC_CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_MODEL_IMPL_H_ diff --git a/chromium_src/components/translate/core/browser/DEPS b/chromium_src/components/translate/core/browser/DEPS index daa8c8b0b84db..97dba98cebc03 100644 --- a/chromium_src/components/translate/core/browser/DEPS +++ b/chromium_src/components/translate/core/browser/DEPS @@ -14,4 +14,7 @@ specific_include_rules = { "translate_url_fetcher(\.cc|\.h)": [ "+brave/browser/translate/buildflags/buildflags.h", ], + "translate_manager(\.cc|\.h)": [ + "+brave/browser/translate/buildflags/buildflags.h", + ], } diff --git a/chromium_src/components/translate/core/browser/translate_manager.cc b/chromium_src/components/translate/core/browser/translate_manager.cc index e30a9989f14c0..80ec9fdb58b61 100644 --- a/chromium_src/components/translate/core/browser/translate_manager.cc +++ b/chromium_src/components/translate/core/browser/translate_manager.cc @@ -5,9 +5,84 @@ #include "components/translate/core/browser/translate_manager.h" +#include "brave/browser/translate/buildflags/buildflags.h" +#include "brave/components/translate/core/browser/brave_translate_language_filter.h" +#include "components/translate/core/browser/translate_download_manager.h" +#include "components/translate/core/browser/translate_prefs.h" + +namespace translate { + +class BraveIsSupportedTargetLanguageProxy : public TranslateDownloadManager { + public: +#if BUILDFLAG(ENABLE_BRAVE_TRANSLATE_GO) + static bool IsSupportedLanguage(const std::string& lang) { + return IsTargetLanguageCodeSupported(lang); + } +#endif // BUILDFLAG(ENABLE_BRAVE_TRANSLATE_GO) + ~BraveIsSupportedTargetLanguageProxy() override; +}; + +} // namespace translate +#define ASSERT_INSIDE_FUNCTION(fname) \ + static_assert(base::StringPiece(__FUNCTION__) == fname, \ + "should work only within " fname " function"); + +#define GetRecentTargetLanguage \ + GetRecentTargetLanguage(); \ + ASSERT_INSIDE_FUNCTION("GetTargetLanguage") \ + using TranslateDownloadManager = BraveIsSupportedTargetLanguageProxy; \ + void #define HasAPIKeyConfigured BraveHasAPIKeyConfigured -#include "../../../../../../components/translate/core/browser/translate_manager.cc" // NOLINT +#define TranslateManager ChromiumTranslateManager +#include "../../../../../../components/translate/core/browser/translate_manager.cc" #undef HasAPIKeyConfigured +#undef TranslateManager +#undef ASSERT_INSIDE_FUNCTION + +namespace translate { + +void TranslateManager::FilterIsTranslatePossible( + TranslateTriggerDecision* decision, + TranslatePrefs* translate_prefs, + const std::string& page_language_code, + const std::string& target_lang) { + ChromiumTranslateManager::FilterIsTranslatePossible( + decision, translate_prefs, page_language_code, target_lang); +#if BUILDFLAG(ENABLE_BRAVE_TRANSLATE_GO) + // The source language is not supported by Brave backend. Currently we allow a + // user to trigger a manual translation to have a chance to change the + // incorrectly recognized source language to the correct one. + if (!IsSourceLanguageCodeSupported(page_language_code)) { + decision->PreventAutoTranslate(); + decision->PreventShowingUI(); + decision->initiation_statuses.push_back( + TranslateBrowserMetrics::INITIATION_STATUS_LANGUAGE_IS_NOT_SUPPORTED); + decision->ranker_events.push_back( + metrics::TranslateEventProto::UNSUPPORTED_LANGUAGE); + GetActiveTranslateMetricsLogger()->LogTriggerDecision( + TriggerDecision::kDisabledUnsupportedLanguage); + } + + // Just in case. In general a user can't trigger a translation to an + // unsupported target language. But some new entry points can be added so + // block translation in that case. + if (!IsTargetLanguageCodeSupported(target_lang)) { + decision->PreventAllTriggering(); + decision->initiation_statuses.push_back( + TranslateBrowserMetrics::INITIATION_STATUS_LANGUAGE_IS_NOT_SUPPORTED); + decision->ranker_events.push_back( + metrics::TranslateEventProto::UNSUPPORTED_LANGUAGE); + GetActiveTranslateMetricsLogger()->LogTriggerDecision( + TriggerDecision::kDisabledUnsupportedLanguage); + } +#endif // BUILDFLAG(ENABLE_BRAVE_TRANSLATE_GO) +} + +base::WeakPtr TranslateManager::GetWeakPtr() { + return AsWeakPtr(); +} + +} // namespace translate namespace google_apis { diff --git a/chromium_src/components/translate/core/browser/translate_manager.h b/chromium_src/components/translate/core/browser/translate_manager.h new file mode 100644 index 0000000000000..55bba3e6920e1 --- /dev/null +++ b/chromium_src/components/translate/core/browser/translate_manager.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_CHROMIUM_SRC_COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_MANAGER_H_ +#define BRAVE_CHROMIUM_SRC_COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_MANAGER_H_ + +namespace translate { +class TranslateManager; +using BraveTranslateManager = TranslateManager; +} // namespace translate + +#define TranslateManager ChromiumTranslateManager +#define ignore_missing_key_for_testing_ \ + ignore_missing_key_for_testing_; \ + friend BraveTranslateManager +#define FilterIsTranslatePossible virtual FilterIsTranslatePossible +#include "../../../../../../components/translate/core/browser/translate_manager.h" +#undef FilterIsTranslatePossible +#undef ignore_missing_key_for_testing_ +#undef TranslateManager + +namespace translate { + +// Brave customization of TranslateManager that limit the number of supported +// languages. Also two independet lists are used for source and target +// languages. +class TranslateManager : public ChromiumTranslateManager, + public base::SupportsWeakPtr { + public: + using ChromiumTranslateManager::ChromiumTranslateManager; + void FilterIsTranslatePossible(TranslateTriggerDecision* decision, + TranslatePrefs* translate_prefs, + const std::string& page_language_code, + const std::string& target_lang) override; + base::WeakPtr GetWeakPtr(); +}; + +} // namespace translate + +#endif // BRAVE_CHROMIUM_SRC_COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_MANAGER_H_ diff --git a/components/translate/core/browser/BUILD.gn b/components/translate/core/browser/BUILD.gn index 80017fb6cb8e1..522b8ec82862e 100644 --- a/components/translate/core/browser/BUILD.gn +++ b/components/translate/core/browser/BUILD.gn @@ -1,4 +1,9 @@ source_set("browser") { + sources = [ + "brave_translate_language_filter.cc", + "brave_translate_language_filter.h", + ] + deps = [ "//base" ] public_deps = [ # TODO(jocelyn): move buildflags to brave/components/translate/core/browser "//brave/browser/translate/buildflags", diff --git a/components/translate/core/browser/brave_translate_language_filter.cc b/components/translate/core/browser/brave_translate_language_filter.cc new file mode 100644 index 0000000000000..20ed04aabc631 --- /dev/null +++ b/components/translate/core/browser/brave_translate_language_filter.cc @@ -0,0 +1,30 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/translate/core/browser/brave_translate_language_filter.h" + +#include "base/containers/contains.h" +#include "base/strings/string_piece.h" + +namespace translate { +namespace { +// Note: keep sync with language/language.go (brave/go-translate repo) +constexpr base::StringPiece kSourceLanguages[] = {"und", "en", "es", "et", + "it", "pt", "ru"}; + +// Note: keep sync with language/language.go (brave/go-translate repo) +constexpr base::StringPiece kTargetLanguages[] = {"de", "en", "es", "et", "ru"}; + +} // namespace + +bool IsSourceLanguageCodeSupported(const std::string& lang_code) { + return base::Contains(kSourceLanguages, lang_code); +} + +bool IsTargetLanguageCodeSupported(const std::string& lang_code) { + return base::Contains(kTargetLanguages, lang_code); +} + +} // namespace translate diff --git a/components/translate/core/browser/brave_translate_language_filter.h b/components/translate/core/browser/brave_translate_language_filter.h new file mode 100644 index 0000000000000..87e43b36c0524 --- /dev/null +++ b/components/translate/core/browser/brave_translate_language_filter.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_TRANSLATE_CORE_BROWSER_BRAVE_TRANSLATE_LANGUAGE_FILTER_H_ +#define BRAVE_COMPONENTS_TRANSLATE_CORE_BROWSER_BRAVE_TRANSLATE_LANGUAGE_FILTER_H_ + +#include + +namespace translate { + +// Returns true if the source language |lang_code| is supported by Brave +// backend. +bool IsSourceLanguageCodeSupported(const std::string& lang_code); + +// Returns true if the target language |lang_code| is supported by Brave +// backend. +bool IsTargetLanguageCodeSupported(const std::string& lang_code); + +} // namespace translate + +#endif // BRAVE_COMPONENTS_TRANSLATE_CORE_BROWSER_BRAVE_TRANSLATE_LANGUAGE_FILTER_H_ diff --git a/test/BUILD.gn b/test/BUILD.gn index d701c94d18d3c..3feca9d9913de 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -233,6 +233,7 @@ test("brave_unit_tests") { "//components/country_codes", "//components/domain_reliability:domain_reliability", "//components/language/core/browser", + "//components/language/core/common", "//components/os_crypt:test_support", "//components/page_load_metrics/common", "//components/permissions",