OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 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. |
| 4 |
| 5 #include "chrome/browser/translate/translate_language_list.h" |
| 6 |
| 7 #include "base/command_line.h" |
| 8 #include "base/json/json_reader.h" |
| 9 #include "base/lazy_instance.h" |
| 10 #include "base/logging.h" |
| 11 #include "base/string_util.h" |
| 12 #include "base/values.h" |
| 13 #include "chrome/browser/browser_process.h" |
| 14 #include "chrome/browser/translate/translate_url_util.h" |
| 15 #include "chrome/common/chrome_switches.h" |
| 16 #include "googleurl/src/gurl.h" |
| 17 #include "net/base/load_flags.h" |
| 18 #include "net/base/url_util.h" |
| 19 #include "net/http/http_status_code.h" |
| 20 #include "net/url_request/url_fetcher.h" |
| 21 #include "net/url_request/url_request_status.h" |
| 22 |
| 23 namespace { |
| 24 |
| 25 // The default list of languages the Google translation server supports. |
| 26 // We use this list until we receive the list that the server exposes. |
| 27 // For information, here is the list of languages that Chrome can be run in |
| 28 // but that the translation server does not support: |
| 29 // am Amharic |
| 30 // bn Bengali |
| 31 // gu Gujarati |
| 32 // kn Kannada |
| 33 // ml Malayalam |
| 34 // mr Marathi |
| 35 // ta Tamil |
| 36 // te Telugu |
| 37 const char* const kDefaultSupportedLanguages[] = { |
| 38 "af", // Afrikaans |
| 39 "sq", // Albanian |
| 40 "ar", // Arabic |
| 41 "be", // Belarusian |
| 42 "bg", // Bulgarian |
| 43 "ca", // Catalan |
| 44 "zh-CN", // Chinese (Simplified) |
| 45 "zh-TW", // Chinese (Traditional) |
| 46 "hr", // Croatian |
| 47 "cs", // Czech |
| 48 "da", // Danish |
| 49 "nl", // Dutch |
| 50 "en", // English |
| 51 "eo", // Esperanto |
| 52 "et", // Estonian |
| 53 "tl", // Filipino |
| 54 "fi", // Finnish |
| 55 "fr", // French |
| 56 "gl", // Galician |
| 57 "de", // German |
| 58 "el", // Greek |
| 59 "ht", // Haitian Creole |
| 60 "iw", // Hebrew |
| 61 "hi", // Hindi |
| 62 "hu", // Hungarian |
| 63 "is", // Icelandic |
| 64 "id", // Indonesian |
| 65 "ga", // Irish |
| 66 "it", // Italian |
| 67 "ja", // Japanese |
| 68 "ko", // Korean |
| 69 "lv", // Latvian |
| 70 "lt", // Lithuanian |
| 71 "mk", // Macedonian |
| 72 "ms", // Malay |
| 73 "mt", // Maltese |
| 74 "no", // Norwegian |
| 75 "fa", // Persian |
| 76 "pl", // Polish |
| 77 "pt", // Portuguese |
| 78 "ro", // Romanian |
| 79 "ru", // Russian |
| 80 "sr", // Serbian |
| 81 "sk", // Slovak |
| 82 "sl", // Slovenian |
| 83 "es", // Spanish |
| 84 "sw", // Swahili |
| 85 "sv", // Swedish |
| 86 "th", // Thai |
| 87 "tr", // Turkish |
| 88 "uk", // Ukrainian |
| 89 "vi", // Vietnamese |
| 90 "cy", // Welsh |
| 91 "yi", // Yiddish |
| 92 }; |
| 93 |
| 94 // Constant URL string to fetch server supporting language list. |
| 95 const char kLanguageListFetchURL[] = |
| 96 "https://translate.googleapis.com/translate_a/l?client=chrome&cb=sl"; |
| 97 |
| 98 // Used in kTranslateScriptURL to request supporting languages list including |
| 99 // "alpha languages". |
| 100 const char kAlphaLanguageQueryName[] = "alpha"; |
| 101 const char kAlphaLanguageQueryValue[] = "1"; |
| 102 |
| 103 // Retry parameter for fetching supporting language list. |
| 104 const int kMaxRetryLanguageListFetch = 5; |
| 105 |
| 106 // The languages supported by the translation server. |
| 107 base::LazyInstance<std::set<std::string> > supported_languages = |
| 108 LAZY_INSTANCE_INITIALIZER; |
| 109 |
| 110 // Initializes the list of supported languages if it wasn't initialized before |
| 111 // in case we failed to get them from the server, or didn't get them just yet. |
| 112 void InitSupportedLanguages() { |
| 113 // If our list of supported languages have not been set yet, we default |
| 114 // to our hard coded list of languages in kDefaultSupportedLanguages. |
| 115 std::set<std::string>* set = supported_languages.Pointer(); |
| 116 if (set->empty()) { |
| 117 for (size_t i = 0; i < arraysize(kDefaultSupportedLanguages); ++i) |
| 118 set->insert(kDefaultSupportedLanguages[i]); |
| 119 } |
| 120 } |
| 121 |
| 122 // Fills supported_languages with the list of languages that the translate |
| 123 // server can translate to and from. |
| 124 void SetSupportedLanguages(const std::string& language_list) { |
| 125 // The format is: |
| 126 // sl({"sl": {"XX": "LanguageName", ...}, "tl": {"XX": "LanguageName", ...}}) |
| 127 // Where "sl(" is set in kLanguageListCallbackName |
| 128 // and "tl" is kTargetLanguagesKey |
| 129 if (!StartsWithASCII(language_list, |
| 130 TranslateLanguageList::kLanguageListCallbackName, |
| 131 false) || |
| 132 !EndsWith(language_list, ")", false)) { |
| 133 // We don't have a NOTREACHED here since this can happen in ui_tests, even |
| 134 // though the the BrowserMain function won't call us with parameters.ui_task |
| 135 // is NULL some tests don't set it, so we must bail here. |
| 136 return; |
| 137 } |
| 138 static const size_t kLanguageListCallbackNameLength = |
| 139 strlen(TranslateLanguageList::kLanguageListCallbackName); |
| 140 std::string languages_json = language_list.substr( |
| 141 kLanguageListCallbackNameLength, |
| 142 language_list.size() - kLanguageListCallbackNameLength - 1); |
| 143 scoped_ptr<Value> json_value( |
| 144 base::JSONReader::Read(languages_json, base::JSON_ALLOW_TRAILING_COMMAS)); |
| 145 if (json_value == NULL || !json_value->IsType(Value::TYPE_DICTIONARY)) { |
| 146 NOTREACHED(); |
| 147 return; |
| 148 } |
| 149 // The first level dictionary contains two sub-dict, one for source languages |
| 150 // and the other for target languages, we want to use the target languages. |
| 151 DictionaryValue* language_dict = |
| 152 static_cast<DictionaryValue*>(json_value.get()); |
| 153 DictionaryValue* target_languages = NULL; |
| 154 if (!language_dict->GetDictionary(TranslateLanguageList::kTargetLanguagesKey, |
| 155 &target_languages) || |
| 156 target_languages == NULL) { |
| 157 NOTREACHED(); |
| 158 return; |
| 159 } |
| 160 // Now we can clear our current state... |
| 161 std::set<std::string>* set = supported_languages.Pointer(); |
| 162 set->clear(); |
| 163 // ... and replace it with the values we just fetched from the server. |
| 164 for (DictionaryValue::Iterator iter(*target_languages); |
| 165 !iter.IsAtEnd(); |
| 166 iter.Advance()) { |
| 167 set->insert(iter.key()); |
| 168 } |
| 169 } |
| 170 |
| 171 } // namespace |
| 172 |
| 173 // This must be kept in sync with the &cb= value in the kLanguageListFetchURL. |
| 174 const char TranslateLanguageList::kLanguageListCallbackName[] = "sl("; |
| 175 const char TranslateLanguageList::kTargetLanguagesKey[] = "tl"; |
| 176 |
| 177 TranslateLanguageList* TranslateLanguageList::GetInstance() { |
| 178 return Singleton<TranslateLanguageList>::get(); |
| 179 } |
| 180 |
| 181 TranslateLanguageList::~TranslateLanguageList() {} |
| 182 |
| 183 void TranslateLanguageList::OnURLFetchComplete(const net::URLFetcher* source) { |
| 184 DCHECK(url_fetcher_.get() == source); |
| 185 |
| 186 scoped_ptr<const net::URLFetcher> delete_ptr(url_fetcher_.release()); |
| 187 |
| 188 if (source->GetStatus().status() == net::URLRequestStatus::SUCCESS && |
| 189 source->GetResponseCode() == net::HTTP_OK) { |
| 190 std::string data; |
| 191 source->GetResponseAsString(&data); |
| 192 SetSupportedLanguages(data); |
| 193 } else { |
| 194 VLOG(9) << "Failed to Fetch languages from: " << kLanguageListFetchURL; |
| 195 } |
| 196 } |
| 197 |
| 198 // static |
| 199 void TranslateLanguageList::GetSupportedLanguages( |
| 200 std::vector<std::string>* languages) { |
| 201 DCHECK(languages && languages->empty()); |
| 202 InitSupportedLanguages(); |
| 203 std::set<std::string>* set = supported_languages.Pointer(); |
| 204 std::set<std::string>::const_iterator iter = set->begin(); |
| 205 for (; iter != set->end(); ++iter) |
| 206 languages->push_back(*iter); |
| 207 } |
| 208 |
| 209 // static |
| 210 bool TranslateLanguageList::IsSupportedLanguage( |
| 211 const std::string& page_language) { |
| 212 InitSupportedLanguages(); |
| 213 return supported_languages.Pointer()->count(page_language) != 0; |
| 214 } |
| 215 |
| 216 // static |
| 217 std::string TranslateLanguageList::GetLanguageCode( |
| 218 const std::string& chrome_locale) { |
| 219 // Only remove the country code for country specific languages we don't |
| 220 // support specifically yet. |
| 221 if (IsSupportedLanguage(chrome_locale)) |
| 222 return chrome_locale; |
| 223 |
| 224 size_t hypen_index = chrome_locale.find('-'); |
| 225 if (hypen_index == std::string::npos) |
| 226 return chrome_locale; |
| 227 return chrome_locale.substr(0, hypen_index); |
| 228 } |
| 229 |
| 230 TranslateLanguageList::TranslateLanguageList() {} |
| 231 |
| 232 // static |
| 233 void TranslateLanguageList::RequestLanguageList() { |
| 234 GURL language_list_fetch_url = GURL(kLanguageListFetchURL); |
| 235 language_list_fetch_url = |
| 236 TranslateURLUtil::AddHostLocaleToUrl(language_list_fetch_url); |
| 237 language_list_fetch_url = |
| 238 TranslateURLUtil::AddApiKeyToUrl(language_list_fetch_url); |
| 239 |
| 240 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| 241 if (command_line.HasSwitch(switches::kEnableTranslateAlphaLanguages)) { |
| 242 language_list_fetch_url = net::AppendQueryParameter( |
| 243 language_list_fetch_url, |
| 244 kAlphaLanguageQueryName, |
| 245 kAlphaLanguageQueryValue); |
| 246 } |
| 247 |
| 248 VLOG(9) << "Fetch supporting language list from: " |
| 249 << language_list_fetch_url.spec().c_str(); |
| 250 |
| 251 TranslateLanguageList* instance = GetInstance(); |
| 252 DCHECK(instance); |
| 253 |
| 254 instance->url_fetcher_.reset(net::URLFetcher::Create(1, |
| 255 language_list_fetch_url, |
| 256 net::URLFetcher::GET, |
| 257 instance)); |
| 258 instance->url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 259 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 260 instance->url_fetcher_->SetRequestContext( |
| 261 g_browser_process->system_request_context()); |
| 262 instance->url_fetcher_->SetMaxRetriesOn5xx(kMaxRetryLanguageListFetch); |
| 263 instance->url_fetcher_->Start(); |
| 264 } |
| 265 |
| 266 // static |
| 267 bool TranslateLanguageList::HasPendingRequest() { |
| 268 TranslateLanguageList* instance = GetInstance(); |
| 269 DCHECK(instance); |
| 270 return instance->url_fetcher_.get() != NULL; |
| 271 } |
| 272 |
| 273 // static |
| 274 void TranslateLanguageList::ResetPendingRequest() { |
| 275 TranslateLanguageList* instance = GetInstance(); |
| 276 DCHECK(instance); |
| 277 instance->url_fetcher_.reset(); |
| 278 } |
OLD | NEW |