Chromium Code Reviews| 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 549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 560 } | 560 } |
| 561 | 561 |
| 562 return extension === ''? '' : '-u' + extension; | 562 return extension === ''? '' : '-u' + extension; |
| 563 } | 563 } |
| 564 | 564 |
| 565 | 565 |
| 566 /** | 566 /** |
| 567 * Given an array-like, outputs an Array with the numbered | 567 * Given an array-like, outputs an Array with the numbered |
| 568 * properties copied over and defined | 568 * properties copied over and defined |
| 569 * configurable: false, writable: false, enumerable: true. | 569 * configurable: false, writable: false, enumerable: true. |
| 570 * When |expandable| is true, the result array can be expanded. | |
|
jungshik at Google
2016/08/16 08:51:39
Ick. I'll get rid of this line.
| |
| 570 */ | 571 */ |
| 571 function freezeArray(input) { | 572 function freezeArray(input) { |
| 572 var array = []; | 573 var array = []; |
| 573 var l = input.length; | 574 var l = input.length; |
| 574 for (var i = 0; i < l; i++) { | 575 for (var i = 0; i < l; i++) { |
| 575 if (i in input) { | 576 if (i in input) { |
| 576 %object_define_property(array, i, {value: input[i], | 577 %object_define_property(array, i, {value: input[i], |
| 577 configurable: false, | 578 configurable: false, |
| 578 writable: false, | 579 writable: false, |
| 579 enumerable: true}); | 580 enumerable: true}); |
| 580 } | 581 } |
| 581 } | 582 } |
| 582 | 583 |
| 583 %object_define_property(array, 'length', {value: l, writable: false}); | 584 %object_define_property(array, 'length', {value: l, writable: false}); |
| 584 return array; | 585 return array; |
| 585 } | 586 } |
| 586 | 587 |
| 588 /* Make JS array[] out of InternalArray */ | |
| 589 function makeArray(input) { | |
| 590 var array = []; | |
| 591 %MoveArrayContents(input, array); | |
| 592 return array; | |
| 593 } | |
| 587 | 594 |
| 588 /** | 595 /** |
| 589 * It's sometimes desireable to leave user requested locale instead of ICU | 596 * It's sometimes desireable to leave user requested locale instead of ICU |
| 590 * supported one (zh-TW is equivalent to zh-Hant-TW, so we should keep shorter | 597 * supported one (zh-TW is equivalent to zh-Hant-TW, so we should keep shorter |
| 591 * one, if that was what user requested). | 598 * one, if that was what user requested). |
| 592 * This function returns user specified tag if its maximized form matches ICU | 599 * This function returns user specified tag if its maximized form matches ICU |
| 593 * resolved locale. If not we return ICU result. | 600 * resolved locale. If not we return ICU result. |
| 594 */ | 601 */ |
| 595 function getOptimalLanguageTag(original, resolved) { | 602 function getOptimalLanguageTag(original, resolved) { |
| 596 // Returns Array<Object>, where each object has maximized and base properties. | 603 // Returns Array<Object>, where each object has maximized and base properties. |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 711 ((lowercasedPart !== 'es' && | 718 ((lowercasedPart !== 'es' && |
| 712 lowercasedPart !== 'of' && lowercasedPart !== 'au') ? | 719 lowercasedPart !== 'of' && lowercasedPart !== 'au') ? |
| 713 toTitleCaseWord(part) : lowercasedPart); | 720 toTitleCaseWord(part) : lowercasedPart); |
| 714 } | 721 } |
| 715 } | 722 } |
| 716 return result; | 723 return result; |
| 717 } | 724 } |
| 718 | 725 |
| 719 /** | 726 /** |
| 720 * Canonicalizes the language tag, or throws in case the tag is invalid. | 727 * Canonicalizes the language tag, or throws in case the tag is invalid. |
| 728 * ECMA 402 9.2.1 steps 7.c ii ~ v. | |
| 721 */ | 729 */ |
| 722 function canonicalizeLanguageTag(localeID) { | 730 function canonicalizeLanguageTag(localeID) { |
| 723 // null is typeof 'object' so we have to do extra check. | 731 // null is typeof 'object' so we have to do extra check. |
| 724 if ((!IS_STRING(localeID) && !IS_RECEIVER(localeID)) || | 732 if ((!IS_STRING(localeID) && !IS_RECEIVER(localeID)) || |
| 725 IS_NULL(localeID)) { | 733 IS_NULL(localeID)) { |
| 726 throw %make_type_error(kLanguageID); | 734 throw %make_type_error(kLanguageID); |
| 727 } | 735 } |
| 728 | 736 |
| 729 // Optimize for the most common case; a language code alone in | 737 // Optimize for the most common case; a language code alone in |
| 730 // the canonical form/lowercase (e.g. "en", "fil"). | 738 // the canonical form/lowercase (e.g. "en", "fil"). |
| 731 if (IS_STRING(localeID) && | 739 if (IS_STRING(localeID) && |
| 732 !IS_NULL(InternalRegExpMatch(/^[a-z]{2,3}$/, localeID))) { | 740 !IS_NULL(InternalRegExpMatch(/^[a-z]{2,3}$/, localeID))) { |
| 733 return localeID; | 741 return localeID; |
| 734 } | 742 } |
| 735 | 743 |
| 736 var localeString = TO_STRING(localeID); | 744 var localeString = TO_STRING(localeID); |
| 737 | 745 |
| 738 if (isValidLanguageTag(localeString) === false) { | 746 if (isStructuallyValidLanguageTag(localeString) === false) { |
| 739 throw %make_range_error(kInvalidLanguageTag, localeString); | 747 throw %make_range_error(kInvalidLanguageTag, localeString); |
| 740 } | 748 } |
| 741 | 749 |
| 750 // ECMA 402 6.2.3 | |
| 742 var tag = %CanonicalizeLanguageTag(localeString); | 751 var tag = %CanonicalizeLanguageTag(localeString); |
| 752 // TODO(jshin): This should not happen because the structual validity | |
| 753 // is already checked. If that's the case, remove this. | |
| 743 if (tag === 'invalid-tag') { | 754 if (tag === 'invalid-tag') { |
| 744 throw %make_range_error(kInvalidLanguageTag, localeString); | 755 throw %make_range_error(kInvalidLanguageTag, localeString); |
| 745 } | 756 } |
| 746 | 757 |
| 747 return tag; | 758 return tag; |
| 748 } | 759 } |
| 749 | 760 |
| 750 | 761 |
| 751 /** | 762 /** |
| 752 * Returns an array where all locales are canonicalized and duplicates removed. | 763 * Returns an InternalArray where all locales are canonicalized and duplicates |
| 764 * removed. | |
| 753 * Throws on locales that are not well formed BCP47 tags. | 765 * Throws on locales that are not well formed BCP47 tags. |
| 766 * ECMA 402 8.2.1 steps 1 (ECMA 402 9.2.1) and 2. | |
| 754 */ | 767 */ |
| 755 function initializeLocaleList(locales) { | 768 function canonicalizeLocaleList(locales) { |
| 756 var seen = new InternalArray(); | 769 var seen = new InternalArray(); |
| 757 if (!IS_UNDEFINED(locales)) { | 770 if (!IS_UNDEFINED(locales)) { |
| 758 // We allow single string localeID. | 771 // We allow single string localeID. |
| 759 if (typeof locales === 'string') { | 772 if (typeof locales === 'string') { |
| 760 %_Call(ArrayPush, seen, canonicalizeLanguageTag(locales)); | 773 %_Call(ArrayPush, seen, canonicalizeLanguageTag(locales)); |
| 761 return freezeArray(seen); | 774 return seen; |
| 762 } | 775 } |
| 763 | 776 |
| 764 var o = TO_OBJECT(locales); | 777 var o = TO_OBJECT(locales); |
| 765 var len = TO_UINT32(o.length); | 778 var len = TO_LENGTH(o.length); |
| 766 | 779 |
| 767 for (var k = 0; k < len; k++) { | 780 for (var k = 0; k < len; k++) { |
| 768 if (k in o) { | 781 if (k in o) { |
| 769 var value = o[k]; | 782 var value = o[k]; |
| 770 | 783 |
| 771 var tag = canonicalizeLanguageTag(value); | 784 var tag = canonicalizeLanguageTag(value); |
| 772 | 785 |
| 773 if (%_Call(ArrayIndexOf, seen, tag) === -1) { | 786 if (%_Call(ArrayIndexOf, seen, tag) === -1) { |
| 774 %_Call(ArrayPush, seen, tag); | 787 %_Call(ArrayPush, seen, tag); |
| 775 } | 788 } |
| 776 } | 789 } |
| 777 } | 790 } |
| 778 } | 791 } |
| 779 | 792 |
| 780 return freezeArray(seen); | 793 return seen; |
| 781 } | 794 } |
| 782 | 795 |
| 796 function initializeLocaleList(locales) { | |
| 797 return freezeArray(canonicalizeLocaleList(locales)); | |
| 798 } | |
| 783 | 799 |
| 784 /** | 800 /** |
| 785 * Validates the language tag. Section 2.2.9 of the bcp47 spec | 801 * Check the structual Validity of the language tag per ECMA 402 6.2.2: |
| 786 * defines a valid tag. | 802 * - Well-formed per RFC 5646 2.1 |
| 803 * - There are no duplicate variant subtags | |
| 804 * - There are no duplicate singletion (extension) subtags | |
| 805 * | |
| 806 * One extra-check is done (from RFC 5646 2.2.9): the tag is compared | |
| 807 * against the list of grandfathered tags. However, subtags for | |
| 808 * primary/extended language, script, region, variant are not checked | |
| 809 * against the IANA language subtag registry. | |
| 787 * | 810 * |
| 788 * ICU is too permissible and lets invalid tags, like | 811 * ICU is too permissible and lets invalid tags, like |
| 789 * hant-cmn-cn, through. | 812 * hant-cmn-cn, through. |
| 790 * | 813 * |
| 791 * Returns false if the language tag is invalid. | 814 * Returns false if the language tag is invalid. |
| 792 */ | 815 */ |
| 793 function isValidLanguageTag(locale) { | 816 function isStructuallyValidLanguageTag(locale) { |
| 794 // Check if it's well-formed, including grandfadered tags. | 817 // Check if it's well-formed, including grandfadered tags. |
| 795 if (IS_NULL(InternalRegExpMatch(GetLanguageTagRE(), locale))) { | 818 if (IS_NULL(InternalRegExpMatch(GetLanguageTagRE(), locale))) { |
| 796 return false; | 819 return false; |
| 797 } | 820 } |
| 798 | 821 |
| 799 // Just return if it's a x- form. It's all private. | 822 // Just return if it's a x- form. It's all private. |
| 800 if (%_Call(StringIndexOf, locale, 'x-') === 0) { | 823 if (%_Call(StringIndexOf, locale, 'x-') === 0) { |
| 801 return true; | 824 return true; |
| 802 } | 825 } |
| 803 | 826 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 878 var resolvedAccessor = { | 901 var resolvedAccessor = { |
| 879 get() { | 902 get() { |
| 880 %IncrementUseCounter(kIntlResolved); | 903 %IncrementUseCounter(kIntlResolved); |
| 881 return this[resolvedSymbol]; | 904 return this[resolvedSymbol]; |
| 882 }, | 905 }, |
| 883 set(value) { | 906 set(value) { |
| 884 this[resolvedSymbol] = value; | 907 this[resolvedSymbol] = value; |
| 885 } | 908 } |
| 886 }; | 909 }; |
| 887 | 910 |
| 911 // ECMA 402 section 8.2.1 | |
| 912 InstallFunction(Intl, 'getCanonicalLocales', function(locales) { | |
| 913 if (!IS_UNDEFINED(new.target)) { | |
| 914 throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); | |
| 915 } | |
| 916 | |
| 917 return makeArray(canonicalizeLocaleList(locales)); | |
| 918 } | |
| 919 ); | |
| 920 | |
| 888 /** | 921 /** |
| 889 * Initializes the given object so it's a valid Collator instance. | 922 * Initializes the given object so it's a valid Collator instance. |
| 890 * Useful for subclassing. | 923 * Useful for subclassing. |
| 891 */ | 924 */ |
| 892 function initializeCollator(collator, locales, options) { | 925 function initializeCollator(collator, locales, options) { |
| 893 if (%IsInitializedIntlObject(collator)) { | 926 if (%IsInitializedIntlObject(collator)) { |
| 894 throw %make_type_error(kReinitializeIntl, "Collator"); | 927 throw %make_type_error(kReinitializeIntl, "Collator"); |
| 895 } | 928 } |
| 896 | 929 |
| 897 if (IS_UNDEFINED(options)) { | 930 if (IS_UNDEFINED(options)) { |
| (...skipping 1348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2246 } | 2279 } |
| 2247 ); | 2280 ); |
| 2248 | 2281 |
| 2249 utils.Export(function(to) { | 2282 utils.Export(function(to) { |
| 2250 to.AddBoundMethod = AddBoundMethod; | 2283 to.AddBoundMethod = AddBoundMethod; |
| 2251 to.IntlParseDate = IntlParseDate; | 2284 to.IntlParseDate = IntlParseDate; |
| 2252 to.IntlParseNumber = IntlParseNumber; | 2285 to.IntlParseNumber = IntlParseNumber; |
| 2253 }); | 2286 }); |
| 2254 | 2287 |
| 2255 }) | 2288 }) |
| OLD | NEW |