Commit 886af587 authored by Donn Denman's avatar Donn Denman Committed by Commit Bot

[TTS] Detect the content language for translation.

Detects the language of the selection whenever it is set instead of
waiting for the resolve request to return.  This allows the translation
to be done during the Resolve request for the
ContextualSearchTranslations experiment.

Also update the logic for detecting the language.  Try to detect the
language of the selection first, and if that's not reliable then
run the detector on the whole context.

BUG=952401

Change-Id: I17886528f8b4c3468762fb1bcde0c27b234549d0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2029262
Auto-Submit: Donn Denman <donnd@chromium.org>
Commit-Queue: Theresa  <twellington@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Reviewed-by: default avatarJinsuk Kim <jinsukkim@chromium.org>
Cr-Commit-Position: refs/heads/master@{#738566}
parent a5f4b24e
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.contextualsearch; package org.chromium.chrome.browser.contextualsearch;
import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
...@@ -42,6 +43,7 @@ public abstract class ContextualSearchContext { ...@@ -42,6 +43,7 @@ public abstract class ContextualSearchContext {
private int mSelectionEndOffset = INVALID_OFFSET; private int mSelectionEndOffset = INVALID_OFFSET;
// The home country, or an empty string if not set. // The home country, or an empty string if not set.
@NonNull
private String mHomeCountry = ""; private String mHomeCountry = "";
// The detected language of the context, or {@code null} if not yet detected, and empty if // The detected language of the context, or {@code null} if not yet detected, and empty if
...@@ -78,6 +80,10 @@ public abstract class ContextualSearchContext { ...@@ -78,6 +80,10 @@ public abstract class ContextualSearchContext {
private long mPreviousEventId; private long mPreviousEventId;
private int mPreviousUserInteractions; private int mPreviousUserInteractions;
// Translation members.
@NonNull
private String mTargetLanguage = "";
/** A {@link ContextualSearchContext} that ignores changes to the selection. */ /** A {@link ContextualSearchContext} that ignores changes to the selection. */
static class ChangeIgnoringContext extends ContextualSearchContext { static class ChangeIgnoringContext extends ContextualSearchContext {
@Override @Override
...@@ -106,7 +112,7 @@ public abstract class ContextualSearchContext { ...@@ -106,7 +112,7 @@ public abstract class ContextualSearchContext {
if (context.hasValidSelection() && !TextUtils.isEmpty(context.getInitialSelectedWord())) { if (context.hasValidSelection() && !TextUtils.isEmpty(context.getInitialSelectedWord())) {
Log.i(TAG, "identified default query: " + context.getWordTapped()); Log.i(TAG, "identified default query: " + context.getWordTapped());
// TODO(donnd): figure out which of these parameters should be passed in. // TODO(donnd): figure out which of these parameters should be passed in.
context.setResolveProperties("US", true, 0, 0); context.setResolveProperties("US", true, 0, 0, "");
return context; return context;
} }
...@@ -130,16 +136,18 @@ public abstract class ContextualSearchContext { ...@@ -130,16 +136,18 @@ public abstract class ContextualSearchContext {
* @param maySendBasePageUrl Whether policy allows sending the base-page URL to the server. * @param maySendBasePageUrl Whether policy allows sending the base-page URL to the server.
* @param previousEventId An EventID from the server to send along with the resolve request. * @param previousEventId An EventID from the server to send along with the resolve request.
* @param previousUserInteractions Persisted interaction outcomes to send along with the resolve * @param previousUserInteractions Persisted interaction outcomes to send along with the resolve
* request. * request.
* @param targetLanguage The language to translate into, in case translation might be needed.
*/ */
void setResolveProperties(String homeCountry, boolean maySendBasePageUrl, long previousEventId, void setResolveProperties(@NonNull String homeCountry, boolean maySendBasePageUrl,
int previousUserInteractions) { long previousEventId, int previousUserInteractions, @NonNull String targetLanguage) {
mHasSetResolveProperties = true; mHasSetResolveProperties = true;
mHomeCountry = homeCountry; mHomeCountry = homeCountry;
mPreviousEventId = previousEventId; mPreviousEventId = previousEventId;
mPreviousUserInteractions = previousUserInteractions; mPreviousUserInteractions = previousUserInteractions;
ContextualSearchContextJni.get().setResolveProperties(getNativePointer(), this, homeCountry, ContextualSearchContextJni.get().setResolveProperties(getNativePointer(), this, homeCountry,
maySendBasePageUrl, previousEventId, previousUserInteractions); maySendBasePageUrl, previousEventId, previousUserInteractions);
mTargetLanguage = targetLanguage;
} }
/** /**
...@@ -196,6 +204,8 @@ public abstract class ContextualSearchContext { ...@@ -196,6 +204,8 @@ public abstract class ContextualSearchContext {
ContextualSearchContextJni.get().setContent(getNativePointer(), this, mSurroundingText, ContextualSearchContextJni.get().setContent(getNativePointer(), this, mSurroundingText,
mSelectionStartOffset, mSelectionEndOffset); mSelectionStartOffset, mSelectionEndOffset);
} }
// Detect the language of the surroundings or the selection.
setTranslationLanguages(getDetectedLanguage(), mTargetLanguage);
} }
/** /**
...@@ -346,6 +356,16 @@ public abstract class ContextualSearchContext { ...@@ -346,6 +356,16 @@ public abstract class ContextualSearchContext {
return mDetectedLanguage; return mDetectedLanguage;
} }
/**
* Pushes the given language down to the native ContextualSearchContext.
* @param detectedLanguage An ISO 639 language code string for the language to translate from.
* @param targetLanguage An ISO 639 language code string to translation into.
*/
void setTranslationLanguages(String detectedLanguage, String targetLanguage) {
ContextualSearchContextJni.get().setTranslationLanguages(
mNativePointer, this, detectedLanguage, targetLanguage);
}
// ============================================================================================ // ============================================================================================
// Content Analysis. // Content Analysis.
// ============================================================================================ // ============================================================================================
...@@ -580,6 +600,8 @@ public abstract class ContextualSearchContext { ...@@ -580,6 +600,8 @@ public abstract class ContextualSearchContext {
void setContent(long nativeContextualSearchContext, ContextualSearchContext caller, void setContent(long nativeContextualSearchContext, ContextualSearchContext caller,
String content, int selectionStart, int selectionEnd); String content, int selectionStart, int selectionEnd);
String detectLanguage(long nativeContextualSearchContext, ContextualSearchContext caller); String detectLanguage(long nativeContextualSearchContext, ContextualSearchContext caller);
void setTranslationLanguages(long nativeContextualSearchContext,
ContextualSearchContext caller, String detectedLanguage, String targetLanguage);
void setExactResolve(long nativeContextualSearchContext, ContextualSearchContext caller); void setExactResolve(long nativeContextualSearchContext, ContextualSearchContext caller);
} }
} }
...@@ -1570,9 +1570,12 @@ public class ContextualSearchManager implements ContextualSearchManagementDelega ...@@ -1570,9 +1570,12 @@ public class ContextualSearchManager implements ContextualSearchManagementDelega
ContextualSearchInteractionPersister.PersistedInteraction interaction = ContextualSearchInteractionPersister.PersistedInteraction interaction =
mInteractionRecorder.getInteractionPersister() mInteractionRecorder.getInteractionPersister()
.getAndClearPersistedInteraction(); .getAndClearPersistedInteraction();
String targetLanguage =
mTranslateController.getTranslateServiceTargetLanguage();
targetLanguage = targetLanguage != null ? targetLanguage : "";
mContext.setResolveProperties(mPolicy.getHomeCountry(mActivity), mContext.setResolveProperties(mPolicy.getHomeCountry(mActivity),
mPolicy.maySendBasePageUrl(), interaction.getEventId(), mPolicy.maySendBasePageUrl(), interaction.getEventId(),
interaction.getEncodedUserInteractions()); interaction.getEncodedUserInteractions(), targetLanguage);
} }
WebContents webContents = getBaseWebContents(); WebContents webContents = getBaseWebContents();
if (webContents != null) { if (webContents != null) {
......
...@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.contextualsearch; ...@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.contextualsearch;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.NonNull;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.format.DateUtils; import android.text.format.DateUtils;
...@@ -451,6 +452,7 @@ class ContextualSearchPolicy { ...@@ -451,6 +452,7 @@ class ContextualSearchPolicy {
* @return The ISO country code for the user's home country, or an empty string if not * @return The ISO country code for the user's home country, or an empty string if not
* available or privacy-enabled. * available or privacy-enabled.
*/ */
@NonNull
String getHomeCountry(Context context) { String getHomeCountry(Context context) {
if (ContextualSearchFieldTrial.getSwitch( if (ContextualSearchFieldTrial.getSwitch(
ContextualSearchSwitch.IS_SEND_HOME_COUNTRY_DISABLED)) { ContextualSearchSwitch.IS_SEND_HOME_COUNTRY_DISABLED)) {
......
...@@ -81,13 +81,13 @@ public class ContextualSearchContextTest { ...@@ -81,13 +81,13 @@ public class ContextualSearchContextTest {
private void setupResolvingTapInBarak() { private void setupResolvingTapInBarak() {
setupTapInBarack(); setupTapInBarack();
mContext.setResolveProperties(HOME_COUNTRY, true, 0, 0); mContext.setResolveProperties(HOME_COUNTRY, true, 0, 0, "");
} }
private void setupResolvingTapInObama() { private void setupResolvingTapInObama() {
int obamaBeforeMOffset = "Now Barack Oba".length(); int obamaBeforeMOffset = "Now Barack Oba".length();
mContext.setSurroundingText(UTF_8, SAMPLE_TEXT, obamaBeforeMOffset, obamaBeforeMOffset); mContext.setSurroundingText(UTF_8, SAMPLE_TEXT, obamaBeforeMOffset, obamaBeforeMOffset);
mContext.setResolveProperties(HOME_COUNTRY, true, 0, 0); mContext.setResolveProperties(HOME_COUNTRY, true, 0, 0, "");
} }
@Test @Test
......
...@@ -18,11 +18,11 @@ ContextualSearchContext::ContextualSearchContext( ...@@ -18,11 +18,11 @@ ContextualSearchContext::ContextualSearchContext(
const std::string& home_country, const std::string& home_country,
const GURL& page_url, const GURL& page_url,
const std::string& encoding) const std::string& encoding)
: can_resolve(true), : can_resolve_(true),
can_send_base_page_url(true), can_send_base_page_url_(true),
home_country(home_country), home_country_(home_country),
base_page_url(page_url), base_page_url_(page_url),
base_page_encoding(encoding) { base_page_encoding_(encoding) {
java_object_ = nullptr; java_object_ = nullptr;
} }
...@@ -52,11 +52,11 @@ void ContextualSearchContext::SetResolveProperties( ...@@ -52,11 +52,11 @@ void ContextualSearchContext::SetResolveProperties(
jboolean j_may_send_base_page_url, jboolean j_may_send_base_page_url,
jlong j_previous_event_id, jlong j_previous_event_id,
jint j_previous_event_results) { jint j_previous_event_results) {
can_resolve = true; can_resolve_ = true;
home_country = base::android::ConvertJavaStringToUTF8(env, j_home_country); home_country_ = base::android::ConvertJavaStringToUTF8(env, j_home_country);
can_send_base_page_url = j_may_send_base_page_url; can_send_base_page_url_ = j_may_send_base_page_url;
previous_event_id = j_previous_event_id; previous_event_id_ = j_previous_event_id;
previous_event_results = j_previous_event_results; previous_event_results_ = j_previous_event_results;
} }
void ContextualSearchContext::SetContent( void ContextualSearchContext::SetContent(
...@@ -74,103 +74,138 @@ void ContextualSearchContext::AdjustSelection(JNIEnv* env, ...@@ -74,103 +74,138 @@ void ContextualSearchContext::AdjustSelection(JNIEnv* env,
jobject obj, jobject obj,
jint j_start_adjust, jint j_start_adjust,
jint j_end_adjust) { jint j_end_adjust) {
DCHECK(start_offset + j_start_adjust >= 0); DCHECK(start_offset_ + j_start_adjust >= 0);
DCHECK(start_offset + j_start_adjust <= (int)surrounding_text.length()); DCHECK(start_offset_ + j_start_adjust <= (int)surrounding_text_.length());
DCHECK(end_offset + j_end_adjust >= 0); DCHECK(end_offset_ + j_end_adjust >= 0);
DCHECK(end_offset + j_end_adjust <= (int)surrounding_text.length()); DCHECK(end_offset_ + j_end_adjust <= (int)surrounding_text_.length());
start_offset += j_start_adjust; start_offset_ += j_start_adjust;
end_offset += j_end_adjust; end_offset_ += j_end_adjust;
} }
// Accessors // Accessors
bool ContextualSearchContext::CanResolve() const { bool ContextualSearchContext::CanResolve() const {
return can_resolve; return can_resolve_;
} }
bool ContextualSearchContext::CanSendBasePageUrl() const { bool ContextualSearchContext::CanSendBasePageUrl() const {
return can_send_base_page_url; return can_send_base_page_url_;
} }
const GURL ContextualSearchContext::GetBasePageUrl() const { const GURL ContextualSearchContext::GetBasePageUrl() const {
return base_page_url; return base_page_url_;
} }
void ContextualSearchContext::SetBasePageUrl(const GURL& base_page_url) { void ContextualSearchContext::SetBasePageUrl(const GURL& base_page_url) {
this->base_page_url = base_page_url; this->base_page_url_ = base_page_url;
} }
const std::string ContextualSearchContext::GetBasePageEncoding() const { const std::string ContextualSearchContext::GetBasePageEncoding() const {
return base_page_encoding; return base_page_encoding_;
} }
void ContextualSearchContext::SetBasePageEncoding( void ContextualSearchContext::SetBasePageEncoding(
const std::string& base_page_encoding) { const std::string& base_page_encoding) {
this->base_page_encoding = base_page_encoding; this->base_page_encoding_ = base_page_encoding;
} }
const std::string ContextualSearchContext::GetHomeCountry() const { const std::string ContextualSearchContext::GetHomeCountry() const {
return home_country; return home_country_;
} }
int64_t ContextualSearchContext::GetPreviousEventId() const { int64_t ContextualSearchContext::GetPreviousEventId() const {
return previous_event_id; return previous_event_id_;
} }
int ContextualSearchContext::GetPreviousEventResults() const { int ContextualSearchContext::GetPreviousEventResults() const {
return previous_event_results; return previous_event_results_;
} }
void ContextualSearchContext::SetSelectionSurroundings( void ContextualSearchContext::SetSelectionSurroundings(
int start_offset, int start_offset,
int end_offset, int end_offset,
const base::string16& surrounding_text) { const base::string16& surrounding_text) {
this->start_offset = start_offset; this->start_offset_ = start_offset;
this->end_offset = end_offset; this->end_offset_ = end_offset;
this->surrounding_text = surrounding_text; this->surrounding_text_ = surrounding_text;
} }
const base::string16 ContextualSearchContext::GetSurroundingText() const { const base::string16 ContextualSearchContext::GetSurroundingText() const {
return surrounding_text; return surrounding_text_;
} }
int ContextualSearchContext::GetStartOffset() const { int ContextualSearchContext::GetStartOffset() const {
return start_offset; return start_offset_;
} }
int ContextualSearchContext::GetEndOffset() const { int ContextualSearchContext::GetEndOffset() const {
return end_offset; return end_offset_;
} }
void ContextualSearchContext::SetExactResolve( void ContextualSearchContext::SetExactResolve(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) { const base::android::JavaParamRef<jobject>& obj) {
is_exact_resolve = true; is_exact_resolve_ = true;
} }
bool ContextualSearchContext::GetExactResolve() { bool ContextualSearchContext::GetExactResolve() {
return is_exact_resolve; return is_exact_resolve_;
} }
base::android::ScopedJavaLocalRef<jstring> base::android::ScopedJavaLocalRef<jstring>
ContextualSearchContext::DetectLanguage( ContextualSearchContext::DetectLanguage(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) { const base::android::JavaParamRef<jobject>& obj) {
std::string language = GetReliableLanguage(GetSelection());
if (language.empty())
language = GetReliableLanguage(this->surrounding_text_);
base::android::ScopedJavaLocalRef<jstring> j_language =
base::android::ConvertUTF8ToJavaString(env, language);
return j_language;
}
void ContextualSearchContext::SetTranslationLanguages(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<jstring>& j_detected_language,
const base::android::JavaParamRef<jstring>& j_target_language) {
translation_languages_.detected_language =
base::android::ConvertJavaStringToUTF8(env, j_detected_language);
translation_languages_.target_language =
base::android::ConvertJavaStringToUTF8(env, j_target_language);
}
const ContextualSearchContext::TranslationLanguages&
ContextualSearchContext::GetTranslationLanguages() {
return translation_languages_;
}
std::string ContextualSearchContext::GetReliableLanguage(
const base::string16& contents) {
std::string content_language; std::string content_language;
std::string html_lang; std::string html_lang;
std::string cld_language; std::string cld_language;
bool is_cld_reliable; bool is_cld_reliable;
std::string language = translate::DeterminePageLanguage( std::string language = translate::DeterminePageLanguage(
content_language, html_lang, this->surrounding_text, &cld_language, content_language, html_lang, contents, &cld_language, &is_cld_reliable);
&is_cld_reliable);
// Make sure we return an empty string when unreliable or an unknown result. // Make sure we return an empty string when unreliable or an unknown result.
if (!is_cld_reliable || language == translate::kUnknownLanguageCode) if (!is_cld_reliable || language == translate::kUnknownLanguageCode)
language = ""; language = "";
base::android::ScopedJavaLocalRef<jstring> j_language = return language;
base::android::ConvertUTF8ToJavaString(env, language); }
return j_language;
base::string16 ContextualSearchContext::GetSelection() {
int start = this->start_offset_;
int end = this->end_offset_;
DCHECK(start >= 0);
DCHECK(end >= 0);
DCHECK(end <= (int)this->surrounding_text_.length());
DCHECK(start <= end);
return this->surrounding_text_.substr(start, end - start);
} }
// Boilerplate.
base::WeakPtr<ContextualSearchContext> ContextualSearchContext::GetWeakPtr() { base::WeakPtr<ContextualSearchContext> ContextualSearchContext::GetWeakPtr() {
return weak_factory_.GetWeakPtr(); return weak_factory_.GetWeakPtr();
} }
......
...@@ -16,6 +16,12 @@ ...@@ -16,6 +16,12 @@
// text. // text.
struct ContextualSearchContext { struct ContextualSearchContext {
public: public:
// Languages needed for translation.
struct TranslationLanguages {
std::string detected_language;
std::string target_language;
};
ContextualSearchContext(JNIEnv* env, jobject obj); ContextualSearchContext(JNIEnv* env, jobject obj);
// Constructor for tests. // Constructor for tests.
ContextualSearchContext(const std::string& home_country, ContextualSearchContext(const std::string& home_country,
...@@ -106,22 +112,41 @@ struct ContextualSearchContext { ...@@ -106,22 +112,41 @@ struct ContextualSearchContext {
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj); const base::android::JavaParamRef<jobject>& obj);
// Sets the languages to remember for use in translation.
// See |GetTranslationLanguages|.
void SetTranslationLanguages(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<jstring>& j_detected_language,
const base::android::JavaParamRef<jstring>& j_target_language);
// Returns the languages to use for translation, as set by
// |SetTranslationLanguages|.
const TranslationLanguages& GetTranslationLanguages();
// Gets a WeakPtr to this instance. // Gets a WeakPtr to this instance.
base::WeakPtr<ContextualSearchContext> GetWeakPtr(); base::WeakPtr<ContextualSearchContext> GetWeakPtr();
private: private:
bool can_resolve = false; // Gets the reliable language of the given |contents| using CLD, or an empty
bool can_send_base_page_url = false; // string if none can reliably be determined.
std::string GetReliableLanguage(const base::string16& contents);
std::string home_country;
GURL base_page_url; // Gets the selection, or an empty string if none.
std::string base_page_encoding; base::string16 GetSelection();
base::string16 surrounding_text;
int start_offset = 0; bool can_resolve_ = false;
int end_offset = 0; bool can_send_base_page_url_ = false;
int64_t previous_event_id = 0L; std::string home_country_;
int previous_event_results = 0; GURL base_page_url_;
bool is_exact_resolve = false; std::string base_page_encoding_;
base::string16 surrounding_text_;
int start_offset_ = 0;
int end_offset_ = 0;
int64_t previous_event_id_ = 0L;
int previous_event_results_ = 0;
bool is_exact_resolve_ = false;
TranslationLanguages translation_languages_;
// The linked Java object. // The linked Java object.
base::android::ScopedJavaGlobalRef<jobject> java_object_; base::android::ScopedJavaGlobalRef<jobject> java_object_;
......
...@@ -294,7 +294,8 @@ std::string ContextualSearchDelegate::BuildRequestUrl( ...@@ -294,7 +294,8 @@ std::string ContextualSearchDelegate::BuildRequestUrl(
kContextualSearchRequestVersion, contextual_cards_version, kContextualSearchRequestVersion, contextual_cards_version,
context->GetHomeCountry(), context->GetPreviousEventId(), context->GetHomeCountry(), context->GetPreviousEventId(),
context->GetPreviousEventResults(), context->GetExactResolve(), context->GetPreviousEventResults(), context->GetExactResolve(),
std::string(), std::string()); context->GetTranslationLanguages().detected_language,
context->GetTranslationLanguages().target_language);
search_terms_args.contextual_search_params = params; search_terms_args.contextual_search_params = params;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment