blob: dbff6e5f520e048d72e63effd33852b087f3a729 [file] [log] [blame]
danno@chromium.org59400602013-08-13 17:09:37 +00001// Copyright 2013 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// limitations under the License.
28
29#include "i18n.h"
30
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000031#include "unicode/brkiter.h"
danno@chromium.org59400602013-08-13 17:09:37 +000032#include "unicode/calendar.h"
33#include "unicode/coll.h"
34#include "unicode/curramt.h"
35#include "unicode/dcfmtsym.h"
36#include "unicode/decimfmt.h"
37#include "unicode/dtfmtsym.h"
38#include "unicode/dtptngen.h"
39#include "unicode/locid.h"
40#include "unicode/numfmt.h"
41#include "unicode/numsys.h"
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000042#include "unicode/rbbi.h"
danno@chromium.org59400602013-08-13 17:09:37 +000043#include "unicode/smpdtfmt.h"
44#include "unicode/timezone.h"
45#include "unicode/uchar.h"
46#include "unicode/ucol.h"
47#include "unicode/ucurr.h"
48#include "unicode/unum.h"
49#include "unicode/uversion.h"
50
51namespace v8 {
52namespace internal {
53
54namespace {
55
56bool ExtractStringSetting(Isolate* isolate,
57 Handle<JSObject> options,
58 const char* key,
59 icu::UnicodeString* setting) {
60 Handle<String> str = isolate->factory()->NewStringFromAscii(CStrVector(key));
61 MaybeObject* maybe_object = options->GetProperty(*str);
62 Object* object;
63 if (maybe_object->ToObject(&object) && object->IsString()) {
64 v8::String::Utf8Value utf8_string(
65 v8::Utils::ToLocal(Handle<String>(String::cast(object))));
66 *setting = icu::UnicodeString::fromUTF8(*utf8_string);
67 return true;
68 }
69 return false;
70}
71
72
73bool ExtractIntegerSetting(Isolate* isolate,
74 Handle<JSObject> options,
75 const char* key,
76 int32_t* value) {
77 Handle<String> str = isolate->factory()->NewStringFromAscii(CStrVector(key));
78 MaybeObject* maybe_object = options->GetProperty(*str);
79 Object* object;
80 if (maybe_object->ToObject(&object) && object->IsNumber()) {
81 object->ToInt32(value);
82 return true;
83 }
84 return false;
85}
86
87
88bool ExtractBooleanSetting(Isolate* isolate,
89 Handle<JSObject> options,
90 const char* key,
91 bool* value) {
92 Handle<String> str = isolate->factory()->NewStringFromAscii(CStrVector(key));
93 MaybeObject* maybe_object = options->GetProperty(*str);
94 Object* object;
95 if (maybe_object->ToObject(&object) && object->IsBoolean()) {
96 *value = object->BooleanValue();
97 return true;
98 }
99 return false;
100}
101
102
103icu::SimpleDateFormat* CreateICUDateFormat(
104 Isolate* isolate,
105 const icu::Locale& icu_locale,
106 Handle<JSObject> options) {
107 // Create time zone as specified by the user. We have to re-create time zone
108 // since calendar takes ownership.
109 icu::TimeZone* tz = NULL;
110 icu::UnicodeString timezone;
111 if (ExtractStringSetting(isolate, options, "timeZone", &timezone)) {
112 tz = icu::TimeZone::createTimeZone(timezone);
113 } else {
114 tz = icu::TimeZone::createDefault();
115 }
116
117 // Create a calendar using locale, and apply time zone to it.
118 UErrorCode status = U_ZERO_ERROR;
119 icu::Calendar* calendar =
120 icu::Calendar::createInstance(tz, icu_locale, status);
121
122 // Make formatter from skeleton. Calendar and numbering system are added
123 // to the locale as Unicode extension (if they were specified at all).
124 icu::SimpleDateFormat* date_format = NULL;
125 icu::UnicodeString skeleton;
126 if (ExtractStringSetting(isolate, options, "skeleton", &skeleton)) {
127 icu::DateTimePatternGenerator* generator =
128 icu::DateTimePatternGenerator::createInstance(icu_locale, status);
129 icu::UnicodeString pattern;
130 if (U_SUCCESS(status)) {
131 pattern = generator->getBestPattern(skeleton, status);
132 delete generator;
133 }
134
135 date_format = new icu::SimpleDateFormat(pattern, icu_locale, status);
136 if (U_SUCCESS(status)) {
137 date_format->adoptCalendar(calendar);
138 }
139 }
140
141 if (U_FAILURE(status)) {
142 delete calendar;
143 delete date_format;
144 date_format = NULL;
145 }
146
147 return date_format;
148}
149
150
151void SetResolvedDateSettings(Isolate* isolate,
152 const icu::Locale& icu_locale,
153 icu::SimpleDateFormat* date_format,
154 Handle<JSObject> resolved) {
155 UErrorCode status = U_ZERO_ERROR;
156 icu::UnicodeString pattern;
157 date_format->toPattern(pattern);
158 JSObject::SetProperty(
159 resolved,
160 isolate->factory()->NewStringFromAscii(CStrVector("pattern")),
161 isolate->factory()->NewStringFromTwoByte(
162 Vector<const uint16_t>(
163 reinterpret_cast<const uint16_t*>(pattern.getBuffer()),
164 pattern.length())),
165 NONE,
166 kNonStrictMode);
167
168 // Set time zone and calendar.
169 const icu::Calendar* calendar = date_format->getCalendar();
170 const char* calendar_name = calendar->getType();
171 JSObject::SetProperty(
172 resolved,
173 isolate->factory()->NewStringFromAscii(CStrVector("calendar")),
174 isolate->factory()->NewStringFromAscii(CStrVector(calendar_name)),
175 NONE,
176 kNonStrictMode);
177
178 const icu::TimeZone& tz = calendar->getTimeZone();
179 icu::UnicodeString time_zone;
180 tz.getID(time_zone);
181
182 icu::UnicodeString canonical_time_zone;
183 icu::TimeZone::getCanonicalID(time_zone, canonical_time_zone, status);
184 if (U_SUCCESS(status)) {
185 if (canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/GMT")) {
186 JSObject::SetProperty(
187 resolved,
188 isolate->factory()->NewStringFromAscii(CStrVector("timeZone")),
189 isolate->factory()->NewStringFromAscii(CStrVector("UTC")),
190 NONE,
191 kNonStrictMode);
192 } else {
193 JSObject::SetProperty(
194 resolved,
195 isolate->factory()->NewStringFromAscii(CStrVector("timeZone")),
196 isolate->factory()->NewStringFromTwoByte(
197 Vector<const uint16_t>(
198 reinterpret_cast<const uint16_t*>(
199 canonical_time_zone.getBuffer()),
200 canonical_time_zone.length())),
201 NONE,
202 kNonStrictMode);
203 }
204 }
205
206 // Ugly hack. ICU doesn't expose numbering system in any way, so we have
207 // to assume that for given locale NumberingSystem constructor produces the
208 // same digits as NumberFormat/Calendar would.
209 status = U_ZERO_ERROR;
210 icu::NumberingSystem* numbering_system =
211 icu::NumberingSystem::createInstance(icu_locale, status);
212 if (U_SUCCESS(status)) {
213 const char* ns = numbering_system->getName();
214 JSObject::SetProperty(
215 resolved,
216 isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")),
217 isolate->factory()->NewStringFromAscii(CStrVector(ns)),
218 NONE,
219 kNonStrictMode);
220 } else {
221 JSObject::SetProperty(
222 resolved,
223 isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")),
224 isolate->factory()->undefined_value(),
225 NONE,
226 kNonStrictMode);
227 }
228 delete numbering_system;
229
230 // Set the locale
231 char result[ULOC_FULLNAME_CAPACITY];
232 status = U_ZERO_ERROR;
233 uloc_toLanguageTag(
234 icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
235 if (U_SUCCESS(status)) {
236 JSObject::SetProperty(
237 resolved,
238 isolate->factory()->NewStringFromAscii(CStrVector("locale")),
239 isolate->factory()->NewStringFromAscii(CStrVector(result)),
240 NONE,
241 kNonStrictMode);
242 } else {
243 // This would never happen, since we got the locale from ICU.
244 JSObject::SetProperty(
245 resolved,
246 isolate->factory()->NewStringFromAscii(CStrVector("locale")),
247 isolate->factory()->NewStringFromAscii(CStrVector("und")),
248 NONE,
249 kNonStrictMode);
250 }
251}
252
253
254template<int internal_fields, EternalHandles::SingletonHandle field>
255Handle<ObjectTemplateInfo> GetEternal(Isolate* isolate) {
256 if (isolate->eternal_handles()->Exists(field)) {
257 return Handle<ObjectTemplateInfo>::cast(
258 isolate->eternal_handles()->GetSingleton(field));
259 }
260 v8::Local<v8::ObjectTemplate> raw_template(v8::ObjectTemplate::New());
261 raw_template->SetInternalFieldCount(internal_fields);
262 return Handle<ObjectTemplateInfo>::cast(
263 isolate->eternal_handles()->CreateSingleton(
264 isolate,
265 *v8::Utils::OpenHandle(*raw_template),
266 field));
267}
268
269
270icu::DecimalFormat* CreateICUNumberFormat(
271 Isolate* isolate,
272 const icu::Locale& icu_locale,
273 Handle<JSObject> options) {
274 // Make formatter from options. Numbering system is added
275 // to the locale as Unicode extension (if it was specified at all).
276 UErrorCode status = U_ZERO_ERROR;
277 icu::DecimalFormat* number_format = NULL;
278 icu::UnicodeString style;
279 icu::UnicodeString currency;
280 if (ExtractStringSetting(isolate, options, "style", &style)) {
281 if (style == UNICODE_STRING_SIMPLE("currency")) {
282 icu::UnicodeString display;
283 ExtractStringSetting(isolate, options, "currency", &currency);
284 ExtractStringSetting(isolate, options, "currencyDisplay", &display);
285
286#if (U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM <= 6)
287 icu::NumberFormat::EStyles format_style;
288 if (display == UNICODE_STRING_SIMPLE("code")) {
289 format_style = icu::NumberFormat::kIsoCurrencyStyle;
290 } else if (display == UNICODE_STRING_SIMPLE("name")) {
291 format_style = icu::NumberFormat::kPluralCurrencyStyle;
292 } else {
293 format_style = icu::NumberFormat::kCurrencyStyle;
294 }
295#else // ICU version is 4.8 or above (we ignore versions below 4.0).
296 UNumberFormatStyle format_style;
297 if (display == UNICODE_STRING_SIMPLE("code")) {
298 format_style = UNUM_CURRENCY_ISO;
299 } else if (display == UNICODE_STRING_SIMPLE("name")) {
300 format_style = UNUM_CURRENCY_PLURAL;
301 } else {
302 format_style = UNUM_CURRENCY;
303 }
304#endif
305
306 number_format = static_cast<icu::DecimalFormat*>(
307 icu::NumberFormat::createInstance(icu_locale, format_style, status));
308 } else if (style == UNICODE_STRING_SIMPLE("percent")) {
309 number_format = static_cast<icu::DecimalFormat*>(
310 icu::NumberFormat::createPercentInstance(icu_locale, status));
311 if (U_FAILURE(status)) {
312 delete number_format;
313 return NULL;
314 }
315 // Make sure 1.1% doesn't go into 2%.
316 number_format->setMinimumFractionDigits(1);
317 } else {
318 // Make a decimal instance by default.
319 number_format = static_cast<icu::DecimalFormat*>(
320 icu::NumberFormat::createInstance(icu_locale, status));
321 }
322 }
323
324 if (U_FAILURE(status)) {
325 delete number_format;
326 return NULL;
327 }
328
329 // Set all options.
330 if (!currency.isEmpty()) {
331 number_format->setCurrency(currency.getBuffer(), status);
332 }
333
334 int32_t digits;
335 if (ExtractIntegerSetting(
336 isolate, options, "minimumIntegerDigits", &digits)) {
337 number_format->setMinimumIntegerDigits(digits);
338 }
339
340 if (ExtractIntegerSetting(
341 isolate, options, "minimumFractionDigits", &digits)) {
342 number_format->setMinimumFractionDigits(digits);
343 }
344
345 if (ExtractIntegerSetting(
346 isolate, options, "maximumFractionDigits", &digits)) {
347 number_format->setMaximumFractionDigits(digits);
348 }
349
350 bool significant_digits_used = false;
351 if (ExtractIntegerSetting(
352 isolate, options, "minimumSignificantDigits", &digits)) {
353 number_format->setMinimumSignificantDigits(digits);
354 significant_digits_used = true;
355 }
356
357 if (ExtractIntegerSetting(
358 isolate, options, "maximumSignificantDigits", &digits)) {
359 number_format->setMaximumSignificantDigits(digits);
360 significant_digits_used = true;
361 }
362
363 number_format->setSignificantDigitsUsed(significant_digits_used);
364
365 bool grouping;
366 if (ExtractBooleanSetting(isolate, options, "useGrouping", &grouping)) {
367 number_format->setGroupingUsed(grouping);
368 }
369
370 // Set rounding mode.
371 number_format->setRoundingMode(icu::DecimalFormat::kRoundHalfUp);
372
373 return number_format;
374}
375
376
377void SetResolvedNumberSettings(Isolate* isolate,
378 const icu::Locale& icu_locale,
379 icu::DecimalFormat* number_format,
380 Handle<JSObject> resolved) {
381 icu::UnicodeString pattern;
382 number_format->toPattern(pattern);
383 JSObject::SetProperty(
384 resolved,
385 isolate->factory()->NewStringFromAscii(CStrVector("pattern")),
386 isolate->factory()->NewStringFromTwoByte(
387 Vector<const uint16_t>(
388 reinterpret_cast<const uint16_t*>(pattern.getBuffer()),
389 pattern.length())),
390 NONE,
391 kNonStrictMode);
392
393 // Set resolved currency code in options.currency if not empty.
394 icu::UnicodeString currency(number_format->getCurrency());
395 if (!currency.isEmpty()) {
396 JSObject::SetProperty(
397 resolved,
398 isolate->factory()->NewStringFromAscii(CStrVector("currency")),
399 isolate->factory()->NewStringFromTwoByte(
400 Vector<const uint16_t>(
401 reinterpret_cast<const uint16_t*>(currency.getBuffer()),
402 currency.length())),
403 NONE,
404 kNonStrictMode);
405 }
406
407 // Ugly hack. ICU doesn't expose numbering system in any way, so we have
408 // to assume that for given locale NumberingSystem constructor produces the
409 // same digits as NumberFormat/Calendar would.
410 UErrorCode status = U_ZERO_ERROR;
411 icu::NumberingSystem* numbering_system =
412 icu::NumberingSystem::createInstance(icu_locale, status);
413 if (U_SUCCESS(status)) {
414 const char* ns = numbering_system->getName();
415 JSObject::SetProperty(
416 resolved,
417 isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")),
418 isolate->factory()->NewStringFromAscii(CStrVector(ns)),
419 NONE,
420 kNonStrictMode);
421 } else {
422 JSObject::SetProperty(
423 resolved,
424 isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")),
425 isolate->factory()->undefined_value(),
426 NONE,
427 kNonStrictMode);
428 }
429 delete numbering_system;
430
431 JSObject::SetProperty(
432 resolved,
433 isolate->factory()->NewStringFromAscii(CStrVector("useGrouping")),
434 isolate->factory()->ToBoolean(number_format->isGroupingUsed()),
435 NONE,
436 kNonStrictMode);
437
438 JSObject::SetProperty(
439 resolved,
440 isolate->factory()->NewStringFromAscii(
441 CStrVector("minimumIntegerDigits")),
442 isolate->factory()->NewNumberFromInt(
443 number_format->getMinimumIntegerDigits()),
444 NONE,
445 kNonStrictMode);
446
447 JSObject::SetProperty(
448 resolved,
449 isolate->factory()->NewStringFromAscii(
450 CStrVector("minimumFractionDigits")),
451 isolate->factory()->NewNumberFromInt(
452 number_format->getMinimumFractionDigits()),
453 NONE,
454 kNonStrictMode);
455
456 JSObject::SetProperty(
457 resolved,
458 isolate->factory()->NewStringFromAscii(
459 CStrVector("maximumFractionDigits")),
460 isolate->factory()->NewNumberFromInt(
461 number_format->getMaximumFractionDigits()),
462 NONE,
463 kNonStrictMode);
464
465 Handle<String> key = isolate->factory()->NewStringFromAscii(
466 CStrVector("minimumSignificantDigits"));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000467 if (JSReceiver::HasLocalProperty(resolved, key)) {
danno@chromium.org59400602013-08-13 17:09:37 +0000468 JSObject::SetProperty(
469 resolved,
470 isolate->factory()->NewStringFromAscii(
471 CStrVector("minimumSignificantDigits")),
472 isolate->factory()->NewNumberFromInt(
473 number_format->getMinimumSignificantDigits()),
474 NONE,
475 kNonStrictMode);
476 }
477
478 key = isolate->factory()->NewStringFromAscii(
479 CStrVector("maximumSignificantDigits"));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000480 if (JSReceiver::HasLocalProperty(resolved, key)) {
danno@chromium.org59400602013-08-13 17:09:37 +0000481 JSObject::SetProperty(
482 resolved,
483 isolate->factory()->NewStringFromAscii(
484 CStrVector("maximumSignificantDigits")),
485 isolate->factory()->NewNumberFromInt(
486 number_format->getMaximumSignificantDigits()),
487 NONE,
488 kNonStrictMode);
489 }
490
491 // Set the locale
492 char result[ULOC_FULLNAME_CAPACITY];
493 status = U_ZERO_ERROR;
494 uloc_toLanguageTag(
495 icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
496 if (U_SUCCESS(status)) {
497 JSObject::SetProperty(
498 resolved,
499 isolate->factory()->NewStringFromAscii(CStrVector("locale")),
500 isolate->factory()->NewStringFromAscii(CStrVector(result)),
501 NONE,
502 kNonStrictMode);
503 } else {
504 // This would never happen, since we got the locale from ICU.
505 JSObject::SetProperty(
506 resolved,
507 isolate->factory()->NewStringFromAscii(CStrVector("locale")),
508 isolate->factory()->NewStringFromAscii(CStrVector("und")),
509 NONE,
510 kNonStrictMode);
511 }
512}
513
514
515icu::Collator* CreateICUCollator(
516 Isolate* isolate,
517 const icu::Locale& icu_locale,
518 Handle<JSObject> options) {
519 // Make collator from options.
520 icu::Collator* collator = NULL;
521 UErrorCode status = U_ZERO_ERROR;
522 collator = icu::Collator::createInstance(icu_locale, status);
523
524 if (U_FAILURE(status)) {
525 delete collator;
526 return NULL;
527 }
528
529 // Set flags first, and then override them with sensitivity if necessary.
530 bool numeric;
531 if (ExtractBooleanSetting(isolate, options, "numeric", &numeric)) {
532 collator->setAttribute(
533 UCOL_NUMERIC_COLLATION, numeric ? UCOL_ON : UCOL_OFF, status);
534 }
535
536 // Normalization is always on, by the spec. We are free to optimize
537 // if the strings are already normalized (but we don't have a way to tell
538 // that right now).
539 collator->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
540
541 icu::UnicodeString case_first;
542 if (ExtractStringSetting(isolate, options, "caseFirst", &case_first)) {
543 if (case_first == UNICODE_STRING_SIMPLE("upper")) {
544 collator->setAttribute(UCOL_CASE_FIRST, UCOL_UPPER_FIRST, status);
545 } else if (case_first == UNICODE_STRING_SIMPLE("lower")) {
546 collator->setAttribute(UCOL_CASE_FIRST, UCOL_LOWER_FIRST, status);
547 } else {
548 // Default (false/off).
549 collator->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status);
550 }
551 }
552
553 icu::UnicodeString sensitivity;
554 if (ExtractStringSetting(isolate, options, "sensitivity", &sensitivity)) {
555 if (sensitivity == UNICODE_STRING_SIMPLE("base")) {
556 collator->setStrength(icu::Collator::PRIMARY);
557 } else if (sensitivity == UNICODE_STRING_SIMPLE("accent")) {
558 collator->setStrength(icu::Collator::SECONDARY);
559 } else if (sensitivity == UNICODE_STRING_SIMPLE("case")) {
560 collator->setStrength(icu::Collator::PRIMARY);
561 collator->setAttribute(UCOL_CASE_LEVEL, UCOL_ON, status);
562 } else {
563 // variant (default)
564 collator->setStrength(icu::Collator::TERTIARY);
565 }
566 }
567
568 bool ignore;
569 if (ExtractBooleanSetting(isolate, options, "ignorePunctuation", &ignore)) {
570 if (ignore) {
571 collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, status);
572 }
573 }
574
575 return collator;
576}
577
578
579void SetResolvedCollatorSettings(Isolate* isolate,
580 const icu::Locale& icu_locale,
581 icu::Collator* collator,
582 Handle<JSObject> resolved) {
583 UErrorCode status = U_ZERO_ERROR;
584
585 JSObject::SetProperty(
586 resolved,
587 isolate->factory()->NewStringFromAscii(CStrVector("numeric")),
588 isolate->factory()->ToBoolean(
589 collator->getAttribute(UCOL_NUMERIC_COLLATION, status) == UCOL_ON),
590 NONE,
591 kNonStrictMode);
592
593 switch (collator->getAttribute(UCOL_CASE_FIRST, status)) {
594 case UCOL_LOWER_FIRST:
595 JSObject::SetProperty(
596 resolved,
597 isolate->factory()->NewStringFromAscii(CStrVector("caseFirst")),
598 isolate->factory()->NewStringFromAscii(CStrVector("lower")),
599 NONE,
600 kNonStrictMode);
601 break;
602 case UCOL_UPPER_FIRST:
603 JSObject::SetProperty(
604 resolved,
605 isolate->factory()->NewStringFromAscii(CStrVector("caseFirst")),
606 isolate->factory()->NewStringFromAscii(CStrVector("upper")),
607 NONE,
608 kNonStrictMode);
609 break;
610 default:
611 JSObject::SetProperty(
612 resolved,
613 isolate->factory()->NewStringFromAscii(CStrVector("caseFirst")),
614 isolate->factory()->NewStringFromAscii(CStrVector("false")),
615 NONE,
616 kNonStrictMode);
617 }
618
619 switch (collator->getAttribute(UCOL_STRENGTH, status)) {
620 case UCOL_PRIMARY: {
621 JSObject::SetProperty(
622 resolved,
623 isolate->factory()->NewStringFromAscii(CStrVector("strength")),
624 isolate->factory()->NewStringFromAscii(CStrVector("primary")),
625 NONE,
626 kNonStrictMode);
627
628 // case level: true + s1 -> case, s1 -> base.
629 if (UCOL_ON == collator->getAttribute(UCOL_CASE_LEVEL, status)) {
630 JSObject::SetProperty(
631 resolved,
632 isolate->factory()->NewStringFromAscii(CStrVector("sensitivity")),
633 isolate->factory()->NewStringFromAscii(CStrVector("case")),
634 NONE,
635 kNonStrictMode);
636 } else {
637 JSObject::SetProperty(
638 resolved,
639 isolate->factory()->NewStringFromAscii(CStrVector("sensitivity")),
640 isolate->factory()->NewStringFromAscii(CStrVector("base")),
641 NONE,
642 kNonStrictMode);
643 }
644 break;
645 }
646 case UCOL_SECONDARY:
647 JSObject::SetProperty(
648 resolved,
649 isolate->factory()->NewStringFromAscii(CStrVector("strength")),
650 isolate->factory()->NewStringFromAscii(CStrVector("secondary")),
651 NONE,
652 kNonStrictMode);
653 JSObject::SetProperty(
654 resolved,
655 isolate->factory()->NewStringFromAscii(CStrVector("sensitivity")),
656 isolate->factory()->NewStringFromAscii(CStrVector("accent")),
657 NONE,
658 kNonStrictMode);
659 break;
660 case UCOL_TERTIARY:
661 JSObject::SetProperty(
662 resolved,
663 isolate->factory()->NewStringFromAscii(CStrVector("strength")),
664 isolate->factory()->NewStringFromAscii(CStrVector("tertiary")),
665 NONE,
666 kNonStrictMode);
667 JSObject::SetProperty(
668 resolved,
669 isolate->factory()->NewStringFromAscii(CStrVector("sensitivity")),
670 isolate->factory()->NewStringFromAscii(CStrVector("variant")),
671 NONE,
672 kNonStrictMode);
673 break;
674 case UCOL_QUATERNARY:
675 // We shouldn't get quaternary and identical from ICU, but if we do
676 // put them into variant.
677 JSObject::SetProperty(
678 resolved,
679 isolate->factory()->NewStringFromAscii(CStrVector("strength")),
680 isolate->factory()->NewStringFromAscii(CStrVector("quaternary")),
681 NONE,
682 kNonStrictMode);
683 JSObject::SetProperty(
684 resolved,
685 isolate->factory()->NewStringFromAscii(CStrVector("sensitivity")),
686 isolate->factory()->NewStringFromAscii(CStrVector("variant")),
687 NONE,
688 kNonStrictMode);
689 break;
690 default:
691 JSObject::SetProperty(
692 resolved,
693 isolate->factory()->NewStringFromAscii(CStrVector("strength")),
694 isolate->factory()->NewStringFromAscii(CStrVector("identical")),
695 NONE,
696 kNonStrictMode);
697 JSObject::SetProperty(
698 resolved,
699 isolate->factory()->NewStringFromAscii(CStrVector("sensitivity")),
700 isolate->factory()->NewStringFromAscii(CStrVector("variant")),
701 NONE,
702 kNonStrictMode);
703 }
704
705 JSObject::SetProperty(
706 resolved,
707 isolate->factory()->NewStringFromAscii(CStrVector("ignorePunctuation")),
708 isolate->factory()->ToBoolean(collator->getAttribute(
709 UCOL_ALTERNATE_HANDLING, status) == UCOL_SHIFTED),
710 NONE,
711 kNonStrictMode);
712
713 // Set the locale
714 char result[ULOC_FULLNAME_CAPACITY];
715 status = U_ZERO_ERROR;
716 uloc_toLanguageTag(
717 icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
718 if (U_SUCCESS(status)) {
719 JSObject::SetProperty(
720 resolved,
721 isolate->factory()->NewStringFromAscii(CStrVector("locale")),
722 isolate->factory()->NewStringFromAscii(CStrVector(result)),
723 NONE,
724 kNonStrictMode);
725 } else {
726 // This would never happen, since we got the locale from ICU.
727 JSObject::SetProperty(
728 resolved,
729 isolate->factory()->NewStringFromAscii(CStrVector("locale")),
730 isolate->factory()->NewStringFromAscii(CStrVector("und")),
731 NONE,
732 kNonStrictMode);
733 }
734}
735
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000736
737icu::BreakIterator* CreateICUBreakIterator(
738 Isolate* isolate,
739 const icu::Locale& icu_locale,
740 Handle<JSObject> options) {
741 UErrorCode status = U_ZERO_ERROR;
742 icu::BreakIterator* break_iterator = NULL;
743 icu::UnicodeString type;
744 if (!ExtractStringSetting(isolate, options, "type", &type)) return NULL;
745
746 if (type == UNICODE_STRING_SIMPLE("character")) {
747 break_iterator =
748 icu::BreakIterator::createCharacterInstance(icu_locale, status);
749 } else if (type == UNICODE_STRING_SIMPLE("sentence")) {
750 break_iterator =
751 icu::BreakIterator::createSentenceInstance(icu_locale, status);
752 } else if (type == UNICODE_STRING_SIMPLE("line")) {
753 break_iterator =
754 icu::BreakIterator::createLineInstance(icu_locale, status);
755 } else {
756 // Defualt is word iterator.
757 break_iterator =
758 icu::BreakIterator::createWordInstance(icu_locale, status);
759 }
760
761 if (U_FAILURE(status)) {
762 delete break_iterator;
763 return NULL;
764 }
765
766 return break_iterator;
767}
768
769
770void SetResolvedBreakIteratorSettings(Isolate* isolate,
771 const icu::Locale& icu_locale,
772 icu::BreakIterator* break_iterator,
773 Handle<JSObject> resolved) {
774 UErrorCode status = U_ZERO_ERROR;
775
776 // Set the locale
777 char result[ULOC_FULLNAME_CAPACITY];
778 status = U_ZERO_ERROR;
779 uloc_toLanguageTag(
780 icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
781 if (U_SUCCESS(status)) {
782 JSObject::SetProperty(
783 resolved,
784 isolate->factory()->NewStringFromAscii(CStrVector("locale")),
785 isolate->factory()->NewStringFromAscii(CStrVector(result)),
786 NONE,
787 kNonStrictMode);
788 } else {
789 // This would never happen, since we got the locale from ICU.
790 JSObject::SetProperty(
791 resolved,
792 isolate->factory()->NewStringFromAscii(CStrVector("locale")),
793 isolate->factory()->NewStringFromAscii(CStrVector("und")),
794 NONE,
795 kNonStrictMode);
796 }
797}
798
danno@chromium.org59400602013-08-13 17:09:37 +0000799} // namespace
800
801
802// static
803Handle<ObjectTemplateInfo> I18N::GetTemplate(Isolate* isolate) {
804 return GetEternal<1, i::EternalHandles::I18N_TEMPLATE_ONE>(isolate);
805}
806
807
808// static
809Handle<ObjectTemplateInfo> I18N::GetTemplate2(Isolate* isolate) {
810 return GetEternal<2, i::EternalHandles::I18N_TEMPLATE_TWO>(isolate);
811}
812
813
814// static
815icu::SimpleDateFormat* DateFormat::InitializeDateTimeFormat(
816 Isolate* isolate,
817 Handle<String> locale,
818 Handle<JSObject> options,
819 Handle<JSObject> resolved) {
820 // Convert BCP47 into ICU locale format.
821 UErrorCode status = U_ZERO_ERROR;
822 icu::Locale icu_locale;
823 char icu_result[ULOC_FULLNAME_CAPACITY];
824 int icu_length = 0;
825 v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale));
826 if (bcp47_locale.length() != 0) {
827 uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
828 &icu_length, &status);
829 if (U_FAILURE(status) || icu_length == 0) {
830 return NULL;
831 }
832 icu_locale = icu::Locale(icu_result);
833 }
834
835 icu::SimpleDateFormat* date_format = CreateICUDateFormat(
836 isolate, icu_locale, options);
837 if (!date_format) {
838 // Remove extensions and try again.
839 icu::Locale no_extension_locale(icu_locale.getBaseName());
840 date_format = CreateICUDateFormat(isolate, no_extension_locale, options);
841
842 // Set resolved settings (pattern, numbering system, calendar).
843 SetResolvedDateSettings(
844 isolate, no_extension_locale, date_format, resolved);
845 } else {
846 SetResolvedDateSettings(isolate, icu_locale, date_format, resolved);
847 }
848
849 return date_format;
850}
851
852
853icu::SimpleDateFormat* DateFormat::UnpackDateFormat(
854 Isolate* isolate,
855 Handle<JSObject> obj) {
856 Handle<String> key =
857 isolate->factory()->NewStringFromAscii(CStrVector("dateFormat"));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000858 if (JSReceiver::HasLocalProperty(obj, key)) {
danno@chromium.org59400602013-08-13 17:09:37 +0000859 return reinterpret_cast<icu::SimpleDateFormat*>(
860 obj->GetInternalField(0));
861 }
862
863 return NULL;
864}
865
866
867void DateFormat::DeleteDateFormat(v8::Isolate* isolate,
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000868 Persistent<v8::Value>* object,
danno@chromium.org59400602013-08-13 17:09:37 +0000869 void* param) {
870 // First delete the hidden C++ object.
871 delete reinterpret_cast<icu::SimpleDateFormat*>(Handle<JSObject>::cast(
872 v8::Utils::OpenPersistent(object))->GetInternalField(0));
873
874 // Then dispose of the persistent handle to JS object.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000875 object->Dispose();
danno@chromium.org59400602013-08-13 17:09:37 +0000876}
877
878
879icu::DecimalFormat* NumberFormat::InitializeNumberFormat(
880 Isolate* isolate,
881 Handle<String> locale,
882 Handle<JSObject> options,
883 Handle<JSObject> resolved) {
884 // Convert BCP47 into ICU locale format.
885 UErrorCode status = U_ZERO_ERROR;
886 icu::Locale icu_locale;
887 char icu_result[ULOC_FULLNAME_CAPACITY];
888 int icu_length = 0;
889 v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale));
890 if (bcp47_locale.length() != 0) {
891 uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
892 &icu_length, &status);
893 if (U_FAILURE(status) || icu_length == 0) {
894 return NULL;
895 }
896 icu_locale = icu::Locale(icu_result);
897 }
898
899 icu::DecimalFormat* number_format =
900 CreateICUNumberFormat(isolate, icu_locale, options);
901 if (!number_format) {
902 // Remove extensions and try again.
903 icu::Locale no_extension_locale(icu_locale.getBaseName());
904 number_format = CreateICUNumberFormat(
905 isolate, no_extension_locale, options);
906
907 // Set resolved settings (pattern, numbering system).
908 SetResolvedNumberSettings(
909 isolate, no_extension_locale, number_format, resolved);
910 } else {
911 SetResolvedNumberSettings(isolate, icu_locale, number_format, resolved);
912 }
913
914 return number_format;
915}
916
917
918icu::DecimalFormat* NumberFormat::UnpackNumberFormat(
919 Isolate* isolate,
920 Handle<JSObject> obj) {
921 Handle<String> key =
922 isolate->factory()->NewStringFromAscii(CStrVector("numberFormat"));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000923 if (JSReceiver::HasLocalProperty(obj, key)) {
danno@chromium.org59400602013-08-13 17:09:37 +0000924 return reinterpret_cast<icu::DecimalFormat*>(obj->GetInternalField(0));
925 }
926
927 return NULL;
928}
929
930
931void NumberFormat::DeleteNumberFormat(v8::Isolate* isolate,
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000932 Persistent<v8::Value>* object,
danno@chromium.org59400602013-08-13 17:09:37 +0000933 void* param) {
934 // First delete the hidden C++ object.
935 delete reinterpret_cast<icu::DecimalFormat*>(Handle<JSObject>::cast(
936 v8::Utils::OpenPersistent(object))->GetInternalField(0));
937
938 // Then dispose of the persistent handle to JS object.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000939 object->Dispose();
danno@chromium.org59400602013-08-13 17:09:37 +0000940}
941
942
943icu::Collator* Collator::InitializeCollator(
944 Isolate* isolate,
945 Handle<String> locale,
946 Handle<JSObject> options,
947 Handle<JSObject> resolved) {
948 // Convert BCP47 into ICU locale format.
949 UErrorCode status = U_ZERO_ERROR;
950 icu::Locale icu_locale;
951 char icu_result[ULOC_FULLNAME_CAPACITY];
952 int icu_length = 0;
953 v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale));
954 if (bcp47_locale.length() != 0) {
955 uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
956 &icu_length, &status);
957 if (U_FAILURE(status) || icu_length == 0) {
958 return NULL;
959 }
960 icu_locale = icu::Locale(icu_result);
961 }
962
963 icu::Collator* collator = CreateICUCollator(isolate, icu_locale, options);
964 if (!collator) {
965 // Remove extensions and try again.
966 icu::Locale no_extension_locale(icu_locale.getBaseName());
967 collator = CreateICUCollator(isolate, no_extension_locale, options);
968
969 // Set resolved settings (pattern, numbering system).
970 SetResolvedCollatorSettings(
971 isolate, no_extension_locale, collator, resolved);
972 } else {
973 SetResolvedCollatorSettings(isolate, icu_locale, collator, resolved);
974 }
975
976 return collator;
977}
978
979
980icu::Collator* Collator::UnpackCollator(Isolate* isolate,
981 Handle<JSObject> obj) {
982 Handle<String> key =
983 isolate->factory()->NewStringFromAscii(CStrVector("collator"));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000984 if (JSReceiver::HasLocalProperty(obj, key)) {
danno@chromium.org59400602013-08-13 17:09:37 +0000985 return reinterpret_cast<icu::Collator*>(obj->GetInternalField(0));
986 }
987
988 return NULL;
989}
990
991
992void Collator::DeleteCollator(v8::Isolate* isolate,
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000993 Persistent<v8::Value>* object,
danno@chromium.org59400602013-08-13 17:09:37 +0000994 void* param) {
995 // First delete the hidden C++ object.
996 delete reinterpret_cast<icu::Collator*>(Handle<JSObject>::cast(
997 v8::Utils::OpenPersistent(object))->GetInternalField(0));
998
999 // Then dispose of the persistent handle to JS object.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001000 object->Dispose();
danno@chromium.org59400602013-08-13 17:09:37 +00001001}
1002
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001003
1004icu::BreakIterator* BreakIterator::InitializeBreakIterator(
1005 Isolate* isolate,
1006 Handle<String> locale,
1007 Handle<JSObject> options,
1008 Handle<JSObject> resolved) {
1009 // Convert BCP47 into ICU locale format.
1010 UErrorCode status = U_ZERO_ERROR;
1011 icu::Locale icu_locale;
1012 char icu_result[ULOC_FULLNAME_CAPACITY];
1013 int icu_length = 0;
1014 v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale));
1015 if (bcp47_locale.length() != 0) {
1016 uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
1017 &icu_length, &status);
1018 if (U_FAILURE(status) || icu_length == 0) {
1019 return NULL;
1020 }
1021 icu_locale = icu::Locale(icu_result);
1022 }
1023
1024 icu::BreakIterator* break_iterator = CreateICUBreakIterator(
1025 isolate, icu_locale, options);
1026 if (!break_iterator) {
1027 // Remove extensions and try again.
1028 icu::Locale no_extension_locale(icu_locale.getBaseName());
1029 break_iterator = CreateICUBreakIterator(
1030 isolate, no_extension_locale, options);
1031
1032 // Set resolved settings (locale).
1033 SetResolvedBreakIteratorSettings(
1034 isolate, no_extension_locale, break_iterator, resolved);
1035 } else {
1036 SetResolvedBreakIteratorSettings(
1037 isolate, icu_locale, break_iterator, resolved);
1038 }
1039
1040 return break_iterator;
1041}
1042
1043
1044icu::BreakIterator* BreakIterator::UnpackBreakIterator(Isolate* isolate,
1045 Handle<JSObject> obj) {
1046 Handle<String> key =
1047 isolate->factory()->NewStringFromAscii(CStrVector("breakIterator"));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001048 if (JSReceiver::HasLocalProperty(obj, key)) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001049 return reinterpret_cast<icu::BreakIterator*>(obj->GetInternalField(0));
1050 }
1051
1052 return NULL;
1053}
1054
1055
1056void BreakIterator::DeleteBreakIterator(v8::Isolate* isolate,
1057 Persistent<v8::Value>* object,
1058 void* param) {
1059 // First delete the hidden C++ object.
1060 delete reinterpret_cast<icu::BreakIterator*>(Handle<JSObject>::cast(
1061 v8::Utils::OpenPersistent(object))->GetInternalField(0));
1062
1063 delete reinterpret_cast<icu::UnicodeString*>(Handle<JSObject>::cast(
1064 v8::Utils::OpenPersistent(object))->GetInternalField(1));
1065
1066 // Then dispose of the persistent handle to JS object.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001067 object->Dispose();
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001068}
1069
danno@chromium.org59400602013-08-13 17:09:37 +00001070} } // namespace v8::internal