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 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
135 'numberformat': UNDEFINED, | 135 'numberformat': UNDEFINED, |
136 'dateformat': UNDEFINED, | 136 'dateformat': UNDEFINED, |
137 'breakiterator': UNDEFINED | 137 'breakiterator': UNDEFINED |
138 }; | 138 }; |
139 | 139 |
140 /** | 140 /** |
141 * Caches default ICU locale. | 141 * Caches default ICU locale. |
142 */ | 142 */ |
143 var DEFAULT_ICU_LOCALE = UNDEFINED; | 143 var DEFAULT_ICU_LOCALE = UNDEFINED; |
144 | 144 |
145 function GetDefaultICULocaleJS() { | |
146 if (IS_UNDEFINED(DEFAULT_ICU_LOCALE)) { | |
147 DEFAULT_ICU_LOCALE = %GetDefaultICULocale(); | |
148 } | |
149 return DEFAULT_ICU_LOCALE; | |
150 } | |
151 | |
145 /** | 152 /** |
146 * Unicode extension regular expression. | 153 * Unicode extension regular expression. |
147 */ | 154 */ |
148 var UNICODE_EXTENSION_RE = UNDEFINED; | 155 var UNICODE_EXTENSION_RE = UNDEFINED; |
149 | 156 |
150 function GetUnicodeExtensionRE() { | 157 function GetUnicodeExtensionRE() { |
151 if (IS_UNDEFINED(UNDEFINED)) { | 158 if (IS_UNDEFINED(UNDEFINED)) { |
152 UNICODE_EXTENSION_RE = new GlobalRegExp('-u(-[a-z0-9]{2,8})+', 'g'); | 159 UNICODE_EXTENSION_RE = new GlobalRegExp('-u(-[a-z0-9]{2,8})+', 'g'); |
153 } | 160 } |
154 return UNICODE_EXTENSION_RE; | 161 return UNICODE_EXTENSION_RE; |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
439 // Truncate locale if possible. | 446 // Truncate locale if possible. |
440 var pos = %_Call(StringLastIndexOf, locale, '-'); | 447 var pos = %_Call(StringLastIndexOf, locale, '-'); |
441 if (pos === -1) { | 448 if (pos === -1) { |
442 break; | 449 break; |
443 } | 450 } |
444 locale = %_Call(StringSubstring, locale, 0, pos); | 451 locale = %_Call(StringSubstring, locale, 0, pos); |
445 } while (true); | 452 } while (true); |
446 } | 453 } |
447 | 454 |
448 // Didn't find a match, return default. | 455 // Didn't find a match, return default. |
449 if (IS_UNDEFINED(DEFAULT_ICU_LOCALE)) { | 456 return {'locale': GetDefaultICULocaleJS(), 'extension': '', 'position': -1}; |
450 DEFAULT_ICU_LOCALE = %GetDefaultICULocale(); | |
451 } | |
452 | |
453 return {'locale': DEFAULT_ICU_LOCALE, 'extension': '', 'position': -1}; | |
454 } | 457 } |
455 | 458 |
456 | 459 |
457 /** | 460 /** |
458 * Returns best matched supported locale and extension info using | 461 * Returns best matched supported locale and extension info using |
459 * implementation dependend algorithm. | 462 * implementation dependend algorithm. |
460 */ | 463 */ |
461 function bestFitMatcher(service, requestedLocales) { | 464 function bestFitMatcher(service, requestedLocales) { |
462 // TODO(cira): implement better best fit algorithm. | 465 // TODO(cira): implement better best fit algorithm. |
463 return lookupMatcher(service, requestedLocales); | 466 return lookupMatcher(service, requestedLocales); |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
715 } | 718 } |
716 } | 719 } |
717 return result; | 720 return result; |
718 } | 721 } |
719 | 722 |
720 /** | 723 /** |
721 * Canonicalizes the language tag, or throws in case the tag is invalid. | 724 * Canonicalizes the language tag, or throws in case the tag is invalid. |
722 */ | 725 */ |
723 function canonicalizeLanguageTag(localeID) { | 726 function canonicalizeLanguageTag(localeID) { |
724 // null is typeof 'object' so we have to do extra check. | 727 // null is typeof 'object' so we have to do extra check. |
725 if (typeof localeID !== 'string' && typeof localeID !== 'object' || | 728 if ((!IS_STRING(localeID) && !IS_RECEIVER(localeID)) || |
726 IS_NULL(localeID)) { | 729 IS_NULL(localeID)) { |
727 throw MakeTypeError(kLanguageID); | 730 throw MakeTypeError(kLanguageID); |
728 } | 731 } |
729 | 732 |
733 // Optimize for the most common case; a language code alone in | |
734 // the canonical form/lowercase (e.g. "en", "fil"). | |
735 if (IS_STRING(localeID) && | |
736 !IS_NULL(InternalRegExpMatch(/^[a-z]{2,3}$/, localeID))) { | |
737 return localeID; | |
738 } | |
739 | |
730 var localeString = GlobalString(localeID); | 740 var localeString = GlobalString(localeID); |
731 | 741 |
732 if (isValidLanguageTag(localeString) === false) { | 742 if (isValidLanguageTag(localeString) === false) { |
733 throw MakeRangeError(kInvalidLanguageTag, localeString); | 743 throw MakeRangeError(kInvalidLanguageTag, localeString); |
734 } | 744 } |
735 | 745 |
736 // This call will strip -kn but not -kn-true extensions. | |
737 // ICU bug filled - http://bugs.icu-project.org/trac/ticket/9265. | |
738 // TODO(cira): check if -u-kn-true-kc-true-kh-true still throws after | |
739 // upgrade to ICU 4.9. | |
740 var tag = %CanonicalizeLanguageTag(localeString); | 746 var tag = %CanonicalizeLanguageTag(localeString); |
741 if (tag === 'invalid-tag') { | 747 if (tag === 'invalid-tag') { |
742 throw MakeRangeError(kInvalidLanguageTag, localeString); | 748 throw MakeRangeError(kInvalidLanguageTag, localeString); |
743 } | 749 } |
744 | 750 |
745 return tag; | 751 return tag; |
746 } | 752 } |
747 | 753 |
748 | 754 |
749 /** | 755 /** |
(...skipping 1232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1982 var useOptions = (IS_UNDEFINED(defaults)) ? options : defaults; | 1988 var useOptions = (IS_UNDEFINED(defaults)) ? options : defaults; |
1983 if (IS_UNDEFINED(locales) && IS_UNDEFINED(options)) { | 1989 if (IS_UNDEFINED(locales) && IS_UNDEFINED(options)) { |
1984 if (IS_UNDEFINED(defaultObjects[service])) { | 1990 if (IS_UNDEFINED(defaultObjects[service])) { |
1985 defaultObjects[service] = new savedObjects[service](locales, useOptions); | 1991 defaultObjects[service] = new savedObjects[service](locales, useOptions); |
1986 } | 1992 } |
1987 return defaultObjects[service]; | 1993 return defaultObjects[service]; |
1988 } | 1994 } |
1989 return new savedObjects[service](locales, useOptions); | 1995 return new savedObjects[service](locales, useOptions); |
1990 } | 1996 } |
1991 | 1997 |
1998 function LocaleConvertCase(s, locales, isToUpper) { | |
1999 // ECMA 402 section 13.1.2 steps 1 through 12. | |
2000 var language; | |
2001 // Optimize for the most common two cases. initializeLocaleList() can handle | |
2002 // them as well, but it's rather slow accounting for over 60% of | |
2003 // toLocale{U,L}Case() and about 40% of toLocale{U,L}Case("<locale>"). | |
srl295
2016/07/27 18:53:39
if it's slow, please file a bug in ICU to address.
| |
2004 if (IS_UNDEFINED(locales)) { | |
2005 language = GetDefaultICULocaleJS(); | |
2006 } else if (IS_STRING(locales)) { | |
2007 language = canonicalizeLanguageTag(locales); | |
2008 } else { | |
2009 var locales = initializeLocaleList(locales); | |
2010 language = locales.length > 0 ? locales[0] : GetDefaultICULocaleJS(); | |
2011 } | |
2012 | |
2013 // StringSplit is slower than this. | |
2014 var pos = %_Call(StringIndexOf, language, '-'); | |
2015 if (pos != -1) { | |
2016 language = %_Call(StringSubstring, language, 0, pos); | |
2017 } | |
2018 | |
2019 var CUSTOM_CASE_LANGUAGES = ['az', 'el', 'lt', 'tr']; | |
srl295
2016/07/27 18:53:39
Filed : http://bugs.icu-project.org/trac/ticket/12
srl295
2016/07/27 18:53:39
Why are these hard coded? This decision should be
| |
2020 var langIndex = %_Call(ArrayIndexOf, CUSTOM_CASE_LANGUAGES, language); | |
2021 if (langIndex == -1) { | |
2022 // language-independent case conversion. | |
2023 return isToUpper ? %StringToUpperCaseI18N(s) : %StringToLowerCaseI18N(s); | |
2024 } | |
2025 return %StringLocaleConvertCase(s, isToUpper, | |
2026 CUSTOM_CASE_LANGUAGES[langIndex]); | |
2027 } | |
2028 | |
1992 /** | 2029 /** |
1993 * Compares this and that, and returns less than 0, 0 or greater than 0 value. | 2030 * Compares this and that, and returns less than 0, 0 or greater than 0 value. |
1994 * Overrides the built-in method. | 2031 * Overrides the built-in method. |
1995 */ | 2032 */ |
1996 OverrideFunction(GlobalString.prototype, 'localeCompare', function(that) { | 2033 OverrideFunction(GlobalString.prototype, 'localeCompare', function(that) { |
1997 if (!IS_UNDEFINED(new.target)) { | 2034 if (!IS_UNDEFINED(new.target)) { |
1998 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); | 2035 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); |
1999 } | 2036 } |
2000 | 2037 |
2001 if (IS_NULL_OR_UNDEFINED(this)) { | 2038 if (IS_NULL_OR_UNDEFINED(this)) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2034 var normalizationForm = %_Call(ArrayIndexOf, NORMALIZATION_FORMS, form); | 2071 var normalizationForm = %_Call(ArrayIndexOf, NORMALIZATION_FORMS, form); |
2035 if (normalizationForm === -1) { | 2072 if (normalizationForm === -1) { |
2036 throw MakeRangeError(kNormalizationForm, | 2073 throw MakeRangeError(kNormalizationForm, |
2037 %_Call(ArrayJoin, NORMALIZATION_FORMS, ', ')); | 2074 %_Call(ArrayJoin, NORMALIZATION_FORMS, ', ')); |
2038 } | 2075 } |
2039 | 2076 |
2040 return %StringNormalize(s, normalizationForm); | 2077 return %StringNormalize(s, normalizationForm); |
2041 } | 2078 } |
2042 ); | 2079 ); |
2043 | 2080 |
2081 function ToLowerCaseI18N() { | |
2082 if (!IS_UNDEFINED(new.target)) { | |
2083 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); | |
2084 } | |
2085 CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLowerCase"); | |
2086 var s = TO_STRING(this); | |
2087 return %StringToLowerCaseI18N(s); | |
2088 } | |
2089 | |
2090 function ToUpperCaseI18N() { | |
2091 if (!IS_UNDEFINED(new.target)) { | |
2092 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); | |
2093 } | |
2094 CHECK_OBJECT_COERCIBLE(this, "String.prototype.toUpperCase"); | |
2095 var s = TO_STRING(this); | |
2096 return %StringToUpperCaseI18N(s); | |
2097 } | |
2098 | |
2099 function ToLocaleLowerCaseI18N(locales) { | |
2100 if (!IS_UNDEFINED(new.target)) { | |
2101 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); | |
2102 } | |
2103 CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleLowerCase"); | |
2104 return LocaleConvertCase(TO_STRING(this), locales, false); | |
2105 } | |
2106 | |
2107 %FunctionSetLength(ToLocaleLowerCaseI18N, 0); | |
2108 | |
2109 function ToLocaleUpperCaseI18N(locales) { | |
2110 if (!IS_UNDEFINED(new.target)) { | |
2111 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); | |
2112 } | |
2113 CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleUpperCase"); | |
2114 return LocaleConvertCase(TO_STRING(this), locales, true); | |
2115 } | |
2116 | |
2117 %FunctionSetLength(ToLocaleUpperCaseI18N, 0); | |
2118 | |
2119 %FunctionRemovePrototype(ToLowerCaseI18N); | |
2120 %FunctionRemovePrototype(ToUpperCaseI18N); | |
2121 %FunctionRemovePrototype(ToLocaleLowerCaseI18N); | |
2122 %FunctionRemovePrototype(ToLocaleUpperCaseI18N); | |
2123 | |
2124 utils.Export(function(to) { | |
2125 to.ToLowerCaseI18N = ToLowerCaseI18N; | |
2126 to.ToUpperCaseI18N = ToUpperCaseI18N; | |
2127 to.ToLocaleLowerCaseI18N = ToLocaleLowerCaseI18N; | |
2128 to.ToLocaleUpperCaseI18N = ToLocaleUpperCaseI18N; | |
2129 }); | |
2130 | |
2044 | 2131 |
2045 /** | 2132 /** |
2046 * Formats a Number object (this) using locale and options values. | 2133 * Formats a Number object (this) using locale and options values. |
2047 * If locale or options are omitted, defaults are used. | 2134 * If locale or options are omitted, defaults are used. |
2048 */ | 2135 */ |
2049 OverrideFunction(GlobalNumber.prototype, 'toLocaleString', function() { | 2136 OverrideFunction(GlobalNumber.prototype, 'toLocaleString', function() { |
2050 if (!IS_UNDEFINED(new.target)) { | 2137 if (!IS_UNDEFINED(new.target)) { |
2051 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); | 2138 throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); |
2052 } | 2139 } |
2053 | 2140 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2129 } | 2216 } |
2130 | 2217 |
2131 var locales = arguments[0]; | 2218 var locales = arguments[0]; |
2132 var options = arguments[1]; | 2219 var options = arguments[1]; |
2133 return toLocaleDateTime( | 2220 return toLocaleDateTime( |
2134 this, locales, options, 'time', 'time', 'dateformattime'); | 2221 this, locales, options, 'time', 'time', 'dateformattime'); |
2135 } | 2222 } |
2136 ); | 2223 ); |
2137 | 2224 |
2138 }) | 2225 }) |
OLD | NEW |