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