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 @@
package org.chromium.chrome.browser.contextualsearch;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import androidx.annotation.Nullable;
......@@ -42,6 +43,7 @@ public abstract class ContextualSearchContext {
private int mSelectionEndOffset = INVALID_OFFSET;
// The home country, or an empty string if not set.
@NonNull
private String mHomeCountry = "";
// The detected language of the context, or {@code null} if not yet detected, and empty if
......@@ -78,6 +80,10 @@ public abstract class ContextualSearchContext {
private long mPreviousEventId;
private int mPreviousUserInteractions;
// Translation members.
@NonNull
private String mTargetLanguage = "";
/** A {@link ContextualSearchContext} that ignores changes to the selection. */
static class ChangeIgnoringContext extends ContextualSearchContext {
@Override
......@@ -106,7 +112,7 @@ public abstract class ContextualSearchContext {
if (context.hasValidSelection() && !TextUtils.isEmpty(context.getInitialSelectedWord())) {
Log.i(TAG, "identified default query: " + context.getWordTapped());
// 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;
}
......@@ -130,16 +136,18 @@ public abstract class ContextualSearchContext {
* @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 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,
int previousUserInteractions) {
void setResolveProperties(@NonNull String homeCountry, boolean maySendBasePageUrl,
long previousEventId, int previousUserInteractions, @NonNull String targetLanguage) {
mHasSetResolveProperties = true;
mHomeCountry = homeCountry;
mPreviousEventId = previousEventId;
mPreviousUserInteractions = previousUserInteractions;
ContextualSearchContextJni.get().setResolveProperties(getNativePointer(), this, homeCountry,
maySendBasePageUrl, previousEventId, previousUserInteractions);
mTargetLanguage = targetLanguage;
}
/**
......@@ -196,6 +204,8 @@ public abstract class ContextualSearchContext {
ContextualSearchContextJni.get().setContent(getNativePointer(), this, mSurroundingText,
mSelectionStartOffset, mSelectionEndOffset);
}
// Detect the language of the surroundings or the selection.
setTranslationLanguages(getDetectedLanguage(), mTargetLanguage);
}
/**
......@@ -346,6 +356,16 @@ public abstract class ContextualSearchContext {
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.
// ============================================================================================
......@@ -580,6 +600,8 @@ public abstract class ContextualSearchContext {
void setContent(long nativeContextualSearchContext, ContextualSearchContext caller,
String content, int selectionStart, int selectionEnd);
String detectLanguage(long nativeContextualSearchContext, ContextualSearchContext caller);
void setTranslationLanguages(long nativeContextualSearchContext,
ContextualSearchContext caller, String detectedLanguage, String targetLanguage);
void setExactResolve(long nativeContextualSearchContext, ContextualSearchContext caller);
}
}
......@@ -1570,9 +1570,12 @@ public class ContextualSearchManager implements ContextualSearchManagementDelega
ContextualSearchInteractionPersister.PersistedInteraction interaction =
mInteractionRecorder.getInteractionPersister()
.getAndClearPersistedInteraction();
String targetLanguage =
mTranslateController.getTranslateServiceTargetLanguage();
targetLanguage = targetLanguage != null ? targetLanguage : "";
mContext.setResolveProperties(mPolicy.getHomeCountry(mActivity),
mPolicy.maySendBasePageUrl(), interaction.getEventId(),
interaction.getEncodedUserInteractions());
interaction.getEncodedUserInteractions(), targetLanguage);
}
WebContents webContents = getBaseWebContents();
if (webContents != null) {
......
......@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.contextualsearch;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.format.DateUtils;
......@@ -451,6 +452,7 @@ class ContextualSearchPolicy {
* @return The ISO country code for the user's home country, or an empty string if not
* available or privacy-enabled.
*/
@NonNull
String getHomeCountry(Context context) {
if (ContextualSearchFieldTrial.getSwitch(
ContextualSearchSwitch.IS_SEND_HOME_COUNTRY_DISABLED)) {
......
......@@ -81,13 +81,13 @@ public class ContextualSearchContextTest {
private void setupResolvingTapInBarak() {
setupTapInBarack();
mContext.setResolveProperties(HOME_COUNTRY, true, 0, 0);
mContext.setResolveProperties(HOME_COUNTRY, true, 0, 0, "");
}
private void setupResolvingTapInObama() {
int obamaBeforeMOffset = "Now Barack Oba".length();
mContext.setSurroundingText(UTF_8, SAMPLE_TEXT, obamaBeforeMOffset, obamaBeforeMOffset);
mContext.setResolveProperties(HOME_COUNTRY, true, 0, 0);
mContext.setResolveProperties(HOME_COUNTRY, true, 0, 0, "");
}
@Test
......
......@@ -18,11 +18,11 @@ ContextualSearchContext::ContextualSearchContext(
const std::string& home_country,
const GURL& page_url,
const std::string& encoding)
: can_resolve(true),
can_send_base_page_url(true),
home_country(home_country),
base_page_url(page_url),
base_page_encoding(encoding) {
: can_resolve_(true),
can_send_base_page_url_(true),
home_country_(home_country),
base_page_url_(page_url),
base_page_encoding_(encoding) {
java_object_ = nullptr;
}
......@@ -52,11 +52,11 @@ void ContextualSearchContext::SetResolveProperties(
jboolean j_may_send_base_page_url,
jlong j_previous_event_id,
jint j_previous_event_results) {
can_resolve = true;
home_country = base::android::ConvertJavaStringToUTF8(env, j_home_country);
can_send_base_page_url = j_may_send_base_page_url;
previous_event_id = j_previous_event_id;
previous_event_results = j_previous_event_results;
can_resolve_ = true;
home_country_ = base::android::ConvertJavaStringToUTF8(env, j_home_country);
can_send_base_page_url_ = j_may_send_base_page_url;
previous_event_id_ = j_previous_event_id;
previous_event_results_ = j_previous_event_results;
}
void ContextualSearchContext::SetContent(
......@@ -74,103 +74,138 @@ void ContextualSearchContext::AdjustSelection(JNIEnv* env,
jobject obj,
jint j_start_adjust,
jint j_end_adjust) {
DCHECK(start_offset + j_start_adjust >= 0);
DCHECK(start_offset + j_start_adjust <= (int)surrounding_text.length());
DCHECK(end_offset + j_end_adjust >= 0);
DCHECK(end_offset + j_end_adjust <= (int)surrounding_text.length());
start_offset += j_start_adjust;
end_offset += j_end_adjust;
DCHECK(start_offset_ + j_start_adjust >= 0);
DCHECK(start_offset_ + j_start_adjust <= (int)surrounding_text_.length());
DCHECK(end_offset_ + j_end_adjust >= 0);
DCHECK(end_offset_ + j_end_adjust <= (int)surrounding_text_.length());
start_offset_ += j_start_adjust;
end_offset_ += j_end_adjust;
}
// Accessors
bool ContextualSearchContext::CanResolve() const {
return can_resolve;
return can_resolve_;
}
bool ContextualSearchContext::CanSendBasePageUrl() const {
return can_send_base_page_url;
return can_send_base_page_url_;
}
const GURL ContextualSearchContext::GetBasePageUrl() const {
return base_page_url;
return 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 {
return base_page_encoding;
return base_page_encoding_;
}
void ContextualSearchContext::SetBasePageEncoding(
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 {
return home_country;
return home_country_;
}
int64_t ContextualSearchContext::GetPreviousEventId() const {
return previous_event_id;
return previous_event_id_;
}
int ContextualSearchContext::GetPreviousEventResults() const {
return previous_event_results;
return previous_event_results_;
}
void ContextualSearchContext::SetSelectionSurroundings(
int start_offset,
int end_offset,
const base::string16& surrounding_text) {
this->start_offset = start_offset;
this->end_offset = end_offset;
this->surrounding_text = surrounding_text;
this->start_offset_ = start_offset;
this->end_offset_ = end_offset;
this->surrounding_text_ = surrounding_text;
}
const base::string16 ContextualSearchContext::GetSurroundingText() const {
return surrounding_text;
return surrounding_text_;
}
int ContextualSearchContext::GetStartOffset() const {
return start_offset;
return start_offset_;
}
int ContextualSearchContext::GetEndOffset() const {
return end_offset;
return end_offset_;
}
void ContextualSearchContext::SetExactResolve(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) {
is_exact_resolve = true;
is_exact_resolve_ = true;
}
bool ContextualSearchContext::GetExactResolve() {
return is_exact_resolve;
return is_exact_resolve_;
}
base::android::ScopedJavaLocalRef<jstring>
ContextualSearchContext::DetectLanguage(
JNIEnv* env,
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 html_lang;
std::string cld_language;
bool is_cld_reliable;
std::string language = translate::DeterminePageLanguage(
content_language, html_lang, this->surrounding_text, &cld_language,
&is_cld_reliable);
content_language, html_lang, contents, &cld_language, &is_cld_reliable);
// Make sure we return an empty string when unreliable or an unknown result.
if (!is_cld_reliable || language == translate::kUnknownLanguageCode)
language = "";
base::android::ScopedJavaLocalRef<jstring> j_language =
base::android::ConvertUTF8ToJavaString(env, language);
return j_language;
return 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() {
return weak_factory_.GetWeakPtr();
}
......
......@@ -16,6 +16,12 @@
// text.
struct ContextualSearchContext {
public:
// Languages needed for translation.
struct TranslationLanguages {
std::string detected_language;
std::string target_language;
};
ContextualSearchContext(JNIEnv* env, jobject obj);
// Constructor for tests.
ContextualSearchContext(const std::string& home_country,
......@@ -106,22 +112,41 @@ struct ContextualSearchContext {
JNIEnv* env,
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.
base::WeakPtr<ContextualSearchContext> GetWeakPtr();
private:
bool can_resolve = false;
bool can_send_base_page_url = false;
std::string home_country;
GURL base_page_url;
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;
// Gets the reliable language of the given |contents| using CLD, or an empty
// string if none can reliably be determined.
std::string GetReliableLanguage(const base::string16& contents);
// Gets the selection, or an empty string if none.
base::string16 GetSelection();
bool can_resolve_ = false;
bool can_send_base_page_url_ = false;
std::string home_country_;
GURL base_page_url_;
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.
base::android::ScopedJavaGlobalRef<jobject> java_object_;
......
......@@ -294,7 +294,8 @@ std::string ContextualSearchDelegate::BuildRequestUrl(
kContextualSearchRequestVersion, contextual_cards_version,
context->GetHomeCountry(), context->GetPreviousEventId(),
context->GetPreviousEventResults(), context->GetExactResolve(),
std::string(), std::string());
context->GetTranslationLanguages().detected_language,
context->GetTranslationLanguages().target_language);
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