Remove linux_chromium_gn_dbg from the chromium CQ.
[chromium-blink-merge.git] / extensions / renderer / i18n_custom_bindings.cc
blob6a743cc521dbd532bd6a7b6f4e61de026eeb5138
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/renderer/i18n_custom_bindings.h"
7 #include "base/bind.h"
8 #include "content/public/renderer/render_frame.h"
9 #include "content/public/renderer/render_thread.h"
10 #include "extensions/common/extension_messages.h"
11 #include "extensions/common/message_bundle.h"
12 #include "extensions/renderer/script_context.h"
13 #include "extensions/renderer/v8_helpers.h"
14 #include "third_party/cld_2/src/public/compact_lang_det.h"
15 #include "third_party/cld_2/src/public/encodings.h"
17 namespace extensions {
19 using namespace v8_helpers;
21 namespace {
23 // Max number of languages detected by CLD2.
24 const int kCldNumLangs = 3;
26 struct DetectedLanguage {
27 DetectedLanguage(const std::string& language, int percentage)
28 : language(language), percentage(percentage) {}
29 ~DetectedLanguage() {}
31 // Returns a new v8::Local<v8::Value> representing the serialized form of
32 // this DetectedLanguage object.
33 v8::Local<v8::Value> ToValue(ScriptContext* context);
35 std::string language;
36 int percentage;
38 private:
39 DISALLOW_COPY_AND_ASSIGN(DetectedLanguage);
42 // LanguageDetectionResult object that holds detected langugae reliability and
43 // array of DetectedLanguage
44 struct LanguageDetectionResult {
45 explicit LanguageDetectionResult(bool is_reliable)
46 : is_reliable(is_reliable) {}
47 ~LanguageDetectionResult() {}
49 // Returns a new v8::Local<v8::Value> representing the serialized form of
50 // this Result object.
51 v8::Local<v8::Value> ToValue(ScriptContext* context);
53 // CLD detected language reliability
54 bool is_reliable;
56 // Array of detectedLanguage of size 1-3. The null is returned if
57 // there were no languages detected
58 ScopedVector<DetectedLanguage> languages;
60 private:
61 DISALLOW_COPY_AND_ASSIGN(LanguageDetectionResult);
64 v8::Local<v8::Value> DetectedLanguage::ToValue(ScriptContext* context) {
65 v8::Local<v8::Context> v8_context = context->v8_context();
66 v8::Isolate* isolate = v8_context->GetIsolate();
67 v8::EscapableHandleScope handle_scope(isolate);
69 v8::Local<v8::Object> value(v8::Object::New(isolate));
70 SetProperty(v8_context, value, ToV8StringUnsafe(isolate, "language"),
71 ToV8StringUnsafe(isolate, language.c_str()));
73 SetProperty(v8_context, value, ToV8StringUnsafe(isolate, "percentage"),
74 v8::Number::New(isolate, percentage));
76 v8::Local<v8::Value> result = v8::Local<v8::Value>::Cast(value);
77 return handle_scope.Escape(result);
80 v8::Local<v8::Value> LanguageDetectionResult::ToValue(ScriptContext* context) {
81 v8::Local<v8::Context> v8_context = context->v8_context();
82 v8::Isolate* isolate = v8_context->GetIsolate();
83 v8::EscapableHandleScope handle_scope(isolate);
85 v8::Local<v8::Object> value(v8::Object::New(isolate));
86 SetProperty(v8_context, value, ToV8StringUnsafe(isolate, "isReliable"),
87 v8::Boolean::New(isolate, is_reliable));
89 v8::Local<v8::Array> langs(v8::Array::New(isolate, languages.size()));
90 for (size_t i = 0; i < languages.size(); ++i) {
91 SetProperty(v8_context, langs, i, languages[i]->ToValue(context));
94 SetProperty(isolate->GetCurrentContext(), value,
95 ToV8StringUnsafe(isolate, "languages"), langs);
97 v8::Local<v8::Value> result = v8::Local<v8::Value>::Cast(value);
98 return handle_scope.Escape(result);
101 void InitDetectedLanguages(CLD2::Language* languages,
102 int* percents,
103 ScopedVector<DetectedLanguage>* detected_languages) {
104 for (int i = 0; i < kCldNumLangs; i++) {
105 std::string language_code;
106 // Convert LanguageCode 'zh' to 'zh-CN' and 'zh-Hant' to 'zh-TW' for
107 // Translate server usage. see DetermineTextLanguage in
108 // components/translate/core/language_detection/language_detection_util.cc
109 if (languages[i] == CLD2::UNKNOWN_LANGUAGE) {
110 // Break from the loop since there is no need to save
111 // unknown languages
112 break;
113 } else {
114 language_code =
115 CLD2::LanguageCode(static_cast<CLD2::Language>(languages[i]));
117 detected_languages->push_back(
118 new DetectedLanguage(language_code, percents[i]));
122 } // namespace
124 I18NCustomBindings::I18NCustomBindings(ScriptContext* context)
125 : ObjectBackedNativeHandler(context) {
126 RouteFunction(
127 "GetL10nMessage",
128 base::Bind(&I18NCustomBindings::GetL10nMessage, base::Unretained(this)));
129 RouteFunction("GetL10nUILanguage",
130 base::Bind(&I18NCustomBindings::GetL10nUILanguage,
131 base::Unretained(this)));
132 RouteFunction("DetectTextLanguage",
133 base::Bind(&I18NCustomBindings::DetectTextLanguage,
134 base::Unretained(this)));
137 void I18NCustomBindings::GetL10nMessage(
138 const v8::FunctionCallbackInfo<v8::Value>& args) {
139 if (args.Length() != 3 || !args[0]->IsString()) {
140 NOTREACHED() << "Bad arguments";
141 return;
144 std::string extension_id;
145 if (args[2]->IsNull() || !args[2]->IsString()) {
146 return;
147 } else {
148 extension_id = *v8::String::Utf8Value(args[2]);
149 if (extension_id.empty())
150 return;
153 L10nMessagesMap* l10n_messages = GetL10nMessagesMap(extension_id);
154 if (!l10n_messages) {
155 content::RenderFrame* render_frame = context()->GetRenderFrame();
156 if (!render_frame)
157 return;
159 L10nMessagesMap messages;
160 // A sync call to load message catalogs for current extension.
161 render_frame->Send(
162 new ExtensionHostMsg_GetMessageBundle(extension_id, &messages));
164 // Save messages we got.
165 ExtensionToL10nMessagesMap& l10n_messages_map =
166 *GetExtensionToL10nMessagesMap();
167 l10n_messages_map[extension_id] = messages;
169 l10n_messages = GetL10nMessagesMap(extension_id);
172 std::string message_name = *v8::String::Utf8Value(args[0]);
173 std::string message =
174 MessageBundle::GetL10nMessage(message_name, *l10n_messages);
176 v8::Isolate* isolate = args.GetIsolate();
177 std::vector<std::string> substitutions;
178 if (args[1]->IsArray()) {
179 // chrome.i18n.getMessage("message_name", ["more", "params"]);
180 v8::Local<v8::Array> placeholders = v8::Local<v8::Array>::Cast(args[1]);
181 uint32_t count = placeholders->Length();
182 if (count > 9)
183 return;
184 for (uint32_t i = 0; i < count; ++i) {
185 substitutions.push_back(*v8::String::Utf8Value(placeholders->Get(
186 v8::Integer::New(isolate, i))));
188 } else if (args[1]->IsString()) {
189 // chrome.i18n.getMessage("message_name", "one param");
190 substitutions.push_back(*v8::String::Utf8Value(args[1]));
193 args.GetReturnValue().Set(v8::String::NewFromUtf8(
194 isolate,
195 base::ReplaceStringPlaceholders(message, substitutions, NULL).c_str()));
198 void I18NCustomBindings::GetL10nUILanguage(
199 const v8::FunctionCallbackInfo<v8::Value>& args) {
200 args.GetReturnValue().Set(v8::String::NewFromUtf8(
201 args.GetIsolate(), content::RenderThread::Get()->GetLocale().c_str()));
204 void I18NCustomBindings::DetectTextLanguage(
205 const v8::FunctionCallbackInfo<v8::Value>& args) {
206 CHECK(args.Length() == 1);
207 CHECK(args[0]->IsString());
209 std::string text = *v8::String::Utf8Value(args[0]);
210 CLD2::CLDHints cldhints = {nullptr, "", CLD2::UNKNOWN_ENCODING,
211 CLD2::UNKNOWN_LANGUAGE};
213 bool is_plain_text = true; // assume the text is a plain text
214 int flags = 0; // no flags, see compact_lang_det.h for details
215 int text_bytes; // amount of non-tag/letters-only text (assumed 0)
216 int valid_prefix_bytes; // amount of valid UTF8 character in the string
217 double normalized_score[kCldNumLangs];
219 CLD2::Language languages[kCldNumLangs];
220 int percents[kCldNumLangs];
221 bool is_reliable = false;
223 // populating languages and percents
224 int cld_language = CLD2::ExtDetectLanguageSummaryCheckUTF8(
225 text.c_str(), static_cast<int>(text.size()), is_plain_text, &cldhints,
226 flags, languages, percents, normalized_score,
227 nullptr, // assumed no ResultChunkVector is used
228 &text_bytes, &is_reliable, &valid_prefix_bytes);
230 // Check if non-UTF8 character is encountered
231 // See bug http://crbug.com/444258.
232 if (valid_prefix_bytes < static_cast<int>(text.size()) &&
233 cld_language == CLD2::UNKNOWN_LANGUAGE) {
234 // Detect Language upto before the first non-UTF8 character
235 CLD2::ExtDetectLanguageSummary(
236 text.c_str(), valid_prefix_bytes, is_plain_text, &cldhints, flags,
237 languages, percents, normalized_score,
238 nullptr, // assumed no ResultChunkVector is used
239 &text_bytes, &is_reliable);
242 LanguageDetectionResult result(is_reliable);
243 // populate LanguageDetectionResult with languages and percents
244 InitDetectedLanguages(languages, percents, &result.languages);
246 args.GetReturnValue().Set(result.ToValue(context()));
249 } // namespace extensions