| 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, shared, exports) { | 11 (function(global, shared, exports) { |
| 12 | 12 |
| 13 "use strict"; | 13 "use strict"; |
| 14 | 14 |
| 15 %CheckIsBootstrapping(); | 15 %CheckIsBootstrapping(); |
| 16 | 16 |
| 17 var GlobalBoolean = global.Boolean; | 17 var GlobalBoolean = global.Boolean; |
| 18 var GlobalDate = global.Date; | 18 var GlobalDate = global.Date; |
| 19 var GlobalNumber = global.Number; | 19 var GlobalNumber = global.Number; |
| 20 var GlobalRegExp = global.RegExp; | 20 var GlobalRegExp = global.RegExp; |
| 21 var GlobalString = global.String; | 21 var GlobalString = global.String; |
| 22 | 22 |
| 23 var undefined = global.undefined; | 23 var undefined = global.undefined; |
| 24 | 24 |
| 25 var Intl = {}; | 25 var Intl = {}; |
| 26 | 26 |
| 27 %AddNamedProperty(global, "Intl", Intl, DONT_ENUM); | 27 %AddNamedProperty(global, "Intl", Intl, DONT_ENUM); |
| 28 | 28 |
| 29 var AVAILABLE_SERVICES = ['collator', | |
| 30 'numberformat', | |
| 31 'dateformat', | |
| 32 'breakiterator']; | |
| 33 | |
| 34 var NORMALIZATION_FORMS = ['NFC', | |
| 35 'NFD', | |
| 36 'NFKC', | |
| 37 'NFKD']; | |
| 38 | |
| 39 /** | 29 /** |
| 40 * Caches available locales for each service. | 30 * Caches available locales for each service. |
| 41 */ | 31 */ |
| 42 var AVAILABLE_LOCALES = { | 32 var AVAILABLE_LOCALES = { |
| 43 'collator': undefined, | 33 'collator': undefined, |
| 44 'numberformat': undefined, | 34 'numberformat': undefined, |
| 45 'dateformat': undefined, | 35 'dateformat': undefined, |
| 46 'breakiterator': undefined | 36 'breakiterator': undefined |
| 47 }; | 37 }; |
| 48 | 38 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 | 134 |
| 145 function GetTimezoneNameCheckRE() { | 135 function GetTimezoneNameCheckRE() { |
| 146 if (TIMEZONE_NAME_CHECK_RE === undefined) { | 136 if (TIMEZONE_NAME_CHECK_RE === undefined) { |
| 147 TIMEZONE_NAME_CHECK_RE = | 137 TIMEZONE_NAME_CHECK_RE = |
| 148 new GlobalRegExp('^([A-Za-z]+)/([A-Za-z]+)(?:_([A-Za-z]+))*$'); | 138 new GlobalRegExp('^([A-Za-z]+)/([A-Za-z]+)(?:_([A-Za-z]+))*$'); |
| 149 } | 139 } |
| 150 return TIMEZONE_NAME_CHECK_RE; | 140 return TIMEZONE_NAME_CHECK_RE; |
| 151 } | 141 } |
| 152 | 142 |
| 153 /** | 143 /** |
| 154 * Maps ICU calendar names into LDML type. | |
| 155 */ | |
| 156 var ICU_CALENDAR_MAP = { | |
| 157 'gregorian': 'gregory', | |
| 158 'japanese': 'japanese', | |
| 159 'buddhist': 'buddhist', | |
| 160 'roc': 'roc', | |
| 161 'persian': 'persian', | |
| 162 'islamic-civil': 'islamicc', | |
| 163 'islamic': 'islamic', | |
| 164 'hebrew': 'hebrew', | |
| 165 'chinese': 'chinese', | |
| 166 'indian': 'indian', | |
| 167 'coptic': 'coptic', | |
| 168 'ethiopic': 'ethiopic', | |
| 169 'ethiopic-amete-alem': 'ethioaa' | |
| 170 }; | |
| 171 | |
| 172 /** | |
| 173 * Map of Unicode extensions to option properties, and their values and types, | |
| 174 * for a collator. | |
| 175 */ | |
| 176 var COLLATOR_KEY_MAP = { | |
| 177 'kn': {'property': 'numeric', 'type': 'boolean'}, | |
| 178 'kf': {'property': 'caseFirst', 'type': 'string', | |
| 179 'values': ['false', 'lower', 'upper']} | |
| 180 }; | |
| 181 | |
| 182 /** | |
| 183 * Map of Unicode extensions to option properties, and their values and types, | |
| 184 * for a number format. | |
| 185 */ | |
| 186 var NUMBER_FORMAT_KEY_MAP = { | |
| 187 'nu': {'property': undefined, 'type': 'string'} | |
| 188 }; | |
| 189 | |
| 190 /** | |
| 191 * Map of Unicode extensions to option properties, and their values and types, | |
| 192 * for a date/time format. | |
| 193 */ | |
| 194 var DATETIME_FORMAT_KEY_MAP = { | |
| 195 'ca': {'property': undefined, 'type': 'string'}, | |
| 196 'nu': {'property': undefined, 'type': 'string'} | |
| 197 }; | |
| 198 | |
| 199 /** | |
| 200 * Allowed -u-co- values. List taken from: | |
| 201 * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml | |
| 202 */ | |
| 203 var ALLOWED_CO_VALUES = [ | |
| 204 'big5han', 'dict', 'direct', 'ducet', 'gb2312', 'phonebk', 'phonetic', | |
| 205 'pinyin', 'reformed', 'searchjl', 'stroke', 'trad', 'unihan', 'zhuyin' | |
| 206 ]; | |
| 207 | |
| 208 /** | |
| 209 * Error message for when function object is created with new and it's not | |
| 210 * a constructor. | |
| 211 */ | |
| 212 var ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR = | |
| 213 'Function object that\'s not a constructor was created with new'; | |
| 214 | |
| 215 | |
| 216 /** | |
| 217 * Adds bound method to the prototype of the given object. | 144 * Adds bound method to the prototype of the given object. |
| 218 */ | 145 */ |
| 219 function addBoundMethod(obj, methodName, implementation, length) { | 146 function addBoundMethod(obj, methodName, implementation, length) { |
| 220 function getter() { | 147 function getter() { |
| 221 if (!%IsInitializedIntlObject(this)) { | 148 if (!%IsInitializedIntlObject(this)) { |
| 222 throw MakeTypeError(kMethodCalledOnWrongObject, methodName); | 149 throw MakeTypeError(kMethodCalledOnWrongObject, methodName); |
| 223 } | 150 } |
| 224 var internalName = '__bound' + methodName + '__'; | 151 var internalName = '__bound' + methodName + '__'; |
| 225 if (this[internalName] === undefined) { | 152 if (this[internalName] === undefined) { |
| 226 var that = this; | 153 var that = this; |
| (...skipping 660 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 887 defineWEProperty(internalOptions, 'ignorePunctuation', getOption( | 814 defineWEProperty(internalOptions, 'ignorePunctuation', getOption( |
| 888 'ignorePunctuation', 'boolean', undefined, false)); | 815 'ignorePunctuation', 'boolean', undefined, false)); |
| 889 | 816 |
| 890 var locale = resolveLocale('collator', locales, options); | 817 var locale = resolveLocale('collator', locales, options); |
| 891 | 818 |
| 892 // ICU can't take kb, kc... parameters through localeID, so we need to pass | 819 // ICU can't take kb, kc... parameters through localeID, so we need to pass |
| 893 // them as options. | 820 // them as options. |
| 894 // One exception is -co- which has to be part of the extension, but only for | 821 // One exception is -co- which has to be part of the extension, but only for |
| 895 // usage: sort, and its value can't be 'standard' or 'search'. | 822 // usage: sort, and its value can't be 'standard' or 'search'. |
| 896 var extensionMap = parseExtension(locale.extension); | 823 var extensionMap = parseExtension(locale.extension); |
| 824 |
| 825 /** |
| 826 * Map of Unicode extensions to option properties, and their values and types, |
| 827 * for a collator. |
| 828 */ |
| 829 var COLLATOR_KEY_MAP = { |
| 830 'kn': {'property': 'numeric', 'type': 'boolean'}, |
| 831 'kf': {'property': 'caseFirst', 'type': 'string', |
| 832 'values': ['false', 'lower', 'upper']} |
| 833 }; |
| 834 |
| 897 setOptions( | 835 setOptions( |
| 898 options, extensionMap, COLLATOR_KEY_MAP, getOption, internalOptions); | 836 options, extensionMap, COLLATOR_KEY_MAP, getOption, internalOptions); |
| 899 | 837 |
| 900 var collation = 'default'; | 838 var collation = 'default'; |
| 901 var extension = ''; | 839 var extension = ''; |
| 902 if (extensionMap.hasOwnProperty('co') && internalOptions.usage === 'sort') { | 840 if (extensionMap.hasOwnProperty('co') && internalOptions.usage === 'sort') { |
| 841 |
| 842 /** |
| 843 * Allowed -u-co- values. List taken from: |
| 844 * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml |
| 845 */ |
| 846 var ALLOWED_CO_VALUES = [ |
| 847 'big5han', 'dict', 'direct', 'ducet', 'gb2312', 'phonebk', 'phonetic', |
| 848 'pinyin', 'reformed', 'searchjl', 'stroke', 'trad', 'unihan', 'zhuyin' |
| 849 ]; |
| 850 |
| 903 if (ALLOWED_CO_VALUES.indexOf(extensionMap.co) !== -1) { | 851 if (ALLOWED_CO_VALUES.indexOf(extensionMap.co) !== -1) { |
| 904 extension = '-u-co-' + extensionMap.co; | 852 extension = '-u-co-' + extensionMap.co; |
| 905 // ICU can't tell us what the collation is, so save user's input. | 853 // ICU can't tell us what the collation is, so save user's input. |
| 906 collation = extensionMap.co; | 854 collation = extensionMap.co; |
| 907 } | 855 } |
| 908 } else if (internalOptions.usage === 'search') { | 856 } else if (internalOptions.usage === 'search') { |
| 909 extension = '-u-co-search'; | 857 extension = '-u-co-search'; |
| 910 } | 858 } |
| 911 defineWEProperty(internalOptions, 'collation', collation); | 859 defineWEProperty(internalOptions, 'collation', collation); |
| 912 | 860 |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1119 defineWEProperty(internalOptions, 'maximumSignificantDigits', mxsd); | 1067 defineWEProperty(internalOptions, 'maximumSignificantDigits', mxsd); |
| 1120 } | 1068 } |
| 1121 | 1069 |
| 1122 // Grouping. | 1070 // Grouping. |
| 1123 defineWEProperty(internalOptions, 'useGrouping', getOption( | 1071 defineWEProperty(internalOptions, 'useGrouping', getOption( |
| 1124 'useGrouping', 'boolean', undefined, true)); | 1072 'useGrouping', 'boolean', undefined, true)); |
| 1125 | 1073 |
| 1126 // ICU prefers options to be passed using -u- extension key/values for | 1074 // ICU prefers options to be passed using -u- extension key/values for |
| 1127 // number format, so we need to build that. | 1075 // number format, so we need to build that. |
| 1128 var extensionMap = parseExtension(locale.extension); | 1076 var extensionMap = parseExtension(locale.extension); |
| 1077 |
| 1078 /** |
| 1079 * Map of Unicode extensions to option properties, and their values and types, |
| 1080 * for a number format. |
| 1081 */ |
| 1082 var NUMBER_FORMAT_KEY_MAP = { |
| 1083 'nu': {'property': undefined, 'type': 'string'} |
| 1084 }; |
| 1085 |
| 1129 var extension = setOptions(options, extensionMap, NUMBER_FORMAT_KEY_MAP, | 1086 var extension = setOptions(options, extensionMap, NUMBER_FORMAT_KEY_MAP, |
| 1130 getOption, internalOptions); | 1087 getOption, internalOptions); |
| 1131 | 1088 |
| 1132 var requestedLocale = locale.locale + extension; | 1089 var requestedLocale = locale.locale + extension; |
| 1133 var resolved = $objectDefineProperties({}, { | 1090 var resolved = $objectDefineProperties({}, { |
| 1134 currency: {writable: true}, | 1091 currency: {writable: true}, |
| 1135 currencyDisplay: {writable: true}, | 1092 currencyDisplay: {writable: true}, |
| 1136 locale: {writable: true}, | 1093 locale: {writable: true}, |
| 1137 maximumFractionDigits: {writable: true}, | 1094 maximumFractionDigits: {writable: true}, |
| 1138 minimumFractionDigits: {writable: true}, | 1095 minimumFractionDigits: {writable: true}, |
| (...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1513 | 1470 |
| 1514 // Filter out supported extension keys so we know what to put in resolved | 1471 // Filter out supported extension keys so we know what to put in resolved |
| 1515 // section later on. | 1472 // section later on. |
| 1516 // We need to pass calendar and number system to the method. | 1473 // We need to pass calendar and number system to the method. |
| 1517 var tz = canonicalizeTimeZoneID(options.timeZone); | 1474 var tz = canonicalizeTimeZoneID(options.timeZone); |
| 1518 | 1475 |
| 1519 // ICU prefers options to be passed using -u- extension key/values, so | 1476 // ICU prefers options to be passed using -u- extension key/values, so |
| 1520 // we need to build that. | 1477 // we need to build that. |
| 1521 var internalOptions = {}; | 1478 var internalOptions = {}; |
| 1522 var extensionMap = parseExtension(locale.extension); | 1479 var extensionMap = parseExtension(locale.extension); |
| 1480 |
| 1481 /** |
| 1482 * Map of Unicode extensions to option properties, and their values and types, |
| 1483 * for a date/time format. |
| 1484 */ |
| 1485 var DATETIME_FORMAT_KEY_MAP = { |
| 1486 'ca': {'property': undefined, 'type': 'string'}, |
| 1487 'nu': {'property': undefined, 'type': 'string'} |
| 1488 }; |
| 1489 |
| 1523 var extension = setOptions(options, extensionMap, DATETIME_FORMAT_KEY_MAP, | 1490 var extension = setOptions(options, extensionMap, DATETIME_FORMAT_KEY_MAP, |
| 1524 getOption, internalOptions); | 1491 getOption, internalOptions); |
| 1525 | 1492 |
| 1526 var requestedLocale = locale.locale + extension; | 1493 var requestedLocale = locale.locale + extension; |
| 1527 var resolved = $objectDefineProperties({}, { | 1494 var resolved = $objectDefineProperties({}, { |
| 1528 calendar: {writable: true}, | 1495 calendar: {writable: true}, |
| 1529 day: {writable: true}, | 1496 day: {writable: true}, |
| 1530 era: {writable: true}, | 1497 era: {writable: true}, |
| 1531 hour12: {writable: true}, | 1498 hour12: {writable: true}, |
| 1532 hour: {writable: true}, | 1499 hour: {writable: true}, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1584 */ | 1551 */ |
| 1585 %AddNamedProperty(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() { | 1552 %AddNamedProperty(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() { |
| 1586 if (%_IsConstructCall()) { | 1553 if (%_IsConstructCall()) { |
| 1587 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); | 1554 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); |
| 1588 } | 1555 } |
| 1589 | 1556 |
| 1590 if (!%IsInitializedIntlObjectOfType(this, 'dateformat')) { | 1557 if (!%IsInitializedIntlObjectOfType(this, 'dateformat')) { |
| 1591 throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "DateTimeFormat"); | 1558 throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "DateTimeFormat"); |
| 1592 } | 1559 } |
| 1593 | 1560 |
| 1561 /** |
| 1562 * Maps ICU calendar names into LDML type. |
| 1563 */ |
| 1564 var ICU_CALENDAR_MAP = { |
| 1565 'gregorian': 'gregory', |
| 1566 'japanese': 'japanese', |
| 1567 'buddhist': 'buddhist', |
| 1568 'roc': 'roc', |
| 1569 'persian': 'persian', |
| 1570 'islamic-civil': 'islamicc', |
| 1571 'islamic': 'islamic', |
| 1572 'hebrew': 'hebrew', |
| 1573 'chinese': 'chinese', |
| 1574 'indian': 'indian', |
| 1575 'coptic': 'coptic', |
| 1576 'ethiopic': 'ethiopic', |
| 1577 'ethiopic-amete-alem': 'ethioaa' |
| 1578 }; |
| 1579 |
| 1594 var format = this; | 1580 var format = this; |
| 1595 var fromPattern = fromLDMLString(format.resolved.pattern); | 1581 var fromPattern = fromLDMLString(format.resolved.pattern); |
| 1596 var userCalendar = ICU_CALENDAR_MAP[format.resolved.calendar]; | 1582 var userCalendar = ICU_CALENDAR_MAP[format.resolved.calendar]; |
| 1597 if (userCalendar === undefined) { | 1583 if (userCalendar === undefined) { |
| 1598 // Use ICU name if we don't have a match. It shouldn't happen, but | 1584 // Use ICU name if we don't have a match. It shouldn't happen, but |
| 1599 // it would be too strict to throw for this. | 1585 // it would be too strict to throw for this. |
| 1600 userCalendar = format.resolved.calendar; | 1586 userCalendar = format.resolved.calendar; |
| 1601 } | 1587 } |
| 1602 | 1588 |
| 1603 var locale = getOptimalLanguageTag(format.resolved.requestedLocale, | 1589 var locale = getOptimalLanguageTag(format.resolved.requestedLocale, |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1946 */ | 1932 */ |
| 1947 $overrideFunction(GlobalString.prototype, 'normalize', function(that) { | 1933 $overrideFunction(GlobalString.prototype, 'normalize', function(that) { |
| 1948 if (%_IsConstructCall()) { | 1934 if (%_IsConstructCall()) { |
| 1949 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); | 1935 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); |
| 1950 } | 1936 } |
| 1951 | 1937 |
| 1952 CHECK_OBJECT_COERCIBLE(this, "String.prototype.normalize"); | 1938 CHECK_OBJECT_COERCIBLE(this, "String.prototype.normalize"); |
| 1953 | 1939 |
| 1954 var form = GlobalString(%_Arguments(0) || 'NFC'); | 1940 var form = GlobalString(%_Arguments(0) || 'NFC'); |
| 1955 | 1941 |
| 1942 var NORMALIZATION_FORMS = ['NFC', 'NFD', 'NFKC', 'NFKD']; |
| 1943 |
| 1956 var normalizationForm = NORMALIZATION_FORMS.indexOf(form); | 1944 var normalizationForm = NORMALIZATION_FORMS.indexOf(form); |
| 1957 if (normalizationForm === -1) { | 1945 if (normalizationForm === -1) { |
| 1958 throw MakeRangeError(kNormalizationForm, NORMALIZATION_FORMS.join(', ')); | 1946 throw MakeRangeError(kNormalizationForm, NORMALIZATION_FORMS.join(', ')); |
| 1959 } | 1947 } |
| 1960 | 1948 |
| 1961 return %StringNormalize(this, normalizationForm); | 1949 return %StringNormalize(this, normalizationForm); |
| 1962 } | 1950 } |
| 1963 ); | 1951 ); |
| 1964 | 1952 |
| 1965 | 1953 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2052 } | 2040 } |
| 2053 | 2041 |
| 2054 var locales = %_Arguments(0); | 2042 var locales = %_Arguments(0); |
| 2055 var options = %_Arguments(1); | 2043 var options = %_Arguments(1); |
| 2056 return toLocaleDateTime( | 2044 return toLocaleDateTime( |
| 2057 this, locales, options, 'time', 'time', 'dateformattime'); | 2045 this, locales, options, 'time', 'time', 'dateformattime'); |
| 2058 } | 2046 } |
| 2059 ); | 2047 ); |
| 2060 | 2048 |
| 2061 }) | 2049 }) |
| OLD | NEW |