summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorjcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-12 21:53:55 +0000
committerjcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-12 21:53:55 +0000
commit3b1c18191d41eac0a551b3009269a259757ca070 (patch)
tree5f466b716abc81ac3bb67262522ba1af0d699588 /chrome
parent7d9ad0b30c0775a7345e965294c9f86bb0d543e5 (diff)
downloadchromium_src-3b1c18191d41eac0a551b3009269a259757ca070.zip
chromium_src-3b1c18191d41eac0a551b3009269a259757ca070.tar.gz
chromium_src-3b1c18191d41eac0a551b3009269a259757ca070.tar.bz2
Implements the auto-translate on click: if you have translated
a page and are navigating to a new page in the same language by clicking a link, the new page is automatically translated. In order to do that I moved the language state from the navigation entry to some dedicated class that each TabContents owns. Also added some basic unit-testing for good measure. BUG=35477 TEST=See bug steps. Run unit-tests. Review URL: http://codereview.chromium.org/596092 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38961 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/browser_browsertest.cc12
-rw-r--r--chrome/browser/extensions/extension_tabs_module.cc17
-rw-r--r--chrome/browser/renderer_host/test/test_render_view_host.h4
-rw-r--r--chrome/browser/tab_contents/language_state.cc51
-rw-r--r--chrome/browser/tab_contents/language_state.h84
-rw-r--r--chrome/browser/tab_contents/navigation_entry.h10
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc15
-rw-r--r--chrome/browser/tab_contents/tab_contents.h8
-rw-r--r--chrome/browser/translate/translate_manager.cc36
-rw-r--r--chrome/browser/translate/translate_manager.h9
-rw-r--r--chrome/browser/translate/translate_manager_unittest.cc142
-rwxr-xr-xchrome/chrome_browser.gypi2
-rwxr-xr-xchrome/chrome_tests.gypi1
13 files changed, 328 insertions, 63 deletions
diff --git a/chrome/browser/browser_browsertest.cc b/chrome/browser/browser_browsertest.cc
index fcd063d..edce8e0 100644
--- a/chrome/browser/browser_browsertest.cc
+++ b/chrome/browser/browser_browsertest.cc
@@ -457,20 +457,16 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, PageLanguageDetection) {
// Navigate to a page in English.
ui_test_utils::NavigateToURL(
browser(), GURL(server->TestServerPage("files/english_page.html")));
- NavigationEntry* entry = current_tab->controller().GetActiveEntry();
- ASSERT_TRUE(NULL != entry);
- EXPECT_TRUE(entry->language().empty());
+ EXPECT_TRUE(current_tab->language_state().original_language().empty());
std::string lang = ui_test_utils::WaitForLanguageDetection(current_tab);
EXPECT_EQ("en", lang);
- EXPECT_EQ("en", entry->language());
+ EXPECT_EQ("en", current_tab->language_state().original_language());
// Now navigate to a page in French.
ui_test_utils::NavigateToURL(
browser(), GURL(server->TestServerPage("files/french_page.html")));
- entry = current_tab->controller().GetActiveEntry();
- ASSERT_TRUE(NULL != entry);
- EXPECT_TRUE(entry->language().empty());
+ EXPECT_TRUE(current_tab->language_state().original_language().empty());
lang = ui_test_utils::WaitForLanguageDetection(current_tab);
EXPECT_EQ("fr", lang);
- EXPECT_EQ("fr", entry->language());
+ EXPECT_EQ("fr", current_tab->language_state().original_language());
}
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index f85f054..14621bf 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -883,16 +883,13 @@ bool DetectTabLanguageFunction::RunImpl() {
AddRef(); // Balanced in GotLanguage()
- NavigationEntry* entry = contents->controller().GetActiveEntry();
- if (entry) {
- std::string language = entry->language();
- if (!language.empty()) {
- // Delay the callback invocation until after the current JS call has
- // returned.
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &DetectTabLanguageFunction::GotLanguage, language));
- return true;
- }
+ if (!contents->language_state().original_language().empty()) {
+ // Delay the callback invocation until after the current JS call has
+ // returned.
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &DetectTabLanguageFunction::GotLanguage,
+ contents->language_state().original_language()));
+ return true;
}
// The tab contents does not know its language yet. Let's wait until it
// receives it, or until the tab is closed/navigates to some other page.
diff --git a/chrome/browser/renderer_host/test/test_render_view_host.h b/chrome/browser/renderer_host/test/test_render_view_host.h
index 85e6eca..d2cac6e 100644
--- a/chrome/browser/renderer_host/test/test_render_view_host.h
+++ b/chrome/browser/renderer_host/test/test_render_view_host.h
@@ -246,8 +246,8 @@ class RenderViewHostTestHarness : public testing::Test {
contents_.reset();
}
- // Creates a pending navigation to the given oURL with the default parameters
- // and the commits the load with a page ID one larger than any seen. This
+ // Creates a pending navigation to the given URL with the default parameters
+ // and then commits the load with a page ID one larger than any seen. This
// emulates what happens on a new navigation.
void NavigateAndCommit(const GURL& url);
diff --git a/chrome/browser/tab_contents/language_state.cc b/chrome/browser/tab_contents/language_state.cc
new file mode 100644
index 0000000..8522ed3
--- /dev/null
+++ b/chrome/browser/tab_contents/language_state.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/tab_contents/language_state.h"
+
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/navigation_entry.h"
+
+LanguageState::LanguageState(NavigationController* nav_controller)
+ : navigation_controller_(nav_controller),
+ translation_pending_(false) {
+}
+
+LanguageState::~LanguageState() {
+}
+
+void LanguageState::DidNavigate() {
+ prev_original_lang_ = original_lang_;
+ prev_current_lang_ = current_lang_;
+
+ original_lang_.clear();
+ current_lang_.clear();
+
+ translation_pending_ = false;
+}
+
+void LanguageState::LanguageDetermined(const std::string& page_language) {
+ original_lang_ = page_language;
+ current_lang_ = page_language;
+}
+
+std::string LanguageState::AutoTranslateTo() const {
+ // Only auto-translate if:
+ // - no translation is pending
+ // - this page is in the same language as the previous page
+ // - the previous page had been translated
+ // - this page is not already translated
+ // - the new page was navigated through a link.
+ if (!translation_pending_ &&
+ prev_original_lang_ == original_lang_ &&
+ prev_original_lang_ != prev_current_lang_ &&
+ original_lang_ == current_lang_ &&
+ navigation_controller_->GetActiveEntry() &&
+ navigation_controller_->GetActiveEntry()->transition_type() ==
+ PageTransition::LINK) {
+ return prev_current_lang_;
+ }
+
+ return std::string();
+}
diff --git a/chrome/browser/tab_contents/language_state.h b/chrome/browser/tab_contents/language_state.h
new file mode 100644
index 0000000..d5c7df6
--- /dev/null
+++ b/chrome/browser/tab_contents/language_state.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TAB_CONTENTS_LANGUAGE_STATE_H_
+#define CHROME_BROWSER_TAB_CONTENTS_LANGUAGE_STATE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+class NavigationController;
+
+// This class holds the language state of the current page.
+// There is one LanguageState instance per TabContents.
+// It is used to determine when navigating to a new page whether it should
+// automatically be translated.
+// This auto-translate behavior is the expected behavior when:
+// - user is on page in language A that they had translated to language B.
+// - user clicks a link in that page that takes them to a page also in language
+// A.
+
+class LanguageState {
+ public:
+ explicit LanguageState(NavigationController* nav_controller);
+ ~LanguageState();
+
+ // Should be called when the page did a new navigation (whether it is a main
+ // frame or sub-frame navigation).
+ void DidNavigate();
+
+ // Should be called when the language of the page has been determined.
+ void LanguageDetermined(const std::string& page_language);
+
+ // Returns the language the current page should be translated to, based on the
+ // previous page languages and the transition. This should be called after
+ // the language page has been determined.
+ // Returns an empty string if the page should not be auto-translated.
+ std::string AutoTranslateTo() const;
+
+ // Returns true if the current page in the associated tab has been translated.
+ bool IsPageTranslated() const { return original_lang_ != current_lang_; }
+
+ const std::string& original_language() const { return original_lang_; }
+
+ void set_current_language(const std::string& language) {
+ current_lang_ = language;
+ }
+ const std::string& current_language() const { return current_lang_; }
+
+ // Whether the page is currently in the process of being translated.
+ bool translation_pending() const { return translation_pending_; }
+ void set_translation_pending(bool value) { translation_pending_ = value; }
+
+ private:
+ // The languages this page is in. Note that current_lang_ is different from
+ // original_lang_ when the page has been translated.
+ // Note that these might be empty if the page language has not been determined
+ // yet.
+ std::string original_lang_;
+ std::string current_lang_;
+
+ // Same as above but for the previous page.
+ std::string prev_original_lang_;
+ std::string prev_current_lang_;
+
+ // The navigation controller of the tab we are associated with.
+ NavigationController* navigation_controller_;
+
+ // Whether a translation is currently pending (TabContents waiting for the
+ // PAGE_TRANSLATED notification). This is needed to avoid sending duplicate
+ // translate requests to a page. TranslateManager initiates translations
+ // when it received the LANGUAGE_DETERMINED notification. This is sent by
+ // the renderer with the page contents, every time the load stops for the
+ // main frame, so we may get several.
+ // TODO(jcampan): make the renderer send the language just once per navigation
+ // then we can get rid of that state.
+ bool translation_pending_;
+
+ DISALLOW_COPY_AND_ASSIGN(LanguageState);
+};
+
+#endif // CHROME_BROWSER_TAB_CONTENTS_LANGUAGE_STATE_H_
+
diff --git a/chrome/browser/tab_contents/navigation_entry.h b/chrome/browser/tab_contents/navigation_entry.h
index df6ad06..e679c10 100644
--- a/chrome/browser/tab_contents/navigation_entry.h
+++ b/chrome/browser/tab_contents/navigation_entry.h
@@ -389,15 +389,6 @@ class NavigationEntry {
return restore_type_;
}
- // The ISO 639-1 language code (ex: en, fr, zh...) for the page.
- // Can be empty if the language was not detected yet or is unknown.
- void set_language(const std::string& language) {
- language_ = language;
- }
- std::string language() const {
- return language_;
- }
-
private:
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
// Session/Tab restore save portions of this class so that it can be recreated
@@ -422,7 +413,6 @@ class NavigationEntry {
GURL user_typed_url_;
bool has_post_data_;
RestoreType restore_type_;
- std::string language_; // ISO 639-1 language code.
// This is a cached version of the result of GetTitleForDisplay. It prevents
// us from having to do URL formatting on the URL evey time the title is
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index 2f0dcd9..ed15084 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -269,7 +269,8 @@ TabContents::TabContents(Profile* profile,
is_showing_before_unload_dialog_(false),
renderer_preferences_(),
opener_dom_ui_type_(DOMUIFactory::kNoDOMUI),
- app_extension_(NULL) {
+ app_extension_(NULL),
+ language_state_(&controller_) {
ClearBlockedContentSettings();
renderer_preferences_util::UpdateFromSystemSettings(
&renderer_preferences_, profile);
@@ -811,6 +812,7 @@ void TabContents::TranslatePage(const std::string& source_lang,
NOTREACHED();
return;
}
+ language_state_.set_translation_pending(true);
render_view_host()->TranslatePage(entry->page_id(), source_lang, target_lang);
}
@@ -1503,6 +1505,9 @@ void TabContents::DidNavigateAnyFramePostCommit(
// cleaned up and covered by tests.
if (params.password_form.origin.is_valid())
GetPasswordManager()->ProvisionallySavePassword(params.password_form);
+
+ // Let the LanguageState clear its state.
+ language_state_.DidNavigate();
}
void TabContents::CloseConstrainedWindows() {
@@ -1860,11 +1865,7 @@ void TabContents::OnPageContents(const GURL& url,
}
}
- NavigationEntry* entry = controller_.GetActiveEntry();
- if (GetRenderProcessHost()->id() == renderer_process_id &&
- entry && entry->page_id() == page_id) {
- entry->set_language(language);
- }
+ language_state_.LanguageDetermined(language);
std::string lang = language;
NotificationService::current()->Notify(
@@ -1876,6 +1877,8 @@ void TabContents::OnPageContents(const GURL& url,
void TabContents::OnPageTranslated(int32 page_id,
const std::string& original_lang,
const std::string& translated_lang) {
+ language_state_.set_current_language(translated_lang);
+ language_state_.set_translation_pending(false);
std::pair<std::string, std::string> lang_pair =
std::make_pair(original_lang, translated_lang);
NotificationService::current()->Notify(
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index 2c7e5be..4d11745 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -30,6 +30,7 @@
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/tab_contents/constrained_window.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
+#include "chrome/browser/tab_contents/language_state.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/page_navigator.h"
@@ -639,6 +640,10 @@ class TabContents : public PageNavigator,
return request_context_;
}
+ LanguageState& language_state() {
+ return language_state_;
+ }
+
// Creates a duplicate of this TabContents. The returned TabContents is
// configured such that the renderer has not been loaded (it'll load the first
// time it is selected).
@@ -1180,6 +1185,9 @@ class TabContents : public PageNavigator,
// created for.
Extension* app_extension_;
+ // Information about the language the page is in and has been translated to.
+ LanguageState language_state_;
+
// ---------------------------------------------------------------------------
DISALLOW_COPY_AND_ASSIGN(TabContents);
diff --git a/chrome/browser/translate/translate_manager.cc b/chrome/browser/translate/translate_manager.cc
index 5f24cb6..773c066 100644
--- a/chrome/browser/translate/translate_manager.cc
+++ b/chrome/browser/translate/translate_manager.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/translation_service.h"
+#include "chrome/browser/tab_contents/language_state.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -27,22 +28,13 @@ void TranslateManager::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
switch (type.value) {
- case NotificationType::NAV_ENTRY_COMMITTED: {
- // We have navigated to a new page.
- NavigationController* controller =
- Source<NavigationController>(source).ptr();
- NavigationEntry* entry = controller->GetActiveEntry();
- if (!entry->language().empty()) {
- // The language for that page is known (it must be a back/forward
- // navigation to a page we already visited).
- InitiateTranslation(controller->tab_contents(), entry->language());
- }
- break;
- }
case NotificationType::TAB_LANGUAGE_DETERMINED: {
TabContents* tab = Source<TabContents>(source).ptr();
std::string language = *(Details<std::string>(details).ptr());
- InitiateTranslation(tab, language);
+ // We may get this notifications multiple times. Make sure to translate
+ // only once.
+ if (!tab->language_state().translation_pending())
+ InitiateTranslation(tab, language);
break;
}
case NotificationType::PAGE_TRANSLATED: {
@@ -91,11 +83,9 @@ void TranslateManager::Observe(NotificationType type,
}
TranslateManager::TranslateManager() {
- if (!TranslationService::IsTranslationEnabled())
+ if (TestEnabled() && !TranslationService::IsTranslationEnabled())
return;
- notification_registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
- NotificationService::AllSources());
notification_registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED,
NotificationService::AllSources());
notification_registrar_.Add(this, NotificationType::PAGE_TRANSLATED,
@@ -134,15 +124,11 @@ void TranslateManager::InitiateTranslation(TabContents* tab,
return;
}
- // If we already have an "after translate" infobar, it sometimes might be
- // sticky when running in frames. So we need to proactively remove any
- // translate related infobars as they would prevent any new infobar from
- // showing. (As TabContents will not add an infobar if there is already one
- // showing equal to the one being added.)
- for (int i = tab->infobar_delegate_count() - 1; i >= 0; --i) {
- InfoBarDelegate* info_bar = tab->GetInfoBarDelegateAt(i);
- if (info_bar->AsTranslateInfoBarDelegate())
- tab->RemoveInfoBar(info_bar);
+ std::string auto_translate_to = tab->language_state().AutoTranslateTo();
+ if (!auto_translate_to.empty()) {
+ // This page was navigated through a click from a translated page.
+ tab->TranslatePage(page_lang, auto_translate_to);
+ return;
}
// Prompts the user if he/she wants the page translated.
diff --git a/chrome/browser/translate/translate_manager.h b/chrome/browser/translate/translate_manager.h
index b70db4b..e41fb04 100644
--- a/chrome/browser/translate/translate_manager.h
+++ b/chrome/browser/translate/translate_manager.h
@@ -29,11 +29,16 @@ class TranslateManager : public NotificationObserver {
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
- private:
- friend struct DefaultSingletonTraits<TranslateManager>;
+
+ protected:
+ // Overriden by unit-tests to enable the TranslateManager.
+ virtual bool TestEnabled() { return false; }
TranslateManager();
+ private:
+ friend struct DefaultSingletonTraits<TranslateManager>;
+
// Starts the translation process on |tab| containing the page in the
// |page_lang| language.
void InitiateTranslation(TabContents* tab, const std::string& page_lang);
diff --git a/chrome/browser/translate/translate_manager_unittest.cc b/chrome/browser/translate/translate_manager_unittest.cc
new file mode 100644
index 0000000..75420c5
--- /dev/null
+++ b/chrome/browser/translate/translate_manager_unittest.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+
+#include "chrome/browser/renderer_host/mock_render_process_host.h"
+#include "chrome/browser/translate/translate_infobars_delegates.h"
+#include "chrome/browser/translate/translate_manager.h"
+#include "chrome/common/ipc_test_sink.h"
+#include "chrome/common/render_messages.h"
+
+class TestTranslateManager : public TranslateManager {
+ public:
+ TestTranslateManager() {}
+
+ protected:
+ virtual bool TestEnabled() { return true; }
+};
+
+class TranslateManagerTest : public RenderViewHostTestHarness {
+ public:
+ // Simluates navigating to a page and getting teh page contents and language
+ // for that navigation.
+ void SimulateNavigation(const GURL& url, int page_id,
+ const std::wstring& contents,
+ const std::string& lang) {
+ NavigateAndCommit(url);
+ rvh()->TestOnMessageReceived(ViewHostMsg_PageContents(0, url, page_id,
+ contents, lang));
+ }
+
+ bool GetTranslateMessage(int* page_id,
+ std::string* original_lang,
+ std::string* target_lang) {
+ const IPC::Message* message =
+ process()->sink().GetFirstMessageMatching(ViewMsg_TranslatePage::ID);
+ if (!message)
+ return false;
+ Tuple3<int, std::string, std::string> translate_param;
+ ViewMsg_TranslatePage::Read(message, &translate_param);
+ *page_id = translate_param.a;
+ *original_lang = translate_param.b;
+ *target_lang = translate_param.c;
+ return true;
+ }
+
+ private:
+ TestTranslateManager translate_manager_;
+};
+
+TEST_F(TranslateManagerTest, NormalTranslate) {
+ // Simulate navigating to a page.
+ SimulateNavigation(GURL("http://www.google.fr"), 0, L"Le Google", "fr");
+
+ // We should have an info-bar.
+ ASSERT_EQ(1, contents()->infobar_delegate_count());
+ TranslateInfoBarDelegate* infobar =
+ contents()->GetInfoBarDelegateAt(0)->AsTranslateInfoBarDelegate();
+ ASSERT_TRUE(infobar != NULL);
+ EXPECT_EQ(TranslateInfoBarDelegate::kBeforeTranslate, infobar->state());
+
+ // Simulate clicking translate.
+ process()->sink().ClearMessages();
+ infobar->Translate();
+
+ // Test that we sent the right message to the renderer.
+ int page_id = 0;
+ std::string original_lang, target_lang;
+ EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
+ EXPECT_EQ(0, page_id);
+ EXPECT_EQ("fr", original_lang);
+ EXPECT_EQ("en", target_lang);
+
+ // The infobar should now be in the translating state.
+ ASSERT_EQ(1, contents()->infobar_delegate_count());
+ ASSERT_EQ(infobar, contents()->GetInfoBarDelegateAt(0)); // Same instance.
+ // TODO(jcampan): the state is not set if the button is not clicked.
+ // Refactor the infobar code so we can simulate the click.
+ // EXPECT_EQ(TranslateInfoBarDelegate::kTranslating, infobar->state());
+
+ // Simulate the render notifying the translation has been done.
+ rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en"));
+
+ // The infobar should have changed to the after state.
+ ASSERT_EQ(1, contents()->infobar_delegate_count());
+ ASSERT_EQ(infobar, contents()->GetInfoBarDelegateAt(0));
+ // TODO(jcampan): the TranslateInfoBar is listening for the PAGE_TRANSLATED
+ // notification. Since in unit-test, no actual info-bar is
+ // created, it does not get the notification and does not
+ // update its state. Ideally the delegate (or rather model)
+ // would be the one listening for notifications and updating
+ // states. That would make this test work.
+ // EXPECT_EQ(TranslateInfoBarDelegate::kAfterTranslate, infobar->state());
+
+ // Simulate translating again from there but 2 different languages.
+ infobar->ModifyOriginalLanguage(0);
+ infobar->ModifyTargetLanguage(1);
+ std::string new_original_lang = infobar->original_lang_code();
+ std::string new_target_lang = infobar->target_lang_code();
+ process()->sink().ClearMessages();
+ infobar->Translate();
+
+ // Test that we sent the right message to the renderer.
+ EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
+ EXPECT_EQ(0, page_id);
+ EXPECT_EQ(new_original_lang, original_lang);
+ EXPECT_EQ(new_target_lang, target_lang);
+}
+
+// Test auto-translate on page.
+TEST_F(TranslateManagerTest, AutoTranslateOnNavigate) {
+ // Simulate navigating to a page and gettings its language.
+ SimulateNavigation(GURL("http://www.google.fr"), 0, L"Le Google", "fr");
+
+ // Simulate the user translating.
+ ASSERT_EQ(1, contents()->infobar_delegate_count());
+ TranslateInfoBarDelegate* infobar =
+ contents()->GetInfoBarDelegateAt(0)->AsTranslateInfoBarDelegate();
+ ASSERT_TRUE(infobar != NULL);
+ infobar->Translate();
+ rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en"));
+
+ // Now navigate to a new page in the same language.
+ process()->sink().ClearMessages();
+ SimulateNavigation(GURL("http://news.google.fr"), 1, L"Les news", "fr");
+
+ // This should have automatically triggered a translation.
+ int page_id = 0;
+ std::string original_lang, target_lang;
+ EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
+ EXPECT_EQ(1, page_id);
+ EXPECT_EQ("fr", original_lang);
+ EXPECT_EQ("en", target_lang);
+
+ // Now navigate to a page in a different language.
+ process()->sink().ClearMessages();
+ SimulateNavigation(GURL("http://news.google.es"), 1, L"Las news", "es");
+
+ // This should not have triggered a translate.
+ EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
+}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index f9a7af1..567ecc5 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1731,6 +1731,8 @@
'browser/tab_contents/infobar_delegate.h',
'browser/tab_contents/interstitial_page.cc',
'browser/tab_contents/interstitial_page.h',
+ 'browser/tab_contents/language_state.h',
+ 'browser/tab_contents/language_state.cc',
'browser/tab_contents/navigation_controller.cc',
'browser/tab_contents/navigation_controller.h',
'browser/tab_contents/navigation_entry.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index f1c9740..9855d8c 100755
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -826,6 +826,7 @@
'browser/tab_menu_model_unittest.cc',
'browser/tabs/tab_strip_model_unittest.cc',
'browser/task_manager_unittest.cc',
+ 'browser/translate/translate_manager_unittest.cc',
'browser/theme_resources_util_unittest.cc',
'browser/views/bookmark_context_menu_test.cc',
'browser/views/bookmark_editor_view_unittest.cc',