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 */ |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 } | 377 } |
378 | 378 |
379 return defaultValue; | 379 return defaultValue; |
380 } | 380 } |
381 | 381 |
382 return getOption; | 382 return getOption; |
383 } | 383 } |
384 | 384 |
385 | 385 |
386 /** | 386 /** |
| 387 * Ecma 402 9.2.5 |
| 388 * TODO(jshin): relevantExtensionKeys and localeData need to be taken into |
| 389 * account per spec. |
387 * Compares a BCP 47 language priority list requestedLocales against the locales | 390 * Compares a BCP 47 language priority list requestedLocales against the locales |
388 * in availableLocales and determines the best available language to meet the | 391 * in availableLocales and determines the best available language to meet the |
389 * request. Two algorithms are available to match the locales: the Lookup | 392 * request. Two algorithms are available to match the locales: the Lookup |
390 * algorithm described in RFC 4647 section 3.4, and an implementation dependent | 393 * algorithm described in RFC 4647 section 3.4, and an implementation dependent |
391 * best-fit algorithm. Independent of the locale matching algorithm, options | 394 * best-fit algorithm. Independent of the locale matching algorithm, options |
392 * specified through Unicode locale extension sequences are negotiated | 395 * specified through Unicode locale extension sequences are negotiated |
393 * separately, taking the caller's relevant extension keys and locale data as | 396 * separately, taking the caller's relevant extension keys and locale data as |
394 * well as client-provided options into consideration. Returns an object with | 397 * well as client-provided options into consideration. Returns an object with |
395 * a locale property whose value is the language tag of the selected locale, | 398 * a locale property whose value is the language tag of the selected locale, |
396 * and properties for each key in relevantExtensionKeys providing the selected | 399 * and properties for each key in relevantExtensionKeys providing the selected |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 function bestFitMatcher(service, requestedLocales) { | 463 function bestFitMatcher(service, requestedLocales) { |
461 // TODO(cira): implement better best fit algorithm. | 464 // TODO(cira): implement better best fit algorithm. |
462 return lookupMatcher(service, requestedLocales); | 465 return lookupMatcher(service, requestedLocales); |
463 } | 466 } |
464 | 467 |
465 | 468 |
466 /** | 469 /** |
467 * Parses Unicode extension into key - value map. | 470 * Parses Unicode extension into key - value map. |
468 * Returns empty object if the extension string is invalid. | 471 * Returns empty object if the extension string is invalid. |
469 * We are not concerned with the validity of the values at this point. | 472 * We are not concerned with the validity of the values at this point. |
| 473 * 'attribute' in RFC 6047 is not supported. Keys without explicit |
| 474 * values are assigned UNDEFINED. |
| 475 * TODO(jshin): Fix the handling of 'attribute' (in RFC 6047, but none |
| 476 * has been defined so that it's not used) and boolean keys without |
| 477 * an explicit value. |
470 */ | 478 */ |
471 function parseExtension(extension) { | 479 function parseExtension(extension) { |
472 var extensionSplit = %StringSplit(extension, '-', kMaxUint32); | 480 var extensionSplit = %StringSplit(extension, '-', kMaxUint32); |
473 | 481 |
474 // Assume ['', 'u', ...] input, but don't throw. | 482 // Assume ['', 'u', ...] input, but don't throw. |
475 if (extensionSplit.length <= 2 || | 483 if (extensionSplit.length <= 2 || |
476 (extensionSplit[0] !== '' && extensionSplit[1] !== 'u')) { | 484 (extensionSplit[0] !== '' && extensionSplit[1] !== 'u')) { |
477 return {}; | 485 return {}; |
478 } | 486 } |
479 | 487 |
480 // Key is {2}alphanum, value is {3,8}alphanum. | 488 // Key is {2}alphanum, value is {3,8}alphanum. |
481 // Some keys may not have explicit values (booleans). | 489 // Some keys may not have explicit values (booleans). |
482 var extensionMap = {}; | 490 var extensionMap = {}; |
483 var previousKey = UNDEFINED; | 491 var key = UNDEFINED; |
| 492 var value = UNDEFINED; |
484 for (var i = 2; i < extensionSplit.length; ++i) { | 493 for (var i = 2; i < extensionSplit.length; ++i) { |
485 var length = extensionSplit[i].length; | 494 var length = extensionSplit[i].length; |
486 var element = extensionSplit[i]; | 495 var element = extensionSplit[i]; |
487 if (length === 2) { | 496 if (length === 2) { |
488 extensionMap[element] = UNDEFINED; | 497 if (!IS_UNDEFINED(key)) { |
489 previousKey = element; | 498 if (!(key in extensionMap)) { |
490 } else if (length >= 3 && length <=8 && !IS_UNDEFINED(previousKey)) { | 499 extensionMap[key] = value; |
491 extensionMap[previousKey] = element; | 500 } |
492 previousKey = UNDEFINED; | 501 value = UNDEFINED; |
| 502 } |
| 503 key = element; |
| 504 } else if (length >= 3 && length <= 8 && !IS_UNDEFINED(key)) { |
| 505 if (IS_UNDEFINED(value)) { |
| 506 value = element; |
| 507 } else { |
| 508 value = value + "-" + element; |
| 509 } |
493 } else { | 510 } else { |
494 // There is a value that's too long, or that doesn't have a key. | 511 // There is a value that's too long, or that doesn't have a key. |
495 return {}; | 512 return {}; |
496 } | 513 } |
497 } | 514 } |
| 515 if (!IS_UNDEFINED(key) && !(key in extensionMap)) { |
| 516 extensionMap[key] = value; |
| 517 } |
498 | 518 |
499 return extensionMap; | 519 return extensionMap; |
500 } | 520 } |
501 | 521 |
502 | 522 |
503 /** | 523 /** |
504 * Populates internalOptions object with boolean key-value pairs | 524 * Populates internalOptions object with boolean key-value pairs |
505 * from extensionMap and options. | 525 * from extensionMap and options. |
506 * Returns filtered extension (number and date format constructors use | 526 * Returns filtered extension (number and date format constructors use |
507 * Unicode extensions for passing parameters to ICU). | 527 * Unicode extensions for passing parameters to ICU). |
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
910 if (IS_UNDEFINED(sensitivity) && internalOptions.usage === 'sort') { | 930 if (IS_UNDEFINED(sensitivity) && internalOptions.usage === 'sort') { |
911 sensitivity = 'variant'; | 931 sensitivity = 'variant'; |
912 } | 932 } |
913 defineWEProperty(internalOptions, 'sensitivity', sensitivity); | 933 defineWEProperty(internalOptions, 'sensitivity', sensitivity); |
914 | 934 |
915 defineWEProperty(internalOptions, 'ignorePunctuation', getOption( | 935 defineWEProperty(internalOptions, 'ignorePunctuation', getOption( |
916 'ignorePunctuation', 'boolean', UNDEFINED, false)); | 936 'ignorePunctuation', 'boolean', UNDEFINED, false)); |
917 | 937 |
918 var locale = resolveLocale('collator', locales, options); | 938 var locale = resolveLocale('collator', locales, options); |
919 | 939 |
| 940 // TODO(jshin): ICU now can take kb, kc, etc. Switch over to using ICU |
| 941 // directly. See Collator::InitializeCollator and |
| 942 // Collator::CreateICUCollator in src/i18n.cc |
920 // ICU can't take kb, kc... parameters through localeID, so we need to pass | 943 // ICU can't take kb, kc... parameters through localeID, so we need to pass |
921 // them as options. | 944 // them as options. |
922 // One exception is -co- which has to be part of the extension, but only for | 945 // One exception is -co- which has to be part of the extension, but only for |
923 // usage: sort, and its value can't be 'standard' or 'search'. | 946 // usage: sort, and its value can't be 'standard' or 'search'. |
924 var extensionMap = parseExtension(locale.extension); | 947 var extensionMap = parseExtension(locale.extension); |
925 | 948 |
926 /** | 949 /** |
927 * Map of Unicode extensions to option properties, and their values and types, | 950 * Map of Unicode extensions to option properties, and their values and types, |
928 * for a collator. | 951 * for a collator. |
929 */ | 952 */ |
(...skipping 727 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1657 InstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() { | 1680 InstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() { |
1658 if (!IS_UNDEFINED(new.target)) { | 1681 if (!IS_UNDEFINED(new.target)) { |
1659 throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); | 1682 throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); |
1660 } | 1683 } |
1661 | 1684 |
1662 if (!%IsInitializedIntlObjectOfType(this, 'dateformat')) { | 1685 if (!%IsInitializedIntlObjectOfType(this, 'dateformat')) { |
1663 throw %make_type_error(kResolvedOptionsCalledOnNonObject, "DateTimeFormat"
); | 1686 throw %make_type_error(kResolvedOptionsCalledOnNonObject, "DateTimeFormat"
); |
1664 } | 1687 } |
1665 | 1688 |
1666 /** | 1689 /** |
1667 * Maps ICU calendar names into LDML type. | 1690 * Maps ICU calendar names to LDML/BCP47 types for key 'ca'. |
| 1691 * See typeMap section in third_party/icu/source/data/misc/keyTypeData.txt |
| 1692 * and |
| 1693 * http://www.unicode.org/repos/cldr/tags/latest/common/bcp47/calendar.xml |
1668 */ | 1694 */ |
1669 var ICU_CALENDAR_MAP = { | 1695 var ICU_CALENDAR_MAP = { |
1670 'gregorian': 'gregory', | 1696 'gregorian': 'gregory', |
1671 'japanese': 'japanese', | |
1672 'buddhist': 'buddhist', | |
1673 'roc': 'roc', | |
1674 'persian': 'persian', | |
1675 'islamic-civil': 'islamicc', | |
1676 'islamic': 'islamic', | |
1677 'hebrew': 'hebrew', | |
1678 'chinese': 'chinese', | |
1679 'indian': 'indian', | |
1680 'coptic': 'coptic', | |
1681 'ethiopic': 'ethiopic', | |
1682 'ethiopic-amete-alem': 'ethioaa' | 1697 'ethiopic-amete-alem': 'ethioaa' |
1683 }; | 1698 }; |
1684 | 1699 |
1685 var format = this; | 1700 var format = this; |
1686 var fromPattern = fromLDMLString(format[resolvedSymbol][patternSymbol]); | 1701 var fromPattern = fromLDMLString(format[resolvedSymbol][patternSymbol]); |
1687 var userCalendar = ICU_CALENDAR_MAP[format[resolvedSymbol].calendar]; | 1702 var userCalendar = ICU_CALENDAR_MAP[format[resolvedSymbol].calendar]; |
1688 if (IS_UNDEFINED(userCalendar)) { | 1703 if (IS_UNDEFINED(userCalendar)) { |
1689 // Use ICU name if we don't have a match. It shouldn't happen, but | 1704 // No match means that ICU's legacy name is identical to LDML/BCP type. |
1690 // it would be too strict to throw for this. | |
1691 userCalendar = format[resolvedSymbol].calendar; | 1705 userCalendar = format[resolvedSymbol].calendar; |
1692 } | 1706 } |
1693 | 1707 |
1694 var locale = getOptimalLanguageTag(format[resolvedSymbol].requestedLocale, | 1708 var locale = getOptimalLanguageTag(format[resolvedSymbol].requestedLocale, |
1695 format[resolvedSymbol].locale); | 1709 format[resolvedSymbol].locale); |
1696 | 1710 |
1697 var result = { | 1711 var result = { |
1698 locale: locale, | 1712 locale: locale, |
1699 numberingSystem: format[resolvedSymbol].numberingSystem, | 1713 numberingSystem: format[resolvedSymbol].numberingSystem, |
1700 calendar: userCalendar, | 1714 calendar: userCalendar, |
(...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2246 } | 2260 } |
2247 ); | 2261 ); |
2248 | 2262 |
2249 utils.Export(function(to) { | 2263 utils.Export(function(to) { |
2250 to.AddBoundMethod = AddBoundMethod; | 2264 to.AddBoundMethod = AddBoundMethod; |
2251 to.IntlParseDate = IntlParseDate; | 2265 to.IntlParseDate = IntlParseDate; |
2252 to.IntlParseNumber = IntlParseNumber; | 2266 to.IntlParseNumber = IntlParseNumber; |
2253 }); | 2267 }); |
2254 | 2268 |
2255 }) | 2269 }) |
OLD | NEW |