Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(585)

Side by Side Diff: src/extensions/experimental/language-matcher.cc

Issue 6932007: Revert r7768 (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/extensions/experimental/language-matcher.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 // TODO(cira): Remove LanguageMatcher from v8 when ICU implements
29 // language matching API.
30
31 #include "language-matcher.h"
32
33 #include "platform.h"
34 #include "unicode/datefmt.h" // For getAvailableLocales
35 #include "unicode/locid.h"
36 #include "unicode/uloc.h"
37 #include "utils.h"
38
39 namespace v8 {
40 namespace internal {
41
42 const unsigned int LanguageMatcher::kLanguageWeight = 75;
43 const unsigned int LanguageMatcher::kScriptWeight = 20;
44 const unsigned int LanguageMatcher::kRegionWeight = 5;
45 const unsigned int LanguageMatcher::kThreshold = 50;
46 const unsigned int LanguageMatcher::kPositionBonus = 1;
47 const char* const LanguageMatcher::kDefaultLocale = "root";
48
49 static const char* GetLanguageException(const char*);
50 static void BCP47ToICUFormat(v8::Handle<v8::String>, char*);
51 static int CompareLocaleSubtags(const char*, const char*);
52 static bool BuildLocaleName(const char*, const char*, LocaleIDMatch*);
53
54 LocaleIDMatch::LocaleIDMatch()
55 : score(-1) {
56 OS::SNPrintF(Vector<char>(bcp47_id, ULOC_FULLNAME_CAPACITY),
57 "%s", LanguageMatcher::kDefaultLocale);
58 OS::SNPrintF(Vector<char>(icu_id, ULOC_FULLNAME_CAPACITY),
59 "%s", LanguageMatcher::kDefaultLocale);
60 }
61
62 LocaleIDMatch& LocaleIDMatch::operator=(const LocaleIDMatch& rhs) {
63 OS::SNPrintF(Vector<char>(this->bcp47_id, ULOC_FULLNAME_CAPACITY),
64 "%s", rhs.bcp47_id);
65 OS::SNPrintF(Vector<char>(this->icu_id, ULOC_FULLNAME_CAPACITY),
66 "%s", rhs.icu_id);
67 this->score = rhs.score;
68
69 return *this;
70 }
71
72 // static
73 void LanguageMatcher::GetBestMatchForPriorityList(
74 v8::Handle<v8::Array> locales, LocaleIDMatch* result) {
75 v8::HandleScope handle_scope;
76
77 unsigned int position_bonus = locales->Length() * kPositionBonus;
78
79 int max_score = 0;
80 LocaleIDMatch match;
81 for (unsigned int i = 0; i < locales->Length(); ++i) {
82 position_bonus -= kPositionBonus;
83
84 v8::TryCatch try_catch;
85 v8::Local<v8::Value> locale_id = locales->Get(v8::Integer::New(i));
86
87 // Return default if exception is raised when reading parameter.
88 if (try_catch.HasCaught()) break;
89
90 // JavaScript arrays can be heterogenous so check each item
91 // if it's a string.
92 if (!locale_id->IsString()) continue;
93
94 if (!CompareToSupportedLocaleIDList(locale_id->ToString(), &match)) {
95 continue;
96 }
97
98 // Skip items under threshold.
99 if (match.score < kThreshold) continue;
100
101 match.score += position_bonus;
102 if (match.score > max_score) {
103 *result = match;
104
105 max_score = match.score;
106 }
107 }
108 }
109
110 // static
111 void LanguageMatcher::GetBestMatchForString(
112 v8::Handle<v8::String> locale, LocaleIDMatch* result) {
113 LocaleIDMatch match;
114
115 if (CompareToSupportedLocaleIDList(locale, &match) &&
116 match.score >= kThreshold) {
117 *result = match;
118 }
119 }
120
121 // static
122 bool LanguageMatcher::CompareToSupportedLocaleIDList(
123 v8::Handle<v8::String> locale_id, LocaleIDMatch* result) {
124 static int32_t available_count = 0;
125 // Depending on how ICU data is built, locales returned by
126 // Locale::getAvailableLocale() are not guaranteed to support DateFormat,
127 // Collation and other services. We can call getAvailableLocale() of all the
128 // services we want to support and take the intersection of them all, but
129 // using DateFormat::getAvailableLocales() should suffice.
130 // TODO(cira): Maybe make this thread-safe?
131 static const icu::Locale* available_locales =
132 icu::DateFormat::getAvailableLocales(available_count);
133
134 // Skip this locale_id if it's not in ASCII.
135 static LocaleIDMatch default_match;
136 v8::String::AsciiValue is_ascii(locale_id);
137 if (*is_ascii == NULL) {
138 *result = default_match;
139 return true;
140 }
141
142 char locale[ULOC_FULLNAME_CAPACITY];
143 BCP47ToICUFormat(locale_id, locale);
144 icu::Locale input_locale(locale);
145
146 // Position of the best match locale in list of available locales.
147 int position = -1;
148 result->score = 0;
149 const char* language = GetLanguageException(input_locale.getLanguage());
150 const char* script = input_locale.getScript();
151 const char* region = input_locale.getCountry();
152 for (int32_t i = 0; i < available_count; ++i) {
153 int current_score = 0;
154 int sign =
155 CompareLocaleSubtags(language, available_locales[i].getLanguage());
156 current_score += sign * kLanguageWeight;
157
158 sign = CompareLocaleSubtags(script, available_locales[i].getScript());
159 current_score += sign * kScriptWeight;
160
161 sign = CompareLocaleSubtags(region, available_locales[i].getCountry());
162 current_score += sign * kRegionWeight;
163
164 if (current_score > result->score) {
165 result->score = current_score;
166 position = i;
167 }
168 }
169
170 if (result->score < kThreshold || position == -1) {
171 *result = default_match;
172 return true;
173 }
174
175 return BuildLocaleName(available_locales[position].getBaseName(),
176 input_locale.getName(), result);
177 }
178
179 // For some unsupported language subtags it is better to fallback to related
180 // language that is supported than to default.
181 static const char* GetLanguageException(const char* language) {
182 // Serbo-croatian to Serbian.
183 if (!strcmp(language, "sh")) return "sr";
184
185 // Norweigan to Norweiaan to Norwegian Bokmal.
186 if (!strcmp(language, "no")) return "nb";
187
188 // Moldavian to Romanian.
189 if (!strcmp(language, "mo")) return "ro";
190
191 // Tagalog to Filipino.
192 if (!strcmp(language, "tl")) return "fil";
193
194 return language;
195 }
196
197 // Converts user input from BCP47 locale id format to ICU compatible format.
198 static void BCP47ToICUFormat(v8::Handle<v8::String> locale_id, char* locale) {
199 UErrorCode status = U_ZERO_ERROR;
200 int32_t locale_size = 0;
201 uloc_forLanguageTag(*v8::String::Utf8Value(locale_id), locale,
202 ULOC_FULLNAME_CAPACITY, &locale_size, &status);
203 }
204
205 // Compares locale id subtags.
206 // Returns 1 for match or -1 for mismatch.
207 static int CompareLocaleSubtags(const char* lsubtag, const char* rsubtag) {
208 return strcmp(lsubtag, rsubtag) == 0 ? 1 : -1;
209 }
210
211 // Builds a BCP47 compliant locale id from base name of matched locale and
212 // full user specified locale.
213 // Returns false if uloc_toLanguageTag failed to convert locale id.
214 // Example:
215 // base_name of matched locale (ICU ID): de_DE
216 // input_locale_name (ICU ID): de_AT@collation=phonebk
217 // result (ICU ID): de_DE@collation=phonebk
218 // result (BCP47 ID): de-DE-u-co-phonebk
219 static bool BuildLocaleName(const char* base_name,
220 const char* input_locale_name,
221 LocaleIDMatch* result) {
222 // Get extensions (if any) from the original locale.
223 const char* extension = strchr(input_locale_name, ULOC_KEYWORD_SEPARATOR);
224 if (extension != NULL) {
225 OS::SNPrintF(Vector<char>(result->icu_id, ULOC_FULLNAME_CAPACITY),
226 "%s%s", base_name, extension);
227 } else {
228 OS::SNPrintF(Vector<char>(result->icu_id, ULOC_FULLNAME_CAPACITY),
229 "%s", base_name);
230 }
231
232 // Convert ICU locale name into BCP47 format.
233 UErrorCode status = U_ZERO_ERROR;
234 uloc_toLanguageTag(result->icu_id, result->bcp47_id,
235 ULOC_FULLNAME_CAPACITY, false, &status);
236 return !U_FAILURE(status);
237 }
238
239 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/extensions/experimental/language-matcher.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698