Home | History | Annotate | Download | only in i18n
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 // limitations under the License.
     28 
     29 // ECMAScript 402 API implementation is broken into separate files for
     30 // each service. The build system combines them together into one
     31 // Intl namespace.
     32 
     33 
     34 // Save references to Intl objects and methods we use, for added security.
     35 var savedObjects = {
     36   'collator': Intl.Collator,
     37   'numberformat': Intl.NumberFormat,
     38   'dateformatall': Intl.DateTimeFormat,
     39   'dateformatdate': Intl.DateTimeFormat,
     40   'dateformattime': Intl.DateTimeFormat
     41 };
     42 
     43 
     44 // Default (created with undefined locales and options parameters) collator,
     45 // number and date format instances. They'll be created as needed.
     46 var defaultObjects = {
     47   'collator': undefined,
     48   'numberformat': undefined,
     49   'dateformatall': undefined,
     50   'dateformatdate': undefined,
     51   'dateformattime': undefined,
     52 };
     53 
     54 
     55 /**
     56  * Returns cached or newly created instance of a given service.
     57  * We cache only default instances (where no locales or options are provided).
     58  */
     59 function cachedOrNewService(service, locales, options, defaults) {
     60   var useOptions = (defaults === undefined) ? options : defaults;
     61   if (locales === undefined && options === undefined) {
     62     if (defaultObjects[service] === undefined) {
     63       defaultObjects[service] = new savedObjects[service](locales, useOptions);
     64     }
     65     return defaultObjects[service];
     66   }
     67   return new savedObjects[service](locales, useOptions);
     68 }
     69 
     70 
     71 /**
     72  * Compares this and that, and returns less than 0, 0 or greater than 0 value.
     73  * Overrides the built-in method.
     74  */
     75 Object.defineProperty(String.prototype, 'localeCompare', {
     76   value: function(that) {
     77     if (%_IsConstructCall()) {
     78       throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
     79     }
     80 
     81     if (this === undefined || this === null) {
     82       throw new TypeError('Method invoked on undefined or null value.');
     83     }
     84 
     85     var locales = arguments[1];
     86     var options = arguments[2];
     87     var collator = cachedOrNewService('collator', locales, options);
     88     return compare(collator, this, that);
     89   },
     90   writable: true,
     91   configurable: true,
     92   enumerable: false
     93 });
     94 %FunctionSetName(String.prototype.localeCompare, 'localeCompare');
     95 %FunctionRemovePrototype(String.prototype.localeCompare);
     96 %SetNativeFlag(String.prototype.localeCompare);
     97 
     98 
     99 /**
    100  * Formats a Number object (this) using locale and options values.
    101  * If locale or options are omitted, defaults are used.
    102  */
    103 Object.defineProperty(Number.prototype, 'toLocaleString', {
    104   value: function() {
    105     if (%_IsConstructCall()) {
    106       throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
    107     }
    108 
    109     if (!(this instanceof Number) && typeof(this) !== 'number') {
    110       throw new TypeError('Method invoked on an object that is not Number.');
    111     }
    112 
    113     var locales = arguments[0];
    114     var options = arguments[1];
    115     var numberFormat = cachedOrNewService('numberformat', locales, options);
    116     return formatNumber(numberFormat, this);
    117   },
    118   writable: true,
    119   configurable: true,
    120   enumerable: false
    121 });
    122 %FunctionSetName(Number.prototype.toLocaleString, 'toLocaleString');
    123 %FunctionRemovePrototype(Number.prototype.toLocaleString);
    124 %SetNativeFlag(Number.prototype.toLocaleString);
    125 
    126 
    127 /**
    128  * Returns actual formatted date or fails if date parameter is invalid.
    129  */
    130 function toLocaleDateTime(date, locales, options, required, defaults, service) {
    131   if (!(date instanceof Date)) {
    132     throw new TypeError('Method invoked on an object that is not Date.');
    133   }
    134 
    135   if (isNaN(date)) {
    136     return 'Invalid Date';
    137   }
    138 
    139   var internalOptions = toDateTimeOptions(options, required, defaults);
    140 
    141   var dateFormat =
    142       cachedOrNewService(service, locales, options, internalOptions);
    143 
    144   return formatDate(dateFormat, date);
    145 }
    146 
    147 
    148 /**
    149  * Formats a Date object (this) using locale and options values.
    150  * If locale or options are omitted, defaults are used - both date and time are
    151  * present in the output.
    152  */
    153 Object.defineProperty(Date.prototype, 'toLocaleString', {
    154   value: function() {
    155     if (%_IsConstructCall()) {
    156       throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
    157     }
    158 
    159     var locales = arguments[0];
    160     var options = arguments[1];
    161     return toLocaleDateTime(
    162         this, locales, options, 'any', 'all', 'dateformatall');
    163   },
    164   writable: true,
    165   configurable: true,
    166   enumerable: false
    167 });
    168 %FunctionSetName(Date.prototype.toLocaleString, 'toLocaleString');
    169 %FunctionRemovePrototype(Date.prototype.toLocaleString);
    170 %SetNativeFlag(Date.prototype.toLocaleString);
    171 
    172 
    173 /**
    174  * Formats a Date object (this) using locale and options values.
    175  * If locale or options are omitted, defaults are used - only date is present
    176  * in the output.
    177  */
    178 Object.defineProperty(Date.prototype, 'toLocaleDateString', {
    179   value: function() {
    180     if (%_IsConstructCall()) {
    181       throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
    182     }
    183 
    184     var locales = arguments[0];
    185     var options = arguments[1];
    186     return toLocaleDateTime(
    187         this, locales, options, 'date', 'date', 'dateformatdate');
    188   },
    189   writable: true,
    190   configurable: true,
    191   enumerable: false
    192 });
    193 %FunctionSetName(Date.prototype.toLocaleDateString, 'toLocaleDateString');
    194 %FunctionRemovePrototype(Date.prototype.toLocaleDateString);
    195 %SetNativeFlag(Date.prototype.toLocaleDateString);
    196 
    197 
    198 /**
    199  * Formats a Date object (this) using locale and options values.
    200  * If locale or options are omitted, defaults are used - only time is present
    201  * in the output.
    202  */
    203 Object.defineProperty(Date.prototype, 'toLocaleTimeString', {
    204   value: function() {
    205     if (%_IsConstructCall()) {
    206       throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
    207     }
    208 
    209     var locales = arguments[0];
    210     var options = arguments[1];
    211     return toLocaleDateTime(
    212         this, locales, options, 'time', 'time', 'dateformattime');
    213   },
    214   writable: true,
    215   configurable: true,
    216   enumerable: false
    217 });
    218 %FunctionSetName(Date.prototype.toLocaleTimeString, 'toLocaleTimeString');
    219 %FunctionRemovePrototype(Date.prototype.toLocaleTimeString);
    220 %SetNativeFlag(Date.prototype.toLocaleTimeString);
    221