The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / i18n.cc @ f230a1cf

History | View | Annotate | Download (35.6 KB)

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/brkiter.h"
32
#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"
42
#include "unicode/rbbi.h"
43
#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

    
51
namespace v8 {
52
namespace internal {
53

    
54
namespace {
55

    
56
bool 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

    
73
bool 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

    
88
bool 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

    
103
icu::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

    
151
void 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

    
254
template<int internal_fields, EternalHandles::SingletonHandle field>
255
Handle<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

    
270
icu::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

    
377
void 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"));
467
  if (JSReceiver::HasLocalProperty(resolved, key)) {
468
    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"));
480
  if (JSReceiver::HasLocalProperty(resolved, key)) {
481
    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

    
515
icu::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

    
579
void 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

    
736

    
737
icu::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

    
770
void 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

    
799
}  // namespace
800

    
801

    
802
// static
803
Handle<ObjectTemplateInfo> I18N::GetTemplate(Isolate* isolate) {
804
  return GetEternal<1, i::EternalHandles::I18N_TEMPLATE_ONE>(isolate);
805
}
806

    
807

    
808
// static
809
Handle<ObjectTemplateInfo> I18N::GetTemplate2(Isolate* isolate) {
810
  return GetEternal<2, i::EternalHandles::I18N_TEMPLATE_TWO>(isolate);
811
}
812

    
813

    
814
// static
815
icu::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

    
853
icu::SimpleDateFormat* DateFormat::UnpackDateFormat(
854
    Isolate* isolate,
855
    Handle<JSObject> obj) {
856
  Handle<String> key =
857
      isolate->factory()->NewStringFromAscii(CStrVector("dateFormat"));
858
  if (JSReceiver::HasLocalProperty(obj, key)) {
859
    return reinterpret_cast<icu::SimpleDateFormat*>(
860
        obj->GetInternalField(0));
861
  }
862

    
863
  return NULL;
864
}
865

    
866

    
867
void DateFormat::DeleteDateFormat(v8::Isolate* isolate,
868
                                  Persistent<v8::Value>* object,
869
                                  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.
875
  object->Dispose();
876
}
877

    
878

    
879
icu::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

    
918
icu::DecimalFormat* NumberFormat::UnpackNumberFormat(
919
    Isolate* isolate,
920
    Handle<JSObject> obj) {
921
  Handle<String> key =
922
      isolate->factory()->NewStringFromAscii(CStrVector("numberFormat"));
923
  if (JSReceiver::HasLocalProperty(obj, key)) {
924
    return reinterpret_cast<icu::DecimalFormat*>(obj->GetInternalField(0));
925
  }
926

    
927
  return NULL;
928
}
929

    
930

    
931
void NumberFormat::DeleteNumberFormat(v8::Isolate* isolate,
932
                                      Persistent<v8::Value>* object,
933
                                      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.
939
  object->Dispose();
940
}
941

    
942

    
943
icu::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

    
980
icu::Collator* Collator::UnpackCollator(Isolate* isolate,
981
                                        Handle<JSObject> obj) {
982
  Handle<String> key =
983
      isolate->factory()->NewStringFromAscii(CStrVector("collator"));
984
  if (JSReceiver::HasLocalProperty(obj, key)) {
985
    return reinterpret_cast<icu::Collator*>(obj->GetInternalField(0));
986
  }
987

    
988
  return NULL;
989
}
990

    
991

    
992
void Collator::DeleteCollator(v8::Isolate* isolate,
993
                              Persistent<v8::Value>* object,
994
                              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.
1000
  object->Dispose();
1001
}
1002

    
1003

    
1004
icu::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

    
1044
icu::BreakIterator* BreakIterator::UnpackBreakIterator(Isolate* isolate,
1045
                                                       Handle<JSObject> obj) {
1046
  Handle<String> key =
1047
      isolate->factory()->NewStringFromAscii(CStrVector("breakIterator"));
1048
  if (JSReceiver::HasLocalProperty(obj, key)) {
1049
    return reinterpret_cast<icu::BreakIterator*>(obj->GetInternalField(0));
1050
  }
1051

    
1052
  return NULL;
1053
}
1054

    
1055

    
1056
void 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.
1067
  object->Dispose();
1068
}
1069

    
1070
} }  // namespace v8::internal