| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // ECMAScript 402 API implementation. | 5 // ECMAScript 402 API implementation. |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Intl object is a single object that has some named properties, | 8 * Intl object is a single object that has some named properties, |
| 9 * all of which are constructors. | 9 * all of which are constructors. |
| 10 */ | 10 */ |
| 11 (function(global, utils) { | 11 (function(global, utils) { |
| 12 | 12 |
| 13 "use strict"; | 13 "use strict"; |
| 14 | 14 |
| 15 %CheckIsBootstrapping(); | 15 %CheckIsBootstrapping(); |
| 16 | 16 |
| 17 // ------------------------------------------------------------------- | 17 // ------------------------------------------------------------------- |
| 18 // Imports | 18 // Imports |
| 19 | 19 |
| 20 var GlobalBoolean = global.Boolean; | 20 var GlobalBoolean = global.Boolean; |
| 21 var GlobalDate = global.Date; | 21 var GlobalDate = global.Date; |
| 22 var GlobalNumber = global.Number; | 22 var GlobalNumber = global.Number; |
| 23 var GlobalRegExp = global.RegExp; | 23 var GlobalRegExp = global.RegExp; |
| 24 var GlobalString = global.String; | 24 var GlobalString = global.String; |
| 25 var ObjectDefineProperties = utils.ObjectDefineProperties; | 25 var ObjectDefineProperties = utils.ObjectDefineProperties; |
| 26 var ObjectDefineProperty = utils.ObjectDefineProperty; | 26 var ObjectDefineProperty = utils.ObjectDefineProperty; |
| 27 var SetFunctionName = utils.SetFunctionName; | 27 var SetFunctionName = utils.SetFunctionName; |
| 28 | 28 |
| 29 var ArrayIndexOf; |
| 30 var ArrayJoin; |
| 29 var IsFinite; | 31 var IsFinite; |
| 30 var IsNaN; | 32 var IsNaN; |
| 31 var MathFloor; | 33 var MathFloor; |
| 34 var RegExpTest; |
| 35 var StringIndexOf; |
| 36 var StringLastIndexOf; |
| 37 var StringMatch; |
| 38 var StringReplace; |
| 39 var StringSplit; |
| 40 var StringSubstr; |
| 41 var StringSubstring; |
| 32 | 42 |
| 33 utils.Import(function(from) { | 43 utils.Import(function(from) { |
| 44 ArrayIndexOf = from.ArrayIndexOf; |
| 45 ArrayJoin = from.ArrayJoin; |
| 34 IsFinite = from.IsFinite; | 46 IsFinite = from.IsFinite; |
| 35 IsNaN = from.IsNaN; | 47 IsNaN = from.IsNaN; |
| 36 MathFloor = from.MathFloor; | 48 MathFloor = from.MathFloor; |
| 49 RegExpTest = from.RegExpTest; |
| 50 StringIndexOf = from.StringIndexOf; |
| 51 StringLastIndexOf = from.StringLastIndexOf; |
| 52 StringMatch = from.StringMatch; |
| 53 StringReplace = from.StringReplace; |
| 54 StringSplit = from.StringSplit; |
| 55 StringSubstr = from.StringSubstr; |
| 56 StringSubstring = from.StringSubstring; |
| 37 }); | 57 }); |
| 38 | 58 |
| 39 // ------------------------------------------------------------------- | 59 // ------------------------------------------------------------------- |
| 40 | 60 |
| 41 var Intl = {}; | 61 var Intl = {}; |
| 42 | 62 |
| 43 %AddNamedProperty(global, "Intl", Intl, DONT_ENUM); | 63 %AddNamedProperty(global, "Intl", Intl, DONT_ENUM); |
| 44 | 64 |
| 45 /** | 65 /** |
| 46 * Caches available locales for each service. | 66 * Caches available locales for each service. |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 configurable: true | 236 configurable: true |
| 217 }); | 237 }); |
| 218 } | 238 } |
| 219 | 239 |
| 220 | 240 |
| 221 /** | 241 /** |
| 222 * Returns an intersection of locales and service supported locales. | 242 * Returns an intersection of locales and service supported locales. |
| 223 * Parameter locales is treated as a priority list. | 243 * Parameter locales is treated as a priority list. |
| 224 */ | 244 */ |
| 225 function supportedLocalesOf(service, locales, options) { | 245 function supportedLocalesOf(service, locales, options) { |
| 226 if (IS_NULL(service.match(GetServiceRE()))) { | 246 if (IS_NULL(%_CallFunction(service, GetServiceRE(), StringMatch))) { |
| 227 throw MakeError(kWrongServiceType, service); | 247 throw MakeError(kWrongServiceType, service); |
| 228 } | 248 } |
| 229 | 249 |
| 230 // Provide defaults if matcher was not specified. | 250 // Provide defaults if matcher was not specified. |
| 231 if (IS_UNDEFINED(options)) { | 251 if (IS_UNDEFINED(options)) { |
| 232 options = {}; | 252 options = {}; |
| 233 } else { | 253 } else { |
| 234 options = $toObject(options); | 254 options = $toObject(options); |
| 235 } | 255 } |
| 236 | 256 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 264 | 284 |
| 265 /** | 285 /** |
| 266 * Returns the subset of the provided BCP 47 language priority list for which | 286 * Returns the subset of the provided BCP 47 language priority list for which |
| 267 * this service has a matching locale when using the BCP 47 Lookup algorithm. | 287 * this service has a matching locale when using the BCP 47 Lookup algorithm. |
| 268 * Locales appear in the same order in the returned list as in the input list. | 288 * Locales appear in the same order in the returned list as in the input list. |
| 269 */ | 289 */ |
| 270 function lookupSupportedLocalesOf(requestedLocales, availableLocales) { | 290 function lookupSupportedLocalesOf(requestedLocales, availableLocales) { |
| 271 var matchedLocales = []; | 291 var matchedLocales = []; |
| 272 for (var i = 0; i < requestedLocales.length; ++i) { | 292 for (var i = 0; i < requestedLocales.length; ++i) { |
| 273 // Remove -u- extension. | 293 // Remove -u- extension. |
| 274 var locale = requestedLocales[i].replace(GetUnicodeExtensionRE(), ''); | 294 var locale = %_CallFunction(requestedLocales[i], GetUnicodeExtensionRE(), |
| 295 '', StringReplace); |
| 275 do { | 296 do { |
| 276 if (!IS_UNDEFINED(availableLocales[locale])) { | 297 if (!IS_UNDEFINED(availableLocales[locale])) { |
| 277 // Push requested locale not the resolved one. | 298 // Push requested locale not the resolved one. |
| 278 matchedLocales.push(requestedLocales[i]); | 299 %_CallFunction(matchedLocales, requestedLocales[i], $arrayPush); |
| 279 break; | 300 break; |
| 280 } | 301 } |
| 281 // Truncate locale if possible, if not break. | 302 // Truncate locale if possible, if not break. |
| 282 var pos = locale.lastIndexOf('-'); | 303 var pos = %_CallFunction(locale, '-', StringLastIndexOf); |
| 283 if (pos === -1) { | 304 if (pos === -1) { |
| 284 break; | 305 break; |
| 285 } | 306 } |
| 286 locale = locale.substring(0, pos); | 307 locale = %_CallFunction(locale, 0, pos, StringSubstring); |
| 287 } while (true); | 308 } while (true); |
| 288 } | 309 } |
| 289 | 310 |
| 290 return matchedLocales; | 311 return matchedLocales; |
| 291 } | 312 } |
| 292 | 313 |
| 293 | 314 |
| 294 /** | 315 /** |
| 295 * Returns the subset of the provided BCP 47 language priority list for which | 316 * Returns the subset of the provided BCP 47 language priority list for which |
| 296 * this service has a matching locale when using the implementation | 317 * this service has a matching locale when using the implementation |
| (...skipping 23 matching lines...) Expand all Loading... |
| 320 break; | 341 break; |
| 321 case 'string': | 342 case 'string': |
| 322 value = GlobalString(value); | 343 value = GlobalString(value); |
| 323 break; | 344 break; |
| 324 case 'number': | 345 case 'number': |
| 325 value = GlobalNumber(value); | 346 value = GlobalNumber(value); |
| 326 break; | 347 break; |
| 327 default: | 348 default: |
| 328 throw MakeError(kWrongValueType); | 349 throw MakeError(kWrongValueType); |
| 329 } | 350 } |
| 330 if (!IS_UNDEFINED(values) && values.indexOf(value) === -1) { | 351 |
| 352 if (!IS_UNDEFINED(values) && |
| 353 %_CallFunction(values, value, ArrayIndexOf) === -1) { |
| 331 throw MakeRangeError(kValueOutOfRange, value, caller, property); | 354 throw MakeRangeError(kValueOutOfRange, value, caller, property); |
| 332 } | 355 } |
| 333 | 356 |
| 334 return value; | 357 return value; |
| 335 } | 358 } |
| 336 | 359 |
| 337 return defaultValue; | 360 return defaultValue; |
| 338 } | 361 } |
| 339 | 362 |
| 340 return getOption; | 363 return getOption; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 369 | 392 |
| 370 return resolved; | 393 return resolved; |
| 371 } | 394 } |
| 372 | 395 |
| 373 | 396 |
| 374 /** | 397 /** |
| 375 * Returns best matched supported locale and extension info using basic | 398 * Returns best matched supported locale and extension info using basic |
| 376 * lookup algorithm. | 399 * lookup algorithm. |
| 377 */ | 400 */ |
| 378 function lookupMatcher(service, requestedLocales) { | 401 function lookupMatcher(service, requestedLocales) { |
| 379 if (IS_NULL(service.match(GetServiceRE()))) { | 402 if (IS_NULL(%_CallFunction(service, GetServiceRE(), StringMatch))) { |
| 380 throw MakeError(kWrongServiceType, service); | 403 throw MakeError(kWrongServiceType, service); |
| 381 } | 404 } |
| 382 | 405 |
| 383 // Cache these, they don't ever change per service. | 406 // Cache these, they don't ever change per service. |
| 384 if (IS_UNDEFINED(AVAILABLE_LOCALES[service])) { | 407 if (IS_UNDEFINED(AVAILABLE_LOCALES[service])) { |
| 385 AVAILABLE_LOCALES[service] = getAvailableLocalesOf(service); | 408 AVAILABLE_LOCALES[service] = getAvailableLocalesOf(service); |
| 386 } | 409 } |
| 387 | 410 |
| 388 for (var i = 0; i < requestedLocales.length; ++i) { | 411 for (var i = 0; i < requestedLocales.length; ++i) { |
| 389 // Remove all extensions. | 412 // Remove all extensions. |
| 390 var locale = requestedLocales[i].replace(GetAnyExtensionRE(), ''); | 413 var locale = %_CallFunction(requestedLocales[i], GetAnyExtensionRE(), '', |
| 414 StringReplace); |
| 391 do { | 415 do { |
| 392 if (!IS_UNDEFINED(AVAILABLE_LOCALES[service][locale])) { | 416 if (!IS_UNDEFINED(AVAILABLE_LOCALES[service][locale])) { |
| 393 // Return the resolved locale and extension. | 417 // Return the resolved locale and extension. |
| 394 var extensionMatch = requestedLocales[i].match(GetUnicodeExtensionRE()); | 418 var extensionMatch = |
| 419 %_CallFunction(requestedLocales[i], GetUnicodeExtensionRE(), |
| 420 StringMatch); |
| 395 var extension = IS_NULL(extensionMatch) ? '' : extensionMatch[0]; | 421 var extension = IS_NULL(extensionMatch) ? '' : extensionMatch[0]; |
| 396 return {'locale': locale, 'extension': extension, 'position': i}; | 422 return {'locale': locale, 'extension': extension, 'position': i}; |
| 397 } | 423 } |
| 398 // Truncate locale if possible. | 424 // Truncate locale if possible. |
| 399 var pos = locale.lastIndexOf('-'); | 425 var pos = %_CallFunction(locale, '-', StringLastIndexOf); |
| 400 if (pos === -1) { | 426 if (pos === -1) { |
| 401 break; | 427 break; |
| 402 } | 428 } |
| 403 locale = locale.substring(0, pos); | 429 locale = %_CallFunction(locale, 0, pos, StringSubstring); |
| 404 } while (true); | 430 } while (true); |
| 405 } | 431 } |
| 406 | 432 |
| 407 // Didn't find a match, return default. | 433 // Didn't find a match, return default. |
| 408 if (IS_UNDEFINED(DEFAULT_ICU_LOCALE)) { | 434 if (IS_UNDEFINED(DEFAULT_ICU_LOCALE)) { |
| 409 DEFAULT_ICU_LOCALE = %GetDefaultICULocale(); | 435 DEFAULT_ICU_LOCALE = %GetDefaultICULocale(); |
| 410 } | 436 } |
| 411 | 437 |
| 412 return {'locale': DEFAULT_ICU_LOCALE, 'extension': '', 'position': -1}; | 438 return {'locale': DEFAULT_ICU_LOCALE, 'extension': '', 'position': -1}; |
| 413 } | 439 } |
| 414 | 440 |
| 415 | 441 |
| 416 /** | 442 /** |
| 417 * Returns best matched supported locale and extension info using | 443 * Returns best matched supported locale and extension info using |
| 418 * implementation dependend algorithm. | 444 * implementation dependend algorithm. |
| 419 */ | 445 */ |
| 420 function bestFitMatcher(service, requestedLocales) { | 446 function bestFitMatcher(service, requestedLocales) { |
| 421 // TODO(cira): implement better best fit algorithm. | 447 // TODO(cira): implement better best fit algorithm. |
| 422 return lookupMatcher(service, requestedLocales); | 448 return lookupMatcher(service, requestedLocales); |
| 423 } | 449 } |
| 424 | 450 |
| 425 | 451 |
| 426 /** | 452 /** |
| 427 * Parses Unicode extension into key - value map. | 453 * Parses Unicode extension into key - value map. |
| 428 * Returns empty object if the extension string is invalid. | 454 * Returns empty object if the extension string is invalid. |
| 429 * We are not concerned with the validity of the values at this point. | 455 * We are not concerned with the validity of the values at this point. |
| 430 */ | 456 */ |
| 431 function parseExtension(extension) { | 457 function parseExtension(extension) { |
| 432 var extensionSplit = extension.split('-'); | 458 var extensionSplit = %_CallFunction(extension, '-', StringSplit); |
| 433 | 459 |
| 434 // Assume ['', 'u', ...] input, but don't throw. | 460 // Assume ['', 'u', ...] input, but don't throw. |
| 435 if (extensionSplit.length <= 2 || | 461 if (extensionSplit.length <= 2 || |
| 436 (extensionSplit[0] !== '' && extensionSplit[1] !== 'u')) { | 462 (extensionSplit[0] !== '' && extensionSplit[1] !== 'u')) { |
| 437 return {}; | 463 return {}; |
| 438 } | 464 } |
| 439 | 465 |
| 440 // Key is {2}alphanum, value is {3,8}alphanum. | 466 // Key is {2}alphanum, value is {3,8}alphanum. |
| 441 // Some keys may not have explicit values (booleans). | 467 // Some keys may not have explicit values (booleans). |
| 442 var extensionMap = {}; | 468 var extensionMap = {}; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 481 if (type === 'boolean' && (typeof value === 'string')) { | 507 if (type === 'boolean' && (typeof value === 'string')) { |
| 482 value = (value === 'true') ? true : false; | 508 value = (value === 'true') ? true : false; |
| 483 } | 509 } |
| 484 | 510 |
| 485 if (!IS_UNDEFINED(property)) { | 511 if (!IS_UNDEFINED(property)) { |
| 486 defineWEProperty(outOptions, property, value); | 512 defineWEProperty(outOptions, property, value); |
| 487 } | 513 } |
| 488 } | 514 } |
| 489 | 515 |
| 490 for (var key in keyValues) { | 516 for (var key in keyValues) { |
| 491 if (keyValues.hasOwnProperty(key)) { | 517 if (%HasOwnProperty(keyValues, key)) { |
| 492 var value = UNDEFINED; | 518 var value = UNDEFINED; |
| 493 var map = keyValues[key]; | 519 var map = keyValues[key]; |
| 494 if (!IS_UNDEFINED(map.property)) { | 520 if (!IS_UNDEFINED(map.property)) { |
| 495 // This may return true if user specifies numeric: 'false', since | 521 // This may return true if user specifies numeric: 'false', since |
| 496 // Boolean('nonempty') === true. | 522 // Boolean('nonempty') === true. |
| 497 value = getOption(map.property, map.type, map.values); | 523 value = getOption(map.property, map.type, map.values); |
| 498 } | 524 } |
| 499 if (!IS_UNDEFINED(value)) { | 525 if (!IS_UNDEFINED(value)) { |
| 500 updateProperty(map.property, map.type, value); | 526 updateProperty(map.property, map.type, value); |
| 501 extension += updateExtension(key, value); | 527 extension += updateExtension(key, value); |
| 502 continue; | 528 continue; |
| 503 } | 529 } |
| 504 // User options didn't have it, check Unicode extension. | 530 // User options didn't have it, check Unicode extension. |
| 505 // Here we want to convert strings 'true', 'false' into proper Boolean | 531 // Here we want to convert strings 'true', 'false' into proper Boolean |
| 506 // values (not a user error). | 532 // values (not a user error). |
| 507 if (extensionMap.hasOwnProperty(key)) { | 533 if (%HasOwnProperty(extensionMap, key)) { |
| 508 value = extensionMap[key]; | 534 value = extensionMap[key]; |
| 509 if (!IS_UNDEFINED(value)) { | 535 if (!IS_UNDEFINED(value)) { |
| 510 updateProperty(map.property, map.type, value); | 536 updateProperty(map.property, map.type, value); |
| 511 extension += updateExtension(key, value); | 537 extension += updateExtension(key, value); |
| 512 } else if (map.type === 'boolean') { | 538 } else if (map.type === 'boolean') { |
| 513 // Boolean keys are allowed not to have values in Unicode extension. | 539 // Boolean keys are allowed not to have values in Unicode extension. |
| 514 // Those default to true. | 540 // Those default to true. |
| 515 updateProperty(map.property, map.type, true); | 541 updateProperty(map.property, map.type, true); |
| 516 extension += updateExtension(key, true); | 542 extension += updateExtension(key, true); |
| 517 } | 543 } |
| 518 } | 544 } |
| 519 } | 545 } |
| 520 } | 546 } |
| 521 | 547 |
| 522 return extension === ''? '' : '-u' + extension; | 548 return extension === ''? '' : '-u' + extension; |
| 523 } | 549 } |
| 524 | 550 |
| 525 | 551 |
| 526 /** | 552 /** |
| 527 * Converts all OwnProperties into | 553 * Converts all OwnProperties into |
| 528 * configurable: false, writable: false, enumerable: true. | 554 * configurable: false, writable: false, enumerable: true. |
| 529 */ | 555 */ |
| 530 function freezeArray(array) { | 556 function freezeArray(array) { |
| 531 array.forEach(function(element, index) { | 557 var l = array.length; |
| 532 ObjectDefineProperty(array, index, {value: element, | 558 for (var i = 0; i < l; i++) { |
| 533 configurable: false, | 559 if (i in array) { |
| 534 writable: false, | 560 ObjectDefineProperty(array, i, {value: array[i], |
| 535 enumerable: true}); | 561 configurable: false, |
| 536 }); | 562 writable: false, |
| 563 enumerable: true}); |
| 564 } |
| 565 } |
| 537 | 566 |
| 538 ObjectDefineProperty(array, 'length', {value: array.length, | 567 ObjectDefineProperty(array, 'length', {value: l, writable: false}); |
| 539 writable: false}); | |
| 540 return array; | 568 return array; |
| 541 } | 569 } |
| 542 | 570 |
| 543 | 571 |
| 544 /** | 572 /** |
| 545 * It's sometimes desireable to leave user requested locale instead of ICU | 573 * It's sometimes desireable to leave user requested locale instead of ICU |
| 546 * supported one (zh-TW is equivalent to zh-Hant-TW, so we should keep shorter | 574 * supported one (zh-TW is equivalent to zh-Hant-TW, so we should keep shorter |
| 547 * one, if that was what user requested). | 575 * one, if that was what user requested). |
| 548 * This function returns user specified tag if its maximized form matches ICU | 576 * This function returns user specified tag if its maximized form matches ICU |
| 549 * resolved locale. If not we return ICU result. | 577 * resolved locale. If not we return ICU result. |
| 550 */ | 578 */ |
| 551 function getOptimalLanguageTag(original, resolved) { | 579 function getOptimalLanguageTag(original, resolved) { |
| 552 // Returns Array<Object>, where each object has maximized and base properties. | 580 // Returns Array<Object>, where each object has maximized and base properties. |
| 553 // Maximized: zh -> zh-Hans-CN | 581 // Maximized: zh -> zh-Hans-CN |
| 554 // Base: zh-CN-u-ca-gregory -> zh-CN | 582 // Base: zh-CN-u-ca-gregory -> zh-CN |
| 555 // Take care of grandfathered or simple cases. | 583 // Take care of grandfathered or simple cases. |
| 556 if (original === resolved) { | 584 if (original === resolved) { |
| 557 return original; | 585 return original; |
| 558 } | 586 } |
| 559 | 587 |
| 560 var locales = %GetLanguageTagVariants([original, resolved]); | 588 var locales = %GetLanguageTagVariants([original, resolved]); |
| 561 if (locales[0].maximized !== locales[1].maximized) { | 589 if (locales[0].maximized !== locales[1].maximized) { |
| 562 return resolved; | 590 return resolved; |
| 563 } | 591 } |
| 564 | 592 |
| 565 // Preserve extensions of resolved locale, but swap base tags with original. | 593 // Preserve extensions of resolved locale, but swap base tags with original. |
| 566 var resolvedBase = new GlobalRegExp('^' + locales[1].base); | 594 var resolvedBase = new GlobalRegExp('^' + locales[1].base); |
| 567 return resolved.replace(resolvedBase, locales[0].base); | 595 return %_CallFunction(resolved, resolvedBase, locales[0].base, StringReplace); |
| 568 } | 596 } |
| 569 | 597 |
| 570 | 598 |
| 571 /** | 599 /** |
| 572 * Returns an Object that contains all of supported locales for a given | 600 * Returns an Object that contains all of supported locales for a given |
| 573 * service. | 601 * service. |
| 574 * In addition to the supported locales we add xx-ZZ locale for each xx-Yyyy-ZZ | 602 * In addition to the supported locales we add xx-ZZ locale for each xx-Yyyy-ZZ |
| 575 * that is supported. This is required by the spec. | 603 * that is supported. This is required by the spec. |
| 576 */ | 604 */ |
| 577 function getAvailableLocalesOf(service) { | 605 function getAvailableLocalesOf(service) { |
| 578 var available = %AvailableLocalesOf(service); | 606 var available = %AvailableLocalesOf(service); |
| 579 | 607 |
| 580 for (var i in available) { | 608 for (var i in available) { |
| 581 if (available.hasOwnProperty(i)) { | 609 if (%HasOwnProperty(available, i)) { |
| 582 var parts = i.match(/^([a-z]{2,3})-([A-Z][a-z]{3})-([A-Z]{2})$/); | 610 var parts = %_CallFunction(i, /^([a-z]{2,3})-([A-Z][a-z]{3})-([A-Z]{2})$/, |
| 611 StringMatch); |
| 583 if (parts !== null) { | 612 if (parts !== null) { |
| 584 // Build xx-ZZ. We don't care about the actual value, | 613 // Build xx-ZZ. We don't care about the actual value, |
| 585 // as long it's not undefined. | 614 // as long it's not undefined. |
| 586 available[parts[1] + '-' + parts[3]] = null; | 615 available[parts[1] + '-' + parts[3]] = null; |
| 587 } | 616 } |
| 588 } | 617 } |
| 589 } | 618 } |
| 590 | 619 |
| 591 return available; | 620 return available; |
| 592 } | 621 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 632 if (!IS_UNDEFINED(value)) { | 661 if (!IS_UNDEFINED(value)) { |
| 633 defineWECProperty(object, property, value); | 662 defineWECProperty(object, property, value); |
| 634 } | 663 } |
| 635 } | 664 } |
| 636 | 665 |
| 637 | 666 |
| 638 /** | 667 /** |
| 639 * Returns titlecased word, aMeRricA -> America. | 668 * Returns titlecased word, aMeRricA -> America. |
| 640 */ | 669 */ |
| 641 function toTitleCaseWord(word) { | 670 function toTitleCaseWord(word) { |
| 642 return word.substr(0, 1).toUpperCase() + word.substr(1).toLowerCase(); | 671 return %StringToUpperCase(%_CallFunction(word, 0, 1, StringSubstr)) + |
| 672 %StringToLowerCase(%_CallFunction(word, 1, StringSubstr)); |
| 643 } | 673 } |
| 644 | 674 |
| 645 /** | 675 /** |
| 646 * Canonicalizes the language tag, or throws in case the tag is invalid. | 676 * Canonicalizes the language tag, or throws in case the tag is invalid. |
| 647 */ | 677 */ |
| 648 function canonicalizeLanguageTag(localeID) { | 678 function canonicalizeLanguageTag(localeID) { |
| 649 // null is typeof 'object' so we have to do extra check. | 679 // null is typeof 'object' so we have to do extra check. |
| 650 if (typeof localeID !== 'string' && typeof localeID !== 'object' || | 680 if (typeof localeID !== 'string' && typeof localeID !== 'object' || |
| 651 IS_NULL(localeID)) { | 681 IS_NULL(localeID)) { |
| 652 throw MakeTypeError(kLanguageID); | 682 throw MakeTypeError(kLanguageID); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 676 * Throws on locales that are not well formed BCP47 tags. | 706 * Throws on locales that are not well formed BCP47 tags. |
| 677 */ | 707 */ |
| 678 function initializeLocaleList(locales) { | 708 function initializeLocaleList(locales) { |
| 679 var seen = []; | 709 var seen = []; |
| 680 if (IS_UNDEFINED(locales)) { | 710 if (IS_UNDEFINED(locales)) { |
| 681 // Constructor is called without arguments. | 711 // Constructor is called without arguments. |
| 682 seen = []; | 712 seen = []; |
| 683 } else { | 713 } else { |
| 684 // We allow single string localeID. | 714 // We allow single string localeID. |
| 685 if (typeof locales === 'string') { | 715 if (typeof locales === 'string') { |
| 686 seen.push(canonicalizeLanguageTag(locales)); | 716 %_CallFunction(seen, canonicalizeLanguageTag(locales), $arrayPush); |
| 687 return freezeArray(seen); | 717 return freezeArray(seen); |
| 688 } | 718 } |
| 689 | 719 |
| 690 var o = $toObject(locales); | 720 var o = $toObject(locales); |
| 691 // Converts it to UInt32 (>>> is shr on 32bit integers). | 721 var len = TO_UINT32(o.length); |
| 692 var len = o.length >>> 0; | |
| 693 | 722 |
| 694 for (var k = 0; k < len; k++) { | 723 for (var k = 0; k < len; k++) { |
| 695 if (k in o) { | 724 if (k in o) { |
| 696 var value = o[k]; | 725 var value = o[k]; |
| 697 | 726 |
| 698 var tag = canonicalizeLanguageTag(value); | 727 var tag = canonicalizeLanguageTag(value); |
| 699 | 728 |
| 700 if (seen.indexOf(tag) === -1) { | 729 if (%_CallFunction(seen, tag, ArrayIndexOf) === -1) { |
| 701 seen.push(tag); | 730 %_CallFunction(seen, tag, $arrayPush); |
| 702 } | 731 } |
| 703 } | 732 } |
| 704 } | 733 } |
| 705 } | 734 } |
| 706 | 735 |
| 707 return freezeArray(seen); | 736 return freezeArray(seen); |
| 708 } | 737 } |
| 709 | 738 |
| 710 | 739 |
| 711 /** | 740 /** |
| 712 * Validates the language tag. Section 2.2.9 of the bcp47 spec | 741 * Validates the language tag. Section 2.2.9 of the bcp47 spec |
| 713 * defines a valid tag. | 742 * defines a valid tag. |
| 714 * | 743 * |
| 715 * ICU is too permissible and lets invalid tags, like | 744 * ICU is too permissible and lets invalid tags, like |
| 716 * hant-cmn-cn, through. | 745 * hant-cmn-cn, through. |
| 717 * | 746 * |
| 718 * Returns false if the language tag is invalid. | 747 * Returns false if the language tag is invalid. |
| 719 */ | 748 */ |
| 720 function isValidLanguageTag(locale) { | 749 function isValidLanguageTag(locale) { |
| 721 // Check if it's well-formed, including grandfadered tags. | 750 // Check if it's well-formed, including grandfadered tags. |
| 722 if (GetLanguageTagRE().test(locale) === false) { | 751 if (!%_CallFunction(GetLanguageTagRE(), locale, RegExpTest)) { |
| 723 return false; | 752 return false; |
| 724 } | 753 } |
| 725 | 754 |
| 726 // Just return if it's a x- form. It's all private. | 755 // Just return if it's a x- form. It's all private. |
| 727 if (locale.indexOf('x-') === 0) { | 756 if (%_CallFunction(locale, 'x-', StringIndexOf) === 0) { |
| 728 return true; | 757 return true; |
| 729 } | 758 } |
| 730 | 759 |
| 731 // Check if there are any duplicate variants or singletons (extensions). | 760 // Check if there are any duplicate variants or singletons (extensions). |
| 732 | 761 |
| 733 // Remove private use section. | 762 // Remove private use section. |
| 734 locale = locale.split(/-x-/)[0]; | 763 locale = %_CallFunction(locale, /-x-/, StringSplit)[0]; |
| 735 | 764 |
| 736 // Skip language since it can match variant regex, so we start from 1. | 765 // Skip language since it can match variant regex, so we start from 1. |
| 737 // We are matching i-klingon here, but that's ok, since i-klingon-klingon | 766 // We are matching i-klingon here, but that's ok, since i-klingon-klingon |
| 738 // is not valid and would fail LANGUAGE_TAG_RE test. | 767 // is not valid and would fail LANGUAGE_TAG_RE test. |
| 739 var variants = []; | 768 var variants = []; |
| 740 var extensions = []; | 769 var extensions = []; |
| 741 var parts = locale.split(/-/); | 770 var parts = %_CallFunction(locale, /-/, StringSplit); |
| 742 for (var i = 1; i < parts.length; i++) { | 771 for (var i = 1; i < parts.length; i++) { |
| 743 var value = parts[i]; | 772 var value = parts[i]; |
| 744 if (GetLanguageVariantRE().test(value) === true && extensions.length === 0)
{ | 773 if (%_CallFunction(GetLanguageVariantRE(), value, RegExpTest) && |
| 745 if (variants.indexOf(value) === -1) { | 774 extensions.length === 0) { |
| 746 variants.push(value); | 775 if (%_CallFunction(variants, value, ArrayIndexOf) === -1) { |
| 776 %_CallFunction(variants, value, $arrayPush); |
| 747 } else { | 777 } else { |
| 748 return false; | 778 return false; |
| 749 } | 779 } |
| 750 } | 780 } |
| 751 | 781 |
| 752 if (GetLanguageSingletonRE().test(value) === true) { | 782 if (%_CallFunction(GetLanguageSingletonRE(), value, RegExpTest)) { |
| 753 if (extensions.indexOf(value) === -1) { | 783 if (%_CallFunction(extensions, value, ArrayIndexOf) === -1) { |
| 754 extensions.push(value); | 784 %_CallFunction(extensions, value, $arrayPush); |
| 755 } else { | 785 } else { |
| 756 return false; | 786 return false; |
| 757 } | 787 } |
| 758 } | 788 } |
| 759 } | 789 } |
| 760 | 790 |
| 761 return true; | 791 return true; |
| 762 } | 792 } |
| 763 | 793 |
| 764 | 794 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 847 'kn': {'property': 'numeric', 'type': 'boolean'}, | 877 'kn': {'property': 'numeric', 'type': 'boolean'}, |
| 848 'kf': {'property': 'caseFirst', 'type': 'string', | 878 'kf': {'property': 'caseFirst', 'type': 'string', |
| 849 'values': ['false', 'lower', 'upper']} | 879 'values': ['false', 'lower', 'upper']} |
| 850 }; | 880 }; |
| 851 | 881 |
| 852 setOptions( | 882 setOptions( |
| 853 options, extensionMap, COLLATOR_KEY_MAP, getOption, internalOptions); | 883 options, extensionMap, COLLATOR_KEY_MAP, getOption, internalOptions); |
| 854 | 884 |
| 855 var collation = 'default'; | 885 var collation = 'default'; |
| 856 var extension = ''; | 886 var extension = ''; |
| 857 if (extensionMap.hasOwnProperty('co') && internalOptions.usage === 'sort') { | 887 if (%HasOwnProperty(extensionMap, 'co') && internalOptions.usage === 'sort') { |
| 858 | 888 |
| 859 /** | 889 /** |
| 860 * Allowed -u-co- values. List taken from: | 890 * Allowed -u-co- values. List taken from: |
| 861 * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml | 891 * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml |
| 862 */ | 892 */ |
| 863 var ALLOWED_CO_VALUES = [ | 893 var ALLOWED_CO_VALUES = [ |
| 864 'big5han', 'dict', 'direct', 'ducet', 'gb2312', 'phonebk', 'phonetic', | 894 'big5han', 'dict', 'direct', 'ducet', 'gb2312', 'phonebk', 'phonetic', |
| 865 'pinyin', 'reformed', 'searchjl', 'stroke', 'trad', 'unihan', 'zhuyin' | 895 'pinyin', 'reformed', 'searchjl', 'stroke', 'trad', 'unihan', 'zhuyin' |
| 866 ]; | 896 ]; |
| 867 | 897 |
| 868 if (ALLOWED_CO_VALUES.indexOf(extensionMap.co) !== -1) { | 898 if (%_CallFunction(ALLOWED_CO_VALUES, extensionMap.co, ArrayIndexOf) !== |
| 899 -1) { |
| 869 extension = '-u-co-' + extensionMap.co; | 900 extension = '-u-co-' + extensionMap.co; |
| 870 // ICU can't tell us what the collation is, so save user's input. | 901 // ICU can't tell us what the collation is, so save user's input. |
| 871 collation = extensionMap.co; | 902 collation = extensionMap.co; |
| 872 } | 903 } |
| 873 } else if (internalOptions.usage === 'search') { | 904 } else if (internalOptions.usage === 'search') { |
| 874 extension = '-u-co-search'; | 905 extension = '-u-co-search'; |
| 875 } | 906 } |
| 876 defineWEProperty(internalOptions, 'collation', collation); | 907 defineWEProperty(internalOptions, 'collation', collation); |
| 877 | 908 |
| 878 var requestedLocale = locale.locale + extension; | 909 var requestedLocale = locale.locale + extension; |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 998 addBoundMethod(Intl.Collator, 'compare', compare, 2); | 1029 addBoundMethod(Intl.Collator, 'compare', compare, 2); |
| 999 | 1030 |
| 1000 /** | 1031 /** |
| 1001 * Verifies that the input is a well-formed ISO 4217 currency code. | 1032 * Verifies that the input is a well-formed ISO 4217 currency code. |
| 1002 * Don't uppercase to test. It could convert invalid code into a valid one. | 1033 * Don't uppercase to test. It could convert invalid code into a valid one. |
| 1003 * For example \u00DFP (Eszett+P) becomes SSP. | 1034 * For example \u00DFP (Eszett+P) becomes SSP. |
| 1004 */ | 1035 */ |
| 1005 function isWellFormedCurrencyCode(currency) { | 1036 function isWellFormedCurrencyCode(currency) { |
| 1006 return typeof currency == "string" && | 1037 return typeof currency == "string" && |
| 1007 currency.length == 3 && | 1038 currency.length == 3 && |
| 1008 currency.match(/[^A-Za-z]/) == null; | 1039 %_CallFunction(currency, /[^A-Za-z]/, StringMatch) == null; |
| 1009 } | 1040 } |
| 1010 | 1041 |
| 1011 | 1042 |
| 1012 /** | 1043 /** |
| 1013 * Returns the valid digit count for a property, or throws RangeError on | 1044 * Returns the valid digit count for a property, or throws RangeError on |
| 1014 * a value out of the range. | 1045 * a value out of the range. |
| 1015 */ | 1046 */ |
| 1016 function getNumberOption(options, property, min, max, fallback) { | 1047 function getNumberOption(options, property, min, max, fallback) { |
| 1017 var value = options[property]; | 1048 var value = options[property]; |
| 1018 if (!IS_UNDEFINED(value)) { | 1049 if (!IS_UNDEFINED(value)) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1053 throw MakeRangeError(kInvalidCurrencyCode, currency); | 1084 throw MakeRangeError(kInvalidCurrencyCode, currency); |
| 1054 } | 1085 } |
| 1055 | 1086 |
| 1056 if (internalOptions.style === 'currency' && IS_UNDEFINED(currency)) { | 1087 if (internalOptions.style === 'currency' && IS_UNDEFINED(currency)) { |
| 1057 throw MakeTypeError(kCurrencyCode); | 1088 throw MakeTypeError(kCurrencyCode); |
| 1058 } | 1089 } |
| 1059 | 1090 |
| 1060 var currencyDisplay = getOption( | 1091 var currencyDisplay = getOption( |
| 1061 'currencyDisplay', 'string', ['code', 'symbol', 'name'], 'symbol'); | 1092 'currencyDisplay', 'string', ['code', 'symbol', 'name'], 'symbol'); |
| 1062 if (internalOptions.style === 'currency') { | 1093 if (internalOptions.style === 'currency') { |
| 1063 defineWEProperty(internalOptions, 'currency', currency.toUpperCase()); | 1094 defineWEProperty(internalOptions, 'currency', %StringToUpperCase(currency)); |
| 1064 defineWEProperty(internalOptions, 'currencyDisplay', currencyDisplay); | 1095 defineWEProperty(internalOptions, 'currencyDisplay', currencyDisplay); |
| 1065 } | 1096 } |
| 1066 | 1097 |
| 1067 // Digit ranges. | 1098 // Digit ranges. |
| 1068 var mnid = getNumberOption(options, 'minimumIntegerDigits', 1, 21, 1); | 1099 var mnid = getNumberOption(options, 'minimumIntegerDigits', 1, 21, 1); |
| 1069 defineWEProperty(internalOptions, 'minimumIntegerDigits', mnid); | 1100 defineWEProperty(internalOptions, 'minimumIntegerDigits', mnid); |
| 1070 | 1101 |
| 1071 var mnfd = getNumberOption(options, 'minimumFractionDigits', 0, 20, 0); | 1102 var mnfd = getNumberOption(options, 'minimumFractionDigits', 0, 20, 0); |
| 1072 defineWEProperty(internalOptions, 'minimumFractionDigits', mnfd); | 1103 defineWEProperty(internalOptions, 'minimumFractionDigits', mnfd); |
| 1073 | 1104 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1109 currencyDisplay: {writable: true}, | 1140 currencyDisplay: {writable: true}, |
| 1110 locale: {writable: true}, | 1141 locale: {writable: true}, |
| 1111 maximumFractionDigits: {writable: true}, | 1142 maximumFractionDigits: {writable: true}, |
| 1112 minimumFractionDigits: {writable: true}, | 1143 minimumFractionDigits: {writable: true}, |
| 1113 minimumIntegerDigits: {writable: true}, | 1144 minimumIntegerDigits: {writable: true}, |
| 1114 numberingSystem: {writable: true}, | 1145 numberingSystem: {writable: true}, |
| 1115 requestedLocale: {value: requestedLocale, writable: true}, | 1146 requestedLocale: {value: requestedLocale, writable: true}, |
| 1116 style: {value: internalOptions.style, writable: true}, | 1147 style: {value: internalOptions.style, writable: true}, |
| 1117 useGrouping: {writable: true} | 1148 useGrouping: {writable: true} |
| 1118 }); | 1149 }); |
| 1119 if (internalOptions.hasOwnProperty('minimumSignificantDigits')) { | 1150 if (%HasOwnProperty(internalOptions, 'minimumSignificantDigits')) { |
| 1120 defineWEProperty(resolved, 'minimumSignificantDigits', UNDEFINED); | 1151 defineWEProperty(resolved, 'minimumSignificantDigits', UNDEFINED); |
| 1121 } | 1152 } |
| 1122 if (internalOptions.hasOwnProperty('maximumSignificantDigits')) { | 1153 if (%HasOwnProperty(internalOptions, 'maximumSignificantDigits')) { |
| 1123 defineWEProperty(resolved, 'maximumSignificantDigits', UNDEFINED); | 1154 defineWEProperty(resolved, 'maximumSignificantDigits', UNDEFINED); |
| 1124 } | 1155 } |
| 1125 var formatter = %CreateNumberFormat(requestedLocale, | 1156 var formatter = %CreateNumberFormat(requestedLocale, |
| 1126 internalOptions, | 1157 internalOptions, |
| 1127 resolved); | 1158 resolved); |
| 1128 | 1159 |
| 1129 // We can't get information about number or currency style from ICU, so we | 1160 // We can't get information about number or currency style from ICU, so we |
| 1130 // assume user request was fulfilled. | 1161 // assume user request was fulfilled. |
| 1131 if (internalOptions.style === 'currency') { | 1162 if (internalOptions.style === 'currency') { |
| 1132 ObjectDefineProperty(resolved, 'currencyDisplay', {value: currencyDisplay, | 1163 ObjectDefineProperty(resolved, 'currencyDisplay', {value: currencyDisplay, |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1186 minimumFractionDigits: format.resolved.minimumFractionDigits, | 1217 minimumFractionDigits: format.resolved.minimumFractionDigits, |
| 1187 maximumFractionDigits: format.resolved.maximumFractionDigits, | 1218 maximumFractionDigits: format.resolved.maximumFractionDigits, |
| 1188 }; | 1219 }; |
| 1189 | 1220 |
| 1190 if (result.style === 'currency') { | 1221 if (result.style === 'currency') { |
| 1191 defineWECProperty(result, 'currency', format.resolved.currency); | 1222 defineWECProperty(result, 'currency', format.resolved.currency); |
| 1192 defineWECProperty(result, 'currencyDisplay', | 1223 defineWECProperty(result, 'currencyDisplay', |
| 1193 format.resolved.currencyDisplay); | 1224 format.resolved.currencyDisplay); |
| 1194 } | 1225 } |
| 1195 | 1226 |
| 1196 if (format.resolved.hasOwnProperty('minimumSignificantDigits')) { | 1227 if (%HasOwnProperty(format.resolved, 'minimumSignificantDigits')) { |
| 1197 defineWECProperty(result, 'minimumSignificantDigits', | 1228 defineWECProperty(result, 'minimumSignificantDigits', |
| 1198 format.resolved.minimumSignificantDigits); | 1229 format.resolved.minimumSignificantDigits); |
| 1199 } | 1230 } |
| 1200 | 1231 |
| 1201 if (format.resolved.hasOwnProperty('maximumSignificantDigits')) { | 1232 if (%HasOwnProperty(format.resolved, 'maximumSignificantDigits')) { |
| 1202 defineWECProperty(result, 'maximumSignificantDigits', | 1233 defineWECProperty(result, 'maximumSignificantDigits', |
| 1203 format.resolved.maximumSignificantDigits); | 1234 format.resolved.maximumSignificantDigits); |
| 1204 } | 1235 } |
| 1205 | 1236 |
| 1206 return result; | 1237 return result; |
| 1207 }, | 1238 }, |
| 1208 DONT_ENUM | 1239 DONT_ENUM |
| 1209 ); | 1240 ); |
| 1210 SetFunctionName(Intl.NumberFormat.prototype.resolvedOptions, 'resolvedOptions'); | 1241 SetFunctionName(Intl.NumberFormat.prototype.resolvedOptions, 'resolvedOptions'); |
| 1211 %FunctionRemovePrototype(Intl.NumberFormat.prototype.resolvedOptions); | 1242 %FunctionRemovePrototype(Intl.NumberFormat.prototype.resolvedOptions); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1319 return ''; | 1350 return ''; |
| 1320 } | 1351 } |
| 1321 } | 1352 } |
| 1322 | 1353 |
| 1323 | 1354 |
| 1324 /** | 1355 /** |
| 1325 * Returns object that matches LDML representation of the date. | 1356 * Returns object that matches LDML representation of the date. |
| 1326 */ | 1357 */ |
| 1327 function fromLDMLString(ldmlString) { | 1358 function fromLDMLString(ldmlString) { |
| 1328 // First remove '' quoted text, so we lose 'Uhr' strings. | 1359 // First remove '' quoted text, so we lose 'Uhr' strings. |
| 1329 ldmlString = ldmlString.replace(GetQuotedStringRE(), ''); | 1360 ldmlString = %_CallFunction(ldmlString, GetQuotedStringRE(), '', |
| 1361 StringReplace); |
| 1330 | 1362 |
| 1331 var options = {}; | 1363 var options = {}; |
| 1332 var match = ldmlString.match(/E{3,5}/g); | 1364 var match = %_CallFunction(ldmlString, /E{3,5}/g, StringMatch); |
| 1333 options = appendToDateTimeObject( | 1365 options = appendToDateTimeObject( |
| 1334 options, 'weekday', match, {EEEEE: 'narrow', EEE: 'short', EEEE: 'long'}); | 1366 options, 'weekday', match, {EEEEE: 'narrow', EEE: 'short', EEEE: 'long'}); |
| 1335 | 1367 |
| 1336 match = ldmlString.match(/G{3,5}/g); | 1368 match = %_CallFunction(ldmlString, /G{3,5}/g, StringMatch); |
| 1337 options = appendToDateTimeObject( | 1369 options = appendToDateTimeObject( |
| 1338 options, 'era', match, {GGGGG: 'narrow', GGG: 'short', GGGG: 'long'}); | 1370 options, 'era', match, {GGGGG: 'narrow', GGG: 'short', GGGG: 'long'}); |
| 1339 | 1371 |
| 1340 match = ldmlString.match(/y{1,2}/g); | 1372 match = %_CallFunction(ldmlString, /y{1,2}/g, StringMatch); |
| 1341 options = appendToDateTimeObject( | 1373 options = appendToDateTimeObject( |
| 1342 options, 'year', match, {y: 'numeric', yy: '2-digit'}); | 1374 options, 'year', match, {y: 'numeric', yy: '2-digit'}); |
| 1343 | 1375 |
| 1344 match = ldmlString.match(/M{1,5}/g); | 1376 match = %_CallFunction(ldmlString, /M{1,5}/g, StringMatch); |
| 1345 options = appendToDateTimeObject(options, 'month', match, {MM: '2-digit', | 1377 options = appendToDateTimeObject(options, 'month', match, {MM: '2-digit', |
| 1346 M: 'numeric', MMMMM: 'narrow', MMM: 'short', MMMM: 'long'}); | 1378 M: 'numeric', MMMMM: 'narrow', MMM: 'short', MMMM: 'long'}); |
| 1347 | 1379 |
| 1348 // Sometimes we get L instead of M for month - standalone name. | 1380 // Sometimes we get L instead of M for month - standalone name. |
| 1349 match = ldmlString.match(/L{1,5}/g); | 1381 match = %_CallFunction(ldmlString, /L{1,5}/g, StringMatch); |
| 1350 options = appendToDateTimeObject(options, 'month', match, {LL: '2-digit', | 1382 options = appendToDateTimeObject(options, 'month', match, {LL: '2-digit', |
| 1351 L: 'numeric', LLLLL: 'narrow', LLL: 'short', LLLL: 'long'}); | 1383 L: 'numeric', LLLLL: 'narrow', LLL: 'short', LLLL: 'long'}); |
| 1352 | 1384 |
| 1353 match = ldmlString.match(/d{1,2}/g); | 1385 match = %_CallFunction(ldmlString, /d{1,2}/g, StringMatch); |
| 1354 options = appendToDateTimeObject( | 1386 options = appendToDateTimeObject( |
| 1355 options, 'day', match, {d: 'numeric', dd: '2-digit'}); | 1387 options, 'day', match, {d: 'numeric', dd: '2-digit'}); |
| 1356 | 1388 |
| 1357 match = ldmlString.match(/h{1,2}/g); | 1389 match = %_CallFunction(ldmlString, /h{1,2}/g, StringMatch); |
| 1358 if (match !== null) { | 1390 if (match !== null) { |
| 1359 options['hour12'] = true; | 1391 options['hour12'] = true; |
| 1360 } | 1392 } |
| 1361 options = appendToDateTimeObject( | 1393 options = appendToDateTimeObject( |
| 1362 options, 'hour', match, {h: 'numeric', hh: '2-digit'}); | 1394 options, 'hour', match, {h: 'numeric', hh: '2-digit'}); |
| 1363 | 1395 |
| 1364 match = ldmlString.match(/H{1,2}/g); | 1396 match = %_CallFunction(ldmlString, /H{1,2}/g, StringMatch); |
| 1365 if (match !== null) { | 1397 if (match !== null) { |
| 1366 options['hour12'] = false; | 1398 options['hour12'] = false; |
| 1367 } | 1399 } |
| 1368 options = appendToDateTimeObject( | 1400 options = appendToDateTimeObject( |
| 1369 options, 'hour', match, {H: 'numeric', HH: '2-digit'}); | 1401 options, 'hour', match, {H: 'numeric', HH: '2-digit'}); |
| 1370 | 1402 |
| 1371 match = ldmlString.match(/m{1,2}/g); | 1403 match = %_CallFunction(ldmlString, /m{1,2}/g, StringMatch); |
| 1372 options = appendToDateTimeObject( | 1404 options = appendToDateTimeObject( |
| 1373 options, 'minute', match, {m: 'numeric', mm: '2-digit'}); | 1405 options, 'minute', match, {m: 'numeric', mm: '2-digit'}); |
| 1374 | 1406 |
| 1375 match = ldmlString.match(/s{1,2}/g); | 1407 match = %_CallFunction(ldmlString, /s{1,2}/g, StringMatch); |
| 1376 options = appendToDateTimeObject( | 1408 options = appendToDateTimeObject( |
| 1377 options, 'second', match, {s: 'numeric', ss: '2-digit'}); | 1409 options, 'second', match, {s: 'numeric', ss: '2-digit'}); |
| 1378 | 1410 |
| 1379 match = ldmlString.match(/z|zzzz/g); | 1411 match = %_CallFunction(ldmlString, /z|zzzz/g, StringMatch); |
| 1380 options = appendToDateTimeObject( | 1412 options = appendToDateTimeObject( |
| 1381 options, 'timeZoneName', match, {z: 'short', zzzz: 'long'}); | 1413 options, 'timeZoneName', match, {z: 'short', zzzz: 'long'}); |
| 1382 | 1414 |
| 1383 return options; | 1415 return options; |
| 1384 } | 1416 } |
| 1385 | 1417 |
| 1386 | 1418 |
| 1387 function appendToDateTimeObject(options, option, match, pairs) { | 1419 function appendToDateTimeObject(options, option, match, pairs) { |
| 1388 if (IS_NULL(match)) { | 1420 if (IS_NULL(match)) { |
| 1389 if (!options.hasOwnProperty(option)) { | 1421 if (!%HasOwnProperty(options, option)) { |
| 1390 defineWEProperty(options, option, UNDEFINED); | 1422 defineWEProperty(options, option, UNDEFINED); |
| 1391 } | 1423 } |
| 1392 return options; | 1424 return options; |
| 1393 } | 1425 } |
| 1394 | 1426 |
| 1395 var property = match[0]; | 1427 var property = match[0]; |
| 1396 defineWEProperty(options, option, pairs[property]); | 1428 defineWEProperty(options, option, pairs[property]); |
| 1397 | 1429 |
| 1398 return options; | 1430 return options; |
| 1399 } | 1431 } |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1654 | 1686 |
| 1655 | 1687 |
| 1656 /** | 1688 /** |
| 1657 * Returns a String value representing the result of calling ToNumber(date) | 1689 * Returns a String value representing the result of calling ToNumber(date) |
| 1658 * according to the effective locale and the formatting options of this | 1690 * according to the effective locale and the formatting options of this |
| 1659 * DateTimeFormat. | 1691 * DateTimeFormat. |
| 1660 */ | 1692 */ |
| 1661 function formatDate(formatter, dateValue) { | 1693 function formatDate(formatter, dateValue) { |
| 1662 var dateMs; | 1694 var dateMs; |
| 1663 if (IS_UNDEFINED(dateValue)) { | 1695 if (IS_UNDEFINED(dateValue)) { |
| 1664 dateMs = GlobalDate.now(); | 1696 dateMs = %DateCurrentTime(); |
| 1665 } else { | 1697 } else { |
| 1666 dateMs = $toNumber(dateValue); | 1698 dateMs = $toNumber(dateValue); |
| 1667 } | 1699 } |
| 1668 | 1700 |
| 1669 if (!IsFinite(dateMs)) throw MakeRangeError(kDateRange); | 1701 if (!IsFinite(dateMs)) throw MakeRangeError(kDateRange); |
| 1670 | 1702 |
| 1671 return %InternalDateFormat(%GetImplFromInitializedIntlObject(formatter), | 1703 return %InternalDateFormat(%GetImplFromInitializedIntlObject(formatter), |
| 1672 new GlobalDate(dateMs)); | 1704 new GlobalDate(dateMs)); |
| 1673 } | 1705 } |
| 1674 | 1706 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1694 * Returns canonical Area/Location name, or throws an exception if the zone | 1726 * Returns canonical Area/Location name, or throws an exception if the zone |
| 1695 * name is invalid IANA name. | 1727 * name is invalid IANA name. |
| 1696 */ | 1728 */ |
| 1697 function canonicalizeTimeZoneID(tzID) { | 1729 function canonicalizeTimeZoneID(tzID) { |
| 1698 // Skip undefined zones. | 1730 // Skip undefined zones. |
| 1699 if (IS_UNDEFINED(tzID)) { | 1731 if (IS_UNDEFINED(tzID)) { |
| 1700 return tzID; | 1732 return tzID; |
| 1701 } | 1733 } |
| 1702 | 1734 |
| 1703 // Special case handling (UTC, GMT). | 1735 // Special case handling (UTC, GMT). |
| 1704 var upperID = tzID.toUpperCase(); | 1736 var upperID = %StringToUpperCase(tzID); |
| 1705 if (upperID === 'UTC' || upperID === 'GMT' || | 1737 if (upperID === 'UTC' || upperID === 'GMT' || |
| 1706 upperID === 'ETC/UTC' || upperID === 'ETC/GMT') { | 1738 upperID === 'ETC/UTC' || upperID === 'ETC/GMT') { |
| 1707 return 'UTC'; | 1739 return 'UTC'; |
| 1708 } | 1740 } |
| 1709 | 1741 |
| 1710 // We expect only _ and / beside ASCII letters. | 1742 // We expect only _ and / beside ASCII letters. |
| 1711 // All inputs should conform to Area/Location from now on. | 1743 // All inputs should conform to Area/Location from now on. |
| 1712 var match = GetTimezoneNameCheckRE().exec(tzID); | 1744 var match = %_CallFunction(tzID, GetTimezoneNameCheckRE(), StringMatch); |
| 1713 if (IS_NULL(match)) throw MakeRangeError(kExpectedLocation, tzID); | 1745 if (IS_NULL(match)) throw MakeRangeError(kExpectedLocation, tzID); |
| 1714 | 1746 |
| 1715 var result = toTitleCaseWord(match[1]) + '/' + toTitleCaseWord(match[2]); | 1747 var result = toTitleCaseWord(match[1]) + '/' + toTitleCaseWord(match[2]); |
| 1716 var i = 3; | 1748 var i = 3; |
| 1717 while (!IS_UNDEFINED(match[i]) && i < match.length) { | 1749 while (!IS_UNDEFINED(match[i]) && i < match.length) { |
| 1718 result = result + '_' + toTitleCaseWord(match[i]); | 1750 result = result + '_' + toTitleCaseWord(match[i]); |
| 1719 i++; | 1751 i++; |
| 1720 } | 1752 } |
| 1721 | 1753 |
| 1722 return result; | 1754 return result; |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1961 if (%_IsConstructCall()) { | 1993 if (%_IsConstructCall()) { |
| 1962 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); | 1994 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); |
| 1963 } | 1995 } |
| 1964 | 1996 |
| 1965 CHECK_OBJECT_COERCIBLE(this, "String.prototype.normalize"); | 1997 CHECK_OBJECT_COERCIBLE(this, "String.prototype.normalize"); |
| 1966 | 1998 |
| 1967 var form = GlobalString(%_Arguments(0) || 'NFC'); | 1999 var form = GlobalString(%_Arguments(0) || 'NFC'); |
| 1968 | 2000 |
| 1969 var NORMALIZATION_FORMS = ['NFC', 'NFD', 'NFKC', 'NFKD']; | 2001 var NORMALIZATION_FORMS = ['NFC', 'NFD', 'NFKC', 'NFKD']; |
| 1970 | 2002 |
| 1971 var normalizationForm = NORMALIZATION_FORMS.indexOf(form); | 2003 var normalizationForm = |
| 2004 %_CallFunction(NORMALIZATION_FORMS, form, ArrayIndexOf); |
| 1972 if (normalizationForm === -1) { | 2005 if (normalizationForm === -1) { |
| 1973 throw MakeRangeError(kNormalizationForm, NORMALIZATION_FORMS.join(', ')); | 2006 throw MakeRangeError(kNormalizationForm, |
| 2007 %_CallFunction(NORMALIZATION_FORMS, ', ', ArrayJoin)); |
| 1974 } | 2008 } |
| 1975 | 2009 |
| 1976 return %StringNormalize(this, normalizationForm); | 2010 return %StringNormalize(this, normalizationForm); |
| 1977 } | 2011 } |
| 1978 ); | 2012 ); |
| 1979 | 2013 |
| 1980 | 2014 |
| 1981 /** | 2015 /** |
| 1982 * Formats a Number object (this) using locale and options values. | 2016 * Formats a Number object (this) using locale and options values. |
| 1983 * If locale or options are omitted, defaults are used. | 2017 * If locale or options are omitted, defaults are used. |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2065 } | 2099 } |
| 2066 | 2100 |
| 2067 var locales = %_Arguments(0); | 2101 var locales = %_Arguments(0); |
| 2068 var options = %_Arguments(1); | 2102 var options = %_Arguments(1); |
| 2069 return toLocaleDateTime( | 2103 return toLocaleDateTime( |
| 2070 this, locales, options, 'time', 'time', 'dateformattime'); | 2104 this, locales, options, 'time', 'time', 'dateformattime'); |
| 2071 } | 2105 } |
| 2072 ); | 2106 ); |
| 2073 | 2107 |
| 2074 }) | 2108 }) |
| OLD | NEW |