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/common/spellcheck_common.h"
6
7#include "base/files/file_path.h"
8#include "base/logging.h"
9#include "third_party/icu/source/common/unicode/uloc.h"
10
11namespace chrome {
12namespace spellcheck_common {
13
14struct LanguageRegion {
15  const char* language;  // The language.
16  const char* language_region;  // language & region, used by dictionaries.
17};
18
19struct LanguageVersion {
20  const char* language;  // The language input.
21  const char* version;   // The corresponding version.
22};
23
24static const LanguageRegion g_supported_spellchecker_languages[] = {
25  // Several languages are not to be included in the spellchecker list:
26  // th-TH, vi-VI.
27  {"af", "af-ZA"},
28  {"bg", "bg-BG"},
29  {"ca", "ca-ES"},
30  {"cs", "cs-CZ"},
31  {"da", "da-DK"},
32  {"de", "de-DE"},
33  {"el", "el-GR"},
34  {"en-AU", "en-AU"},
35  {"en-CA", "en-CA"},
36  {"en-GB", "en-GB"},
37  {"en-US", "en-US"},
38  {"es", "es-ES"},
39  {"et", "et-EE"},
40  {"fo", "fo-FO"},
41  {"fr", "fr-FR"},
42  {"he", "he-IL"},
43  {"hi", "hi-IN"},
44  {"hr", "hr-HR"},
45  {"hu", "hu-HU"},
46  {"id", "id-ID"},
47  {"it", "it-IT"},
48  {"ko", "ko"},
49  {"lt", "lt-LT"},
50  {"lv", "lv-LV"},
51  {"nb", "nb-NO"},
52  {"nl", "nl-NL"},
53  {"pl", "pl-PL"},
54  {"pt-BR", "pt-BR"},
55  {"pt-PT", "pt-PT"},
56  {"ro", "ro-RO"},
57  {"ru", "ru-RU"},
58  {"sh", "sh"},
59  {"sk", "sk-SK"},
60  {"sl", "sl-SI"},
61  {"sq", "sq"},
62  {"sr", "sr"},
63  {"sv", "sv-SE"},
64  {"ta", "ta-IN"},
65  {"tg", "tg-TG"},
66  {"tr", "tr-TR"},
67  {"uk", "uk-UA"},
68  {"vi", "vi-VN"},
69};
70
71bool IsValidRegion(const std::string& region) {
72  for (size_t i = 0; i < arraysize(g_supported_spellchecker_languages);
73       ++i) {
74    if (g_supported_spellchecker_languages[i].language_region == region)
75      return true;
76  }
77  return false;
78}
79
80// This function returns the language-region version of language name.
81// e.g. returns hi-IN for hi.
82std::string GetSpellCheckLanguageRegion(const std::string& input_language) {
83  for (size_t i = 0; i < arraysize(g_supported_spellchecker_languages);
84       ++i) {
85    if (g_supported_spellchecker_languages[i].language == input_language) {
86      return std::string(
87          g_supported_spellchecker_languages[i].language_region);
88    }
89  }
90
91  return input_language;
92}
93
94base::FilePath GetVersionedFileName(const std::string& input_language,
95                                    const base::FilePath& dict_dir) {
96  // The default dictionary version is 3-0. This version indicates that the bdic
97  // file contains a checksum.
98  static const char kDefaultVersionString[] = "-3-0";
99
100  // Add non-default version strings here. Use the same version for all the
101  // dictionaries that you add at the same time. Increment the major version
102  // number if you're updating either dic or aff files. Increment the minor
103  // version number if you're updating only dic_delta files.
104  static LanguageVersion special_version_string[] = {
105    {"tr-TR", "-4-0"},  // Jan 9, 2013: Add "FLAG num" to aff to avoid heapcheck
106                        // crash.
107    {"tg-TG", "-5-0"},  // Mar 4, 2014: Add Tajik dictionary.
108  };
109
110  // Generate the bdict file name using default version string or special
111  // version string, depending on the language.
112  std::string language = GetSpellCheckLanguageRegion(input_language);
113  std::string versioned_bdict_file_name(language + kDefaultVersionString +
114                                        ".bdic");
115  for (size_t i = 0; i < arraysize(special_version_string); ++i) {
116    if (language == special_version_string[i].language) {
117      versioned_bdict_file_name =
118          language + special_version_string[i].version + ".bdic";
119      break;
120    }
121  }
122
123  return dict_dir.AppendASCII(versioned_bdict_file_name);
124}
125
126std::string GetCorrespondingSpellCheckLanguage(const std::string& language) {
127  // Look for exact match in the Spell Check language list.
128  for (size_t i = 0; i < arraysize(g_supported_spellchecker_languages);
129       ++i) {
130    // First look for exact match in the language region of the list.
131    std::string spellcheck_language(
132        g_supported_spellchecker_languages[i].language);
133    if (spellcheck_language == language)
134      return language;
135
136    // Next, look for exact match in the language_region part of the list.
137    std::string spellcheck_language_region(
138        g_supported_spellchecker_languages[i].language_region);
139    if (spellcheck_language_region == language)
140      return g_supported_spellchecker_languages[i].language;
141  }
142
143  // No match found - return blank.
144  return std::string();
145}
146
147void SpellCheckLanguages(std::vector<std::string>* languages) {
148  for (size_t i = 0; i < arraysize(g_supported_spellchecker_languages);
149       ++i) {
150    languages->push_back(g_supported_spellchecker_languages[i].language);
151  }
152}
153
154void GetISOLanguageCountryCodeFromLocale(const std::string& locale,
155                                         std::string* language_code,
156                                         std::string* country_code) {
157  DCHECK(language_code);
158  DCHECK(country_code);
159  char language[ULOC_LANG_CAPACITY] = ULOC_ENGLISH;
160  const char* country = "USA";
161  if (!locale.empty()) {
162    UErrorCode error = U_ZERO_ERROR;
163    char id[ULOC_LANG_CAPACITY + ULOC_SCRIPT_CAPACITY + ULOC_COUNTRY_CAPACITY];
164    uloc_addLikelySubtags(locale.c_str(), id, arraysize(id), &error);
165    error = U_ZERO_ERROR;
166    uloc_getLanguage(id, language, arraysize(language), &error);
167    country = uloc_getISO3Country(id);
168  }
169  *language_code = std::string(language);
170  *country_code = std::string(country);
171}
172
173}  // namespace spellcheck_common
174}  // namespace chrome
175