1 // Copyright (c) 2011 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/file_path.h"
8
9 namespace SpellCheckCommon {
10
11 static const struct {
12 // The language.
13 const char* language;
14
15 // The corresponding language and region, used by the dictionaries.
16 const char* language_region;
17 } g_supported_spellchecker_languages[] = {
18 // Several languages are not to be included in the spellchecker list:
19 // th-TH, uk-UA
20 {"bg", "bg-BG"},
21 {"ca", "ca-ES"},
22 {"cs", "cs-CZ"},
23 {"da", "da-DK"},
24 {"de", "de-DE"},
25 {"el", "el-GR"},
26 {"en-AU", "en-AU"},
27 {"en-CA", "en-CA"},
28 {"en-GB", "en-GB"},
29 {"en-US", "en-US"},
30 {"es", "es-ES"},
31 {"et", "et-EE"},
32 {"fr", "fr-FR"},
33 {"he", "he-IL"},
34 {"hi", "hi-IN"},
35 {"hr", "hr-HR"},
36 {"hu", "hu-HU"},
37 {"id", "id-ID"},
38 {"it", "it-IT"},
39 {"lt", "lt-LT"},
40 {"lv", "lv-LV"},
41 {"nb", "nb-NO"},
42 {"nl", "nl-NL"},
43 {"pl", "pl-PL"},
44 {"pt-BR", "pt-BR"},
45 {"pt-PT", "pt-PT"},
46 {"ro", "ro-RO"},
47 {"ru", "ru-RU"},
48 {"sk", "sk-SK"},
49 {"sl", "sl-SI"},
50 {"sh", "sh"},
51 {"sr", "sr"},
52 {"sv", "sv-SE"},
53 {"tr", "tr-TR"},
54 {"uk", "uk-UA"},
55 {"vi", "vi-VN"},
56 };
57
58 // This function returns the language-region version of language name.
59 // e.g. returns hi-IN for hi.
GetSpellCheckLanguageRegion(const std::string & input_language)60 std::string GetSpellCheckLanguageRegion(const std::string& input_language) {
61 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages);
62 ++i) {
63 if (g_supported_spellchecker_languages[i].language == input_language) {
64 return std::string(
65 g_supported_spellchecker_languages[i].language_region);
66 }
67 }
68
69 return input_language;
70 }
71
GetVersionedFileName(const std::string & input_language,const FilePath & dict_dir)72 FilePath GetVersionedFileName(const std::string& input_language,
73 const FilePath& dict_dir) {
74 // The default dictionary version is 1-2. These versions have been augmented
75 // with additional words found by the translation team.
76 static const char kDefaultVersionString[] = "-1-2";
77
78 static const struct {
79 // The language input.
80 const char* language;
81
82 // The corresponding version.
83 const char* version;
84 } special_version_string[] = {
85 {"es-ES", "-1-1"}, // 1-1: Have not been augmented with addtional words.
86 {"nl-NL", "-1-1"},
87 {"sv-SE", "-1-1"},
88 {"he-IL", "-1-1"},
89 {"el-GR", "-1-1"},
90 {"hi-IN", "-1-1"},
91 {"tr-TR", "-1-1"},
92 {"et-EE", "-1-1"},
93 {"lt-LT", "-1-3"}, // 1-3 (Feb 2009): new words, as well as an upgraded
94 // dictionary.
95 {"pl-PL", "-1-3"},
96 {"fr-FR", "-2-0"}, // 2-0 (2010): upgraded dictionaries.
97 {"hu-HU", "-2-0"},
98 {"ro-RO", "-2-0"},
99 {"ru-RU", "-2-0"},
100 {"bg-BG", "-2-0"},
101 {"sr", "-2-0"},
102 {"uk-UA", "-2-0"},
103 {"en-US", "-2-1"}, // 2-1 (Mar 2011): upgraded dictionaries.
104 {"en-CA", "-2-1"},
105 {"pt-BR", "-2-2"}, // 2-2 (Mar 2011): upgraded a dictionary.
106 {"sh", "-2-2"}, // 2-2 (Mar 2011): added a dictionary.
107 };
108
109 // Generate the bdict file name using default version string or special
110 // version string, depending on the language.
111 std::string language = GetSpellCheckLanguageRegion(input_language);
112 std::string versioned_bdict_file_name(language + kDefaultVersionString +
113 ".bdic");
114 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(special_version_string); ++i) {
115 if (language == special_version_string[i].language) {
116 versioned_bdict_file_name =
117 language + special_version_string[i].version + ".bdic";
118 break;
119 }
120 }
121
122 return dict_dir.AppendASCII(versioned_bdict_file_name);
123 }
124
GetCorrespondingSpellCheckLanguage(const std::string & language)125 std::string GetCorrespondingSpellCheckLanguage(const std::string& language) {
126 // Look for exact match in the Spell Check language list.
127 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages);
128 ++i) {
129 // First look for exact match in the language region of the list.
130 std::string spellcheck_language(
131 g_supported_spellchecker_languages[i].language);
132 if (spellcheck_language == language)
133 return language;
134
135 // Next, look for exact match in the language_region part of the list.
136 std::string spellcheck_language_region(
137 g_supported_spellchecker_languages[i].language_region);
138 if (spellcheck_language_region == language)
139 return g_supported_spellchecker_languages[i].language;
140 }
141
142 // Look for a match by comparing only language parts. All the 'en-RR'
143 // except for 'en-GB' exactly matched in the above loop, will match
144 // 'en-US'. This is not ideal because 'en-ZA', 'en-NZ' had
145 // better be matched with 'en-GB'. This does not handle cases like
146 // 'az-Latn-AZ' vs 'az-Arab-AZ', either, but we don't use 3-part
147 // locale ids with a script code in the middle, yet.
148 // TODO(jungshik): Add a better fallback.
149 std::string language_part(language, 0, language.find('-'));
150 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages);
151 ++i) {
152 std::string spellcheck_language(
153 g_supported_spellchecker_languages[i].language_region);
154 if (spellcheck_language.substr(0, spellcheck_language.find('-')) ==
155 language_part) {
156 return spellcheck_language;
157 }
158 }
159
160 // No match found - return blank.
161 return std::string();
162 }
163
164
SpellCheckLanguages(std::vector<std::string> * languages)165 void SpellCheckLanguages(std::vector<std::string>* languages) {
166 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages);
167 ++i) {
168 languages->push_back(g_supported_spellchecker_languages[i].language);
169 }
170 }
171
172 } // namespace SpellCheckCommon
173