1// Copyright (c) 2012 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/ui/webui/options/language_options_handler_common.h"
6
7#include <map>
8#include <string>
9#include <utility>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/bind.h"
14#include "base/command_line.h"
15#include "base/prefs/pref_service.h"
16#include "base/strings/string_util.h"
17#include "base/strings/stringprintf.h"
18#include "base/strings/utf_string_conversions.h"
19#include "base/values.h"
20#include "chrome/browser/browser_process.h"
21#include "chrome/browser/profiles/profile.h"
22#include "chrome/browser/spellchecker/spellcheck_factory.h"
23#include "chrome/browser/spellchecker/spellcheck_service.h"
24#include "chrome/browser/translate/chrome_translate_client.h"
25#include "chrome/browser/translate/translate_service.h"
26#include "chrome/browser/ui/browser_list.h"
27#include "chrome/common/chrome_switches.h"
28#include "chrome/common/pref_names.h"
29#include "chrome/common/spellcheck_common.h"
30#include "chrome/grit/chromium_strings.h"
31#include "chrome/grit/generated_resources.h"
32#include "components/translate/core/browser/translate_download_manager.h"
33#include "components/translate/core/browser/translate_prefs.h"
34#include "content/public/browser/user_metrics.h"
35#include "content/public/browser/web_ui.h"
36#include "ui/base/l10n/l10n_util.h"
37
38using base::UserMetricsAction;
39
40namespace options {
41
42LanguageOptionsHandlerCommon::LanguageOptionsHandlerCommon() {
43}
44
45LanguageOptionsHandlerCommon::~LanguageOptionsHandlerCommon() {
46}
47
48void LanguageOptionsHandlerCommon::GetLocalizedValues(
49    base::DictionaryValue* localized_strings) {
50  DCHECK(localized_strings);
51  static OptionsStringResource resources[] = {
52    { "addButton", IDS_OPTIONS_SETTINGS_LANGUAGES_ADD_BUTTON },
53    { "languages", IDS_OPTIONS_SETTINGS_LANGUAGES_LANGUAGES },
54    { "addLanguageInstructions",
55      IDS_OPTIONS_SETTINGS_LANGUAGES_ADD_LANGUAGE_INSTRUCTIONS },
56    { "cannotBeDisplayedInThisLanguage",
57      IDS_OPTIONS_SETTINGS_LANGUAGES_CANNOT_BE_DISPLAYED_IN_THIS_LANGUAGE,
58      IDS_PRODUCT_NAME },
59    { "isDisplayedInThisLanguage",
60      IDS_OPTIONS_SETTINGS_LANGUAGES_IS_DISPLAYED_IN_THIS_LANGUAGE,
61      IDS_PRODUCT_NAME },
62    { "displayInThisLanguage",
63      IDS_OPTIONS_SETTINGS_LANGUAGES_DISPLAY_IN_THIS_LANGUAGE,
64      IDS_PRODUCT_NAME },
65    { "restartRequired", IDS_OPTIONS_RELAUNCH_REQUIRED },
66  // OS X uses the OS native spellchecker so no need for these strings.
67#if !defined(OS_MACOSX)
68    { "useThisForSpellChecking",
69      IDS_OPTIONS_SETTINGS_USE_THIS_FOR_SPELL_CHECKING },
70    { "cannotBeUsedForSpellChecking",
71      IDS_OPTIONS_SETTINGS_CANNOT_BE_USED_FOR_SPELL_CHECKING },
72    { "isUsedForSpellChecking",
73      IDS_OPTIONS_SETTINGS_IS_USED_FOR_SPELL_CHECKING },
74    { "enableSpellCheck", IDS_OPTIONS_ENABLE_SPELLCHECK },
75    { "enableAutoSpellCorrection",
76      IDS_OPTIONS_ENABLE_AUTO_SPELL_CORRECTION },
77    { "downloadingDictionary", IDS_OPTIONS_DICTIONARY_DOWNLOADING },
78    { "downloadFailed", IDS_OPTIONS_DICTIONARY_DOWNLOAD_FAILED },
79    { "retryButton", IDS_OPTIONS_DICTIONARY_DOWNLOAD_RETRY },
80    { "downloadFailHelp", IDS_OPTIONS_DICTIONARY_DOWNLOAD_FAIL_HELP },
81#endif  // !OS_MACOSX
82    { "addLanguageTitle", IDS_OPTIONS_LANGUAGES_ADD_TITLE },
83    { "addLanguageSelectLabel", IDS_OPTIONS_LANGUAGES_ADD_SELECT_LABEL },
84    { "restartButton", IDS_OPTIONS_SETTINGS_LANGUAGES_RELAUNCH_BUTTON },
85    { "offerToTranslateInThisLanguage",
86      IDS_OPTIONS_LANGUAGES_OFFER_TO_TRANSLATE_IN_THIS_LANGUAGE },
87    { "cannotTranslateInThisLanguage",
88      IDS_OPTIONS_LANGUAGES_CANNOT_TRANSLATE_IN_THIS_LANGUAGE },
89  };
90
91#if defined(ENABLE_SETTINGS_APP)
92  static OptionsStringResource app_resources[] = {
93    { "cannotBeDisplayedInThisLanguage",
94      IDS_OPTIONS_SETTINGS_LANGUAGES_CANNOT_BE_DISPLAYED_IN_THIS_LANGUAGE,
95      IDS_SETTINGS_APP_LAUNCHER_PRODUCT_NAME },
96    { "isDisplayedInThisLanguage",
97      IDS_OPTIONS_SETTINGS_LANGUAGES_IS_DISPLAYED_IN_THIS_LANGUAGE,
98      IDS_SETTINGS_APP_LAUNCHER_PRODUCT_NAME },
99    { "displayInThisLanguage",
100      IDS_OPTIONS_SETTINGS_LANGUAGES_DISPLAY_IN_THIS_LANGUAGE,
101      IDS_SETTINGS_APP_LAUNCHER_PRODUCT_NAME },
102  };
103  base::DictionaryValue* app_values = NULL;
104  CHECK(localized_strings->GetDictionary(kSettingsAppKey, &app_values));
105  RegisterStrings(app_values, app_resources, arraysize(app_resources));
106#endif
107
108  RegisterStrings(localized_strings, resources, arraysize(resources));
109
110  // The following are resources, rather than local strings.
111  std::string application_locale = g_browser_process->GetApplicationLocale();
112  localized_strings->SetString("currentUiLanguageCode", application_locale);
113  std::string prospective_locale =
114      g_browser_process->local_state()->GetString(prefs::kApplicationLocale);
115  localized_strings->SetString("prospectiveUiLanguageCode",
116      !prospective_locale.empty() ? prospective_locale : application_locale);
117  localized_strings->Set("spellCheckLanguageCodeSet",
118                         GetSpellCheckLanguageCodeSet());
119  localized_strings->Set("uiLanguageCodeSet", GetUILanguageCodeSet());
120
121  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
122  bool enable_spelling_auto_correct =
123      command_line.HasSwitch(switches::kEnableSpellingAutoCorrect);
124  localized_strings->SetBoolean("enableSpellingAutoCorrect",
125                                enable_spelling_auto_correct);
126
127  Profile* profile = Profile::FromWebUI(web_ui());
128  PrefService* prefs = profile->GetPrefs();
129  std::string default_target_language =
130      TranslateService::GetTargetLanguage(prefs);
131  localized_strings->SetString("defaultTargetLanguage",
132                               default_target_language);
133
134  std::vector<std::string> languages;
135  translate::TranslateDownloadManager::GetSupportedLanguages(&languages);
136
137  base::ListValue* languages_list = new base::ListValue();
138  for (std::vector<std::string>::iterator it = languages.begin();
139       it != languages.end(); ++it) {
140    languages_list->Append(new base::StringValue(*it));
141  }
142
143  localized_strings->Set("translateSupportedLanguages", languages_list);
144}
145
146void LanguageOptionsHandlerCommon::Uninitialize() {
147  if (hunspell_dictionary_.get())
148    hunspell_dictionary_->RemoveObserver(this);
149  hunspell_dictionary_.reset();
150}
151
152void LanguageOptionsHandlerCommon::RegisterMessages() {
153  web_ui()->RegisterMessageCallback("languageOptionsOpen",
154      base::Bind(
155          &LanguageOptionsHandlerCommon::LanguageOptionsOpenCallback,
156          base::Unretained(this)));
157  web_ui()->RegisterMessageCallback("spellCheckLanguageChange",
158      base::Bind(
159          &LanguageOptionsHandlerCommon::SpellCheckLanguageChangeCallback,
160          base::Unretained(this)));
161  web_ui()->RegisterMessageCallback("uiLanguageChange",
162      base::Bind(
163          &LanguageOptionsHandlerCommon::UiLanguageChangeCallback,
164          base::Unretained(this)));
165  web_ui()->RegisterMessageCallback("retryDictionaryDownload",
166      base::Bind(
167          &LanguageOptionsHandlerCommon::RetrySpellcheckDictionaryDownload,
168          base::Unretained(this)));
169  web_ui()->RegisterMessageCallback("updateLanguageList",
170      base::Bind(
171          &LanguageOptionsHandlerCommon::UpdateLanguageListCallback,
172          base::Unretained(this)));
173}
174
175void LanguageOptionsHandlerCommon::OnHunspellDictionaryInitialized() {
176}
177
178void LanguageOptionsHandlerCommon::OnHunspellDictionaryDownloadBegin() {
179  web_ui()->CallJavascriptFunction(
180      "options.LanguageOptions.onDictionaryDownloadBegin",
181      base::StringValue(GetHunspellDictionary()->GetLanguage()));
182}
183
184void LanguageOptionsHandlerCommon::OnHunspellDictionaryDownloadSuccess() {
185  web_ui()->CallJavascriptFunction(
186      "options.LanguageOptions.onDictionaryDownloadSuccess",
187      base::StringValue(GetHunspellDictionary()->GetLanguage()));
188}
189
190void LanguageOptionsHandlerCommon::OnHunspellDictionaryDownloadFailure() {
191  web_ui()->CallJavascriptFunction(
192      "options.LanguageOptions.onDictionaryDownloadFailure",
193      base::StringValue(GetHunspellDictionary()->GetLanguage()));
194}
195
196base::DictionaryValue* LanguageOptionsHandlerCommon::GetUILanguageCodeSet() {
197  base::DictionaryValue* dictionary = new base::DictionaryValue();
198  const std::vector<std::string>& available_locales =
199      l10n_util::GetAvailableLocales();
200  for (size_t i = 0; i < available_locales.size(); ++i)
201    dictionary->SetBoolean(available_locales[i], true);
202  return dictionary;
203}
204
205base::DictionaryValue*
206LanguageOptionsHandlerCommon::GetSpellCheckLanguageCodeSet() {
207  base::DictionaryValue* dictionary = new base::DictionaryValue();
208  std::vector<std::string> spell_check_languages;
209  chrome::spellcheck_common::SpellCheckLanguages(&spell_check_languages);
210  for (size_t i = 0; i < spell_check_languages.size(); ++i) {
211    dictionary->SetBoolean(spell_check_languages[i], true);
212  }
213  return dictionary;
214}
215
216void LanguageOptionsHandlerCommon::LanguageOptionsOpenCallback(
217    const base::ListValue* args) {
218  content::RecordAction(UserMetricsAction("LanguageOptions_Open"));
219  RefreshHunspellDictionary();
220  if (hunspell_dictionary_->IsDownloadInProgress())
221    OnHunspellDictionaryDownloadBegin();
222  else if (hunspell_dictionary_->IsDownloadFailure())
223    OnHunspellDictionaryDownloadFailure();
224  else
225    OnHunspellDictionaryDownloadSuccess();
226}
227
228void LanguageOptionsHandlerCommon::UiLanguageChangeCallback(
229    const base::ListValue* args) {
230  const std::string language_code =
231      base::UTF16ToASCII(ExtractStringValue(args));
232  CHECK(!language_code.empty());
233  const std::string action = base::StringPrintf(
234      "LanguageOptions_UiLanguageChange_%s", language_code.c_str());
235  content::RecordComputedAction(action);
236  SetApplicationLocale(language_code);
237  base::StringValue language_value(language_code);
238  web_ui()->CallJavascriptFunction("options.LanguageOptions.uiLanguageSaved",
239                                   language_value);
240}
241
242void LanguageOptionsHandlerCommon::SpellCheckLanguageChangeCallback(
243    const base::ListValue* args) {
244  const std::string language_code =
245      base::UTF16ToASCII(ExtractStringValue(args));
246  CHECK(!language_code.empty());
247  const std::string action = base::StringPrintf(
248      "LanguageOptions_SpellCheckLanguageChange_%s", language_code.c_str());
249  content::RecordComputedAction(action);
250  RefreshHunspellDictionary();
251}
252
253void LanguageOptionsHandlerCommon::UpdateLanguageListCallback(
254    const base::ListValue* args) {
255  CHECK_EQ(args->GetSize(), 1u);
256  const base::ListValue* language_list;
257  args->GetList(0, &language_list);
258  DCHECK(language_list);
259
260  std::vector<std::string> languages;
261  for (base::ListValue::const_iterator it = language_list->begin();
262       it != language_list->end(); ++it) {
263    std::string lang;
264    (*it)->GetAsString(&lang);
265    languages.push_back(lang);
266  }
267
268  Profile* profile = Profile::FromWebUI(web_ui());
269  scoped_ptr<translate::TranslatePrefs> translate_prefs =
270      ChromeTranslateClient::CreateTranslatePrefs(profile->GetPrefs());
271  translate_prefs->UpdateLanguageList(languages);
272}
273
274void LanguageOptionsHandlerCommon::RetrySpellcheckDictionaryDownload(
275    const base::ListValue* args) {
276  GetHunspellDictionary()->RetryDownloadDictionary(
277      Profile::FromWebUI(web_ui())->GetRequestContext());
278}
279
280void LanguageOptionsHandlerCommon::RefreshHunspellDictionary() {
281  if (hunspell_dictionary_.get())
282    hunspell_dictionary_->RemoveObserver(this);
283  hunspell_dictionary_.reset();
284  SpellcheckService* service = SpellcheckServiceFactory::GetForContext(
285      Profile::FromWebUI(web_ui()));
286  hunspell_dictionary_ = service->GetHunspellDictionary()->AsWeakPtr();
287  hunspell_dictionary_->AddObserver(this);
288}
289
290base::WeakPtr<SpellcheckHunspellDictionary>&
291    LanguageOptionsHandlerCommon::GetHunspellDictionary() {
292  if (!hunspell_dictionary_.get())
293    RefreshHunspellDictionary();
294  return hunspell_dictionary_;
295}
296
297}  // namespace options
298