Index: chrome/browser/translate/translate_language_list.cc |
diff --git a/chrome/browser/translate/translate_language_list.cc b/chrome/browser/translate/translate_language_list.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..99e3c6e650ae436119538dc2f83a72459232ca08 |
--- /dev/null |
+++ b/chrome/browser/translate/translate_language_list.cc |
@@ -0,0 +1,242 @@ |
+// Copyright 2013 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/translate/translate_language_list.h" |
+ |
+#include <set> |
+ |
+#include "base/command_line.h" |
+#include "base/json/json_reader.h" |
+#include "base/lazy_instance.h" |
+#include "base/logging.h" |
+#include "base/string_util.h" |
+#include "base/values.h" |
+#include "chrome/browser/browser_process.h" |
+#include "chrome/browser/translate/translate_url_util.h" |
+#include "chrome/common/chrome_switches.h" |
+#include "googleurl/src/gurl.h" |
+#include "net/base/load_flags.h" |
+#include "net/base/url_util.h" |
+#include "net/http/http_status_code.h" |
+#include "net/url_request/url_fetcher.h" |
+#include "net/url_request/url_request_status.h" |
+ |
+namespace { |
+ |
+// The default list of languages the Google translation server supports. |
+// We use this list until we receive the list that the server exposes. |
+// For information, here is the list of languages that Chrome can be run in |
+// but that the translation server does not support: |
+// am Amharic |
+// bn Bengali |
+// gu Gujarati |
+// kn Kannada |
+// ml Malayalam |
+// mr Marathi |
+// ta Tamil |
+// te Telugu |
+const char* const kDefaultSupportedLanguages[] = { |
+ "af", // Afrikaans |
+ "sq", // Albanian |
+ "ar", // Arabic |
+ "be", // Belarusian |
+ "bg", // Bulgarian |
+ "ca", // Catalan |
+ "zh-CN", // Chinese (Simplified) |
+ "zh-TW", // Chinese (Traditional) |
+ "hr", // Croatian |
+ "cs", // Czech |
+ "da", // Danish |
+ "nl", // Dutch |
+ "en", // English |
+ "eo", // Esperanto |
+ "et", // Estonian |
+ "tl", // Filipino |
+ "fi", // Finnish |
+ "fr", // French |
+ "gl", // Galician |
+ "de", // German |
+ "el", // Greek |
+ "ht", // Haitian Creole |
+ "iw", // Hebrew |
+ "hi", // Hindi |
+ "hu", // Hungarian |
+ "is", // Icelandic |
+ "id", // Indonesian |
+ "ga", // Irish |
+ "it", // Italian |
+ "ja", // Japanese |
+ "ko", // Korean |
+ "lv", // Latvian |
+ "lt", // Lithuanian |
+ "mk", // Macedonian |
+ "ms", // Malay |
+ "mt", // Maltese |
+ "no", // Norwegian |
+ "fa", // Persian |
+ "pl", // Polish |
+ "pt", // Portuguese |
+ "ro", // Romanian |
+ "ru", // Russian |
+ "sr", // Serbian |
+ "sk", // Slovak |
+ "sl", // Slovenian |
+ "es", // Spanish |
+ "sw", // Swahili |
+ "sv", // Swedish |
+ "th", // Thai |
+ "tr", // Turkish |
+ "uk", // Ukrainian |
+ "vi", // Vietnamese |
+ "cy", // Welsh |
+ "yi", // Yiddish |
+}; |
+ |
+// Constant URL string to fetch server supporting language list. |
+const char kLanguageListFetchURL[] = |
+ "https://translate.googleapis.com/translate_a/l?client=chrome&cb=sl"; |
+ |
+// Used in kTranslateScriptURL to request supporting languages list including |
+// "alpha languages". |
+const char kAlphaLanguageQueryName[] = "alpha"; |
+const char kAlphaLanguageQueryValue[] = "1"; |
+ |
+// Retry parameter for fetching supporting language list. |
+const int kMaxRetryLanguageListFetch = 5; |
+ |
+} // namespace |
+ |
+// This must be kept in sync with the &cb= value in the kLanguageListFetchURL. |
+const char TranslateLanguageList::kLanguageListCallbackName[] = "sl("; |
+const char TranslateLanguageList::kTargetLanguagesKey[] = "tl"; |
+ |
+TranslateLanguageList::TranslateLanguageList() { |
+ // We default to our hard coded list of languages in |
+ // |kDefaultSupportedLanguages|. This list will be overriden by a server |
+ // providing supported langauges list. |
+ for (size_t i = 0; i < arraysize(kDefaultSupportedLanguages); ++i) |
+ supported_languages_.insert(kDefaultSupportedLanguages[i]); |
+} |
+ |
+TranslateLanguageList::~TranslateLanguageList() {} |
+ |
+void TranslateLanguageList::OnURLFetchComplete(const net::URLFetcher* source) { |
+ DCHECK(url_fetcher_.get() == source); |
+ scoped_ptr<const net::URLFetcher> delete_ptr(url_fetcher_.release()); |
+ |
+ if (source->GetStatus().status() == net::URLRequestStatus::SUCCESS && |
+ source->GetResponseCode() == net::HTTP_OK) { |
+ std::string data; |
+ source->GetResponseAsString(&data); |
+ SetSupportedLanguages(data); |
+ } else { |
+ // TODO(toyoshim): Try again. http://crbug.com/244202 . |
+ VLOG(9) << "Failed to Fetch languages from: " << kLanguageListFetchURL; |
+ } |
+} |
+ |
+void TranslateLanguageList::GetSupportedLanguages( |
+ std::vector<std::string>* languages) { |
+ DCHECK(languages && languages->empty()); |
+ std::set<std::string>::const_iterator iter = supported_languages_.begin(); |
+ for (; iter != supported_languages_.end(); ++iter) |
+ languages->push_back(*iter); |
+} |
+ |
+std::string TranslateLanguageList::GetLanguageCode( |
+ const std::string& chrome_locale) { |
+ // Only remove the country code for country specific languages we don't |
+ // support specifically yet. |
+ if (IsSupportedLanguage(chrome_locale)) |
+ return chrome_locale; |
+ |
+ size_t hypen_index = chrome_locale.find('-'); |
+ if (hypen_index == std::string::npos) |
+ return chrome_locale; |
+ return chrome_locale.substr(0, hypen_index); |
+} |
+ |
+bool TranslateLanguageList::IsSupportedLanguage( |
+ const std::string& page_language) { |
+ return supported_languages_.count(page_language) != 0; |
+} |
+ |
+void TranslateLanguageList::RequestLanguageList() { |
+ if (url_fetcher_.get()) |
+ return; |
+ |
+ GURL language_list_fetch_url = GURL(kLanguageListFetchURL); |
+ language_list_fetch_url = |
+ TranslateURLUtil::AddHostLocaleToUrl(language_list_fetch_url); |
+ language_list_fetch_url = |
+ TranslateURLUtil::AddApiKeyToUrl(language_list_fetch_url); |
+ |
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
+ if (command_line.HasSwitch(switches::kEnableTranslateAlphaLanguages)) { |
+ language_list_fetch_url = net::AppendQueryParameter( |
+ language_list_fetch_url, |
+ kAlphaLanguageQueryName, |
+ kAlphaLanguageQueryValue); |
+ } |
+ |
+ VLOG(9) << "Fetch supporting language list from: " |
+ << language_list_fetch_url.spec().c_str(); |
+ |
+ url_fetcher_.reset(net::URLFetcher::Create(1, |
+ language_list_fetch_url, |
+ net::URLFetcher::GET, |
+ this)); |
+ url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
+ net::LOAD_DO_NOT_SAVE_COOKIES); |
+ url_fetcher_->SetRequestContext(g_browser_process->system_request_context()); |
+ url_fetcher_->SetMaxRetriesOn5xx(kMaxRetryLanguageListFetch); |
+ url_fetcher_->Start(); |
+} |
+ |
+void TranslateLanguageList::SetSupportedLanguages( |
+ const std::string& language_list) { |
+ // The format is: |
+ // sl({"sl": {"XX": "LanguageName", ...}, "tl": {"XX": "LanguageName", ...}}) |
+ // Where "sl(" is set in kLanguageListCallbackName |
+ // and "tl" is kTargetLanguagesKey |
+ if (!StartsWithASCII(language_list, |
+ TranslateLanguageList::kLanguageListCallbackName, |
+ false) || |
+ !EndsWith(language_list, ")", false)) { |
+ // We don't have a NOTREACHED here since this can happen in ui_tests, even |
+ // though the the BrowserMain function won't call us with parameters.ui_task |
+ // is NULL some tests don't set it, so we must bail here. |
+ return; |
+ } |
+ static const size_t kLanguageListCallbackNameLength = |
+ strlen(TranslateLanguageList::kLanguageListCallbackName); |
+ std::string languages_json = language_list.substr( |
+ kLanguageListCallbackNameLength, |
+ language_list.size() - kLanguageListCallbackNameLength - 1); |
+ scoped_ptr<Value> json_value( |
+ base::JSONReader::Read(languages_json, base::JSON_ALLOW_TRAILING_COMMAS)); |
+ if (json_value == NULL || !json_value->IsType(Value::TYPE_DICTIONARY)) { |
+ NOTREACHED(); |
+ return; |
+ } |
+ // The first level dictionary contains two sub-dict, one for source languages |
+ // and the other for target languages, we want to use the target languages. |
+ DictionaryValue* language_dict = |
+ static_cast<DictionaryValue*>(json_value.get()); |
+ DictionaryValue* target_languages = NULL; |
+ if (!language_dict->GetDictionary(TranslateLanguageList::kTargetLanguagesKey, |
+ &target_languages) || |
+ target_languages == NULL) { |
+ NOTREACHED(); |
+ return; |
+ } |
+ // Now we can clear our current state... |
+ supported_languages_.clear(); |
+ // ... and replace it with the values we just fetched from the server. |
+ for (DictionaryValue::Iterator iter(*target_languages); |
+ !iter.IsAtEnd(); |
+ iter.Advance()) { |
+ supported_languages_.insert(iter.key()); |
+ } |
+} |