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", ¤cy); 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->Reset(); 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->Reset(); 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->Reset(); 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->Reset(); 1068 } 1069 1070 } } // namespace v8::internal 1071