Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: src/js/i18n.js

Issue 1529363005: tzname check fix (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: todo comment added for Etc/GMT{offset} Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/messages.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 return LANGUAGE_SINGLETON_RE; 169 return LANGUAGE_SINGLETON_RE;
170 } 170 }
171 171
172 /** 172 /**
173 * Matches valid IANA time zone names. 173 * Matches valid IANA time zone names.
174 */ 174 */
175 var TIMEZONE_NAME_CHECK_RE = UNDEFINED; 175 var TIMEZONE_NAME_CHECK_RE = UNDEFINED;
176 176
177 function GetTimezoneNameCheckRE() { 177 function GetTimezoneNameCheckRE() {
178 if (IS_UNDEFINED(TIMEZONE_NAME_CHECK_RE)) { 178 if (IS_UNDEFINED(TIMEZONE_NAME_CHECK_RE)) {
179 TIMEZONE_NAME_CHECK_RE = 179 TIMEZONE_NAME_CHECK_RE = new GlobalRegExp(
180 new GlobalRegExp('^([A-Za-z]+)/([A-Za-z]+)(?:_([A-Za-z]+))*$'); 180 '^([A-Za-z]+)/([A-Za-z_-]+)((?:\/[A-Za-z_-]+)+)*$');
181 } 181 }
182 return TIMEZONE_NAME_CHECK_RE; 182 return TIMEZONE_NAME_CHECK_RE;
183 } 183 }
184 184
185 /** 185 /**
186 * Matches valid location parts of IANA time zone names.
187 */
188 var TIMEZONE_NAME_LOCATION_PART_RE = UNDEFINED;
189
190 function GetTimezoneNameLocationPartRE() {
191 if (IS_UNDEFINED(TIMEZONE_NAME_LOCATION_PART_RE)) {
192 TIMEZONE_NAME_LOCATION_PART_RE =
193 new GlobalRegExp('^([A-Za-z]+)((?:[_-][A-Za-z]+)+)*$');
194 }
195 return TIMEZONE_NAME_LOCATION_PART_RE;
196 }
197
198 /**
186 * Adds bound method to the prototype of the given object. 199 * Adds bound method to the prototype of the given object.
187 */ 200 */
188 function addBoundMethod(obj, methodName, implementation, length) { 201 function addBoundMethod(obj, methodName, implementation, length) {
189 %CheckIsBootstrapping(); 202 %CheckIsBootstrapping();
190 function getter() { 203 function getter() {
191 if (!%IsInitializedIntlObject(this)) { 204 if (!%IsInitializedIntlObject(this)) {
192 throw MakeTypeError(kMethodCalledOnWrongObject, methodName); 205 throw MakeTypeError(kMethodCalledOnWrongObject, methodName);
193 } 206 }
194 var internalName = '__bound' + methodName + '__'; 207 var internalName = '__bound' + methodName + '__';
195 if (IS_UNDEFINED(this[internalName])) { 208 if (IS_UNDEFINED(this[internalName])) {
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after
672 685
673 /** 686 /**
674 * Returns titlecased word, aMeRricA -> America. 687 * Returns titlecased word, aMeRricA -> America.
675 */ 688 */
676 function toTitleCaseWord(word) { 689 function toTitleCaseWord(word) {
677 return %StringToUpperCase(%_Call(StringSubstr, word, 0, 1)) + 690 return %StringToUpperCase(%_Call(StringSubstr, word, 0, 1)) +
678 %StringToLowerCase(%_Call(StringSubstr, word, 1)); 691 %StringToLowerCase(%_Call(StringSubstr, word, 1));
679 } 692 }
680 693
681 /** 694 /**
695 * Returns titlecased location, bueNos_airES -> Buenos_Aires
696 * or ho_cHi_minH -> Ho_Chi_Minh. It is locale-agnostic and only
697 * deals with ASCII only characters.
698 * 'of', 'au' and 'es' are special-cased and lowercased.
699 */
700 function toTitleCaseTimezoneLocation(location) {
701 var match = %_Call(StringMatch, location, GetTimezoneNameLocationPartRE());
702 if (IS_NULL(match)) throw MakeRangeError(kExpectedLocation, location);
703
704 var result = toTitleCaseWord(match[1]);
705 if (!IS_UNDEFINED(match[2]) && 2 < match.length) {
706 // The first character is a separator, '_' or '-'.
707 // None of IANA zone names has both '_' and '-'.
708 var separator = %_Call(StringSubstring, match[2], 0, 1);
709 var parts = %_Call(StringSplit, match[2], separator);
710 for (var i = 1; i < parts.length; i++) {
711 var part = parts[i]
712 var lowercasedPart = %StringToLowerCase(part);
713 result = result + separator +
714 ((lowercasedPart !== 'es' &&
715 lowercasedPart !== 'of' && lowercasedPart !== 'au') ?
716 toTitleCaseWord(part) : lowercasedPart);
717 }
718 }
719 return result;
720 }
721
722 /**
682 * Canonicalizes the language tag, or throws in case the tag is invalid. 723 * Canonicalizes the language tag, or throws in case the tag is invalid.
683 */ 724 */
684 function canonicalizeLanguageTag(localeID) { 725 function canonicalizeLanguageTag(localeID) {
685 // null is typeof 'object' so we have to do extra check. 726 // null is typeof 'object' so we have to do extra check.
686 if (typeof localeID !== 'string' && typeof localeID !== 'object' || 727 if (typeof localeID !== 'string' && typeof localeID !== 'object' ||
687 IS_NULL(localeID)) { 728 IS_NULL(localeID)) {
688 throw MakeTypeError(kLanguageID); 729 throw MakeTypeError(kLanguageID);
689 } 730 }
690 731
691 var localeString = GlobalString(localeID); 732 var localeString = GlobalString(localeID);
(...skipping 1036 matching lines...) Expand 10 before | Expand all | Expand 10 after
1728 GlobalString(value)); 1769 GlobalString(value));
1729 } 1770 }
1730 1771
1731 1772
1732 // 0 because date is optional argument. 1773 // 0 because date is optional argument.
1733 addBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0); 1774 addBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0);
1734 addBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1); 1775 addBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1);
1735 1776
1736 1777
1737 /** 1778 /**
1738 * Returns canonical Area/Location name, or throws an exception if the zone 1779 * Returns canonical Area/Location(/Location) name, or throws an exception
1739 * name is invalid IANA name. 1780 * if the zone name is invalid IANA name.
1740 */ 1781 */
1741 function canonicalizeTimeZoneID(tzID) { 1782 function canonicalizeTimeZoneID(tzID) {
1742 // Skip undefined zones. 1783 // Skip undefined zones.
1743 if (IS_UNDEFINED(tzID)) { 1784 if (IS_UNDEFINED(tzID)) {
1744 return tzID; 1785 return tzID;
1745 } 1786 }
1746 1787
1747 // Special case handling (UTC, GMT). 1788 // Special case handling (UTC, GMT).
1748 var upperID = %StringToUpperCase(tzID); 1789 var upperID = %StringToUpperCase(tzID);
1749 if (upperID === 'UTC' || upperID === 'GMT' || 1790 if (upperID === 'UTC' || upperID === 'GMT' ||
1750 upperID === 'ETC/UTC' || upperID === 'ETC/GMT') { 1791 upperID === 'ETC/UTC' || upperID === 'ETC/GMT') {
1751 return 'UTC'; 1792 return 'UTC';
1752 } 1793 }
1753 1794
1754 // We expect only _ and / beside ASCII letters. 1795 // TODO(jshin): Add support for Etc/GMT[+-]([1-9]|1[0-2])
1755 // All inputs should conform to Area/Location from now on. 1796
1797 // We expect only _, '-' and / beside ASCII letters.
1798 // All inputs should conform to Area/Location(/Location)* from now on.
1756 var match = %_Call(StringMatch, tzID, GetTimezoneNameCheckRE()); 1799 var match = %_Call(StringMatch, tzID, GetTimezoneNameCheckRE());
1757 if (IS_NULL(match)) throw MakeRangeError(kExpectedLocation, tzID); 1800 if (IS_NULL(match)) throw MakeRangeError(kExpectedTimezoneID, tzID);
1758 1801
1759 var result = toTitleCaseWord(match[1]) + '/' + toTitleCaseWord(match[2]); 1802 var result = toTitleCaseTimezoneLocation(match[1]) + '/' +
1760 var i = 3; 1803 toTitleCaseTimezoneLocation(match[2]);
1761 while (!IS_UNDEFINED(match[i]) && i < match.length) { 1804
1762 result = result + '_' + toTitleCaseWord(match[i]); 1805 if (!IS_UNDEFINED(match[3]) && 3 < match.length) {
1763 i++; 1806 var locations = %_Call(StringSplit, match[3], '/');
1807 // The 1st element is empty. Starts with i=1.
1808 for (var i = 1; i < locations.length; i++) {
1809 result = result + '/' + toTitleCaseTimezoneLocation(locations[i]);
1810 }
1764 } 1811 }
1765 1812
1766 return result; 1813 return result;
1767 } 1814 }
1768 1815
1769 /** 1816 /**
1770 * Initializes the given object so it's a valid BreakIterator instance. 1817 * Initializes the given object so it's a valid BreakIterator instance.
1771 * Useful for subclassing. 1818 * Useful for subclassing.
1772 */ 1819 */
1773 function initializeBreakIterator(iterator, locales, options) { 1820 function initializeBreakIterator(iterator, locales, options) {
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after
2113 } 2160 }
2114 2161
2115 var locales = %_Arguments(0); 2162 var locales = %_Arguments(0);
2116 var options = %_Arguments(1); 2163 var options = %_Arguments(1);
2117 return toLocaleDateTime( 2164 return toLocaleDateTime(
2118 this, locales, options, 'time', 'time', 'dateformattime'); 2165 this, locales, options, 'time', 'time', 'dateformattime');
2119 } 2166 }
2120 ); 2167 );
2121 2168
2122 }) 2169 })
OLDNEW
« no previous file with comments | « no previous file | src/messages.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698