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

Side by Side Diff: src/extensions/i18n/number-format.js

Issue 18487004: Import the v8-i18n extension into v8 (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years, 5 months 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 | Annotate | Revision Log
OLDNEW
(Empty)
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 * Verifies that the input is a well-formed ISO 4217 currency code.
35 * Don't uppercase to test. It could convert invalid code into a valid one.
36 * For example \u00DFP (Eszett+P) becomes SSP.
37 */
38 function isWellFormedCurrencyCode(currency) {
39 return typeof currency == "string" &&
40 currency.length == 3 &&
41 currency.match(/[^A-Za-z]/) == null;
42 }
43
44
45 /**
46 * Returns the valid digit count for a property, or throws RangeError on
47 * a value out of the range.
48 */
49 function getNumberOption(options, property, min, max, fallback) {
50 var value = options[property];
51 if (value !== undefined) {
52 value = Number(value);
53 if (isNaN(value) || value < min || value > max) {
54 throw new RangeError(property + ' value is out of range.');
55 }
56 return Math.floor(value);
57 }
58
59 return fallback;
60 }
61
62
63 /**
64 * Initializes the given object so it's a valid NumberFormat instance.
65 * Useful for subclassing.
66 */
67 function initializeNumberFormat(numberFormat, locales, options) {
68 native function NativeJSCreateNumberFormat();
69
70 if (numberFormat.hasOwnProperty('__initializedIntlObject')) {
71 throw new TypeError('Trying to re-initialize NumberFormat object.');
72 }
73
74 if (options === undefined) {
75 options = {};
76 }
77
78 var getOption = getGetOption(options, 'numberformat');
79
80 var locale = resolveLocale('numberformat', locales, options);
81
82 var internalOptions = {};
83 defineWEProperty(internalOptions, 'style', getOption(
84 'style', 'string', ['decimal', 'percent', 'currency'], 'decimal'));
85
86 var currency = getOption('currency', 'string');
87 if (currency !== undefined && !isWellFormedCurrencyCode(currency)) {
88 throw new RangeError('Invalid currency code: ' + currency);
89 }
90
91 if (internalOptions.style === 'currency' && currency === undefined) {
92 throw new TypeError('Currency code is required with currency style.');
93 }
94
95 var currencyDisplay = getOption(
96 'currencyDisplay', 'string', ['code', 'symbol', 'name'], 'symbol');
97 if (internalOptions.style === 'currency') {
98 defineWEProperty(internalOptions, 'currency', currency.toUpperCase());
99 defineWEProperty(internalOptions, 'currencyDisplay', currencyDisplay);
100 }
101
102 // Digit ranges.
103 var mnid = getNumberOption(options, 'minimumIntegerDigits', 1, 21, 1);
104 defineWEProperty(internalOptions, 'minimumIntegerDigits', mnid);
105
106 var mnfd = getNumberOption(options, 'minimumFractionDigits', 0, 20, 0);
107 defineWEProperty(internalOptions, 'minimumFractionDigits', mnfd);
108
109 var mxfd = getNumberOption(options, 'maximumFractionDigits', mnfd, 20, 3);
110 defineWEProperty(internalOptions, 'maximumFractionDigits', mxfd);
111
112 var mnsd = options['minimumSignificantDigits'];
113 var mxsd = options['maximumSignificantDigits'];
114 if (mnsd !== undefined || mxsd !== undefined) {
115 mnsd = getNumberOption(options, 'minimumSignificantDigits', 1, 21, 0);
116 defineWEProperty(internalOptions, 'minimumSignificantDigits', mnsd);
117
118 mxsd = getNumberOption(options, 'maximumSignificantDigits', mnsd, 21, 21);
119 defineWEProperty(internalOptions, 'maximumSignificantDigits', mxsd);
120 }
121
122 // Grouping.
123 defineWEProperty(internalOptions, 'useGrouping', getOption(
124 'useGrouping', 'boolean', undefined, true));
125
126 // ICU prefers options to be passed using -u- extension key/values for
127 // number format, so we need to build that.
128 var extensionMap = parseExtension(locale.extension);
129 var extension = setOptions(options, extensionMap, NUMBER_FORMAT_KEY_MAP,
130 getOption, internalOptions);
131
132 var requestedLocale = locale.locale + extension;
133 var resolved = Object.defineProperties({}, {
134 currency: {writable: true},
135 currencyDisplay: {writable: true},
136 locale: {writable: true},
137 maximumFractionDigits: {writable: true},
138 minimumFractionDigits: {writable: true},
139 minimumIntegerDigits: {writable: true},
140 numberingSystem: {writable: true},
141 requestedLocale: {value: requestedLocale, writable: true},
142 style: {value: internalOptions.style, writable: true},
143 useGrouping: {writable: true}
144 });
145 if (internalOptions.hasOwnProperty('minimumSignificantDigits')) {
146 defineWEProperty(resolved, 'minimumSignificantDigits', undefined);
147 }
148 if (internalOptions.hasOwnProperty('maximumSignificantDigits')) {
149 defineWEProperty(resolved, 'maximumSignificantDigits', undefined);
150 }
151 var formatter = NativeJSCreateNumberFormat(requestedLocale,
152 internalOptions,
153 resolved);
154
155 // We can't get information about number or currency style from ICU, so we
156 // assume user request was fulfilled.
157 if (internalOptions.style === 'currency') {
158 Object.defineProperty(resolved, 'currencyDisplay', {value: currencyDisplay,
159 writable: true});
160 }
161
162 Object.defineProperty(numberFormat, 'formatter', {value: formatter});
163 Object.defineProperty(numberFormat, 'resolved', {value: resolved});
164 Object.defineProperty(numberFormat, '__initializedIntlObject',
165 {value: 'numberformat'});
166
167 return numberFormat;
168 }
169
170
171 /**
172 * Constructs Intl.NumberFormat object given optional locales and options
173 * parameters.
174 *
175 * @constructor
176 */
177 %SetProperty(Intl, 'NumberFormat', function() {
178 var locales = arguments[0];
179 var options = arguments[1];
180
181 if (!this || this === Intl) {
182 // Constructor is called as a function.
183 return new Intl.NumberFormat(locales, options);
184 }
185
186 return initializeNumberFormat(toObject(this), locales, options);
187 },
188 ATTRIBUTES.DONT_ENUM
189 );
190
191
192 /**
193 * NumberFormat resolvedOptions method.
194 */
195 %SetProperty(Intl.NumberFormat.prototype, 'resolvedOptions', function() {
196 if (%_IsConstructCall()) {
197 throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
198 }
199
200 if (!this || typeof this !== 'object' ||
201 this.__initializedIntlObject !== 'numberformat') {
202 throw new TypeError('resolvedOptions method called on a non-object' +
203 ' or on a object that is not Intl.NumberFormat.');
204 }
205
206 var format = this;
207 var locale = getOptimalLanguageTag(format.resolved.requestedLocale,
208 format.resolved.locale);
209
210 var result = {
211 locale: locale,
212 numberingSystem: format.resolved.numberingSystem,
213 style: format.resolved.style,
214 useGrouping: format.resolved.useGrouping,
215 minimumIntegerDigits: format.resolved.minimumIntegerDigits,
216 minimumFractionDigits: format.resolved.minimumFractionDigits,
217 maximumFractionDigits: format.resolved.maximumFractionDigits,
218 };
219
220 if (result.style === 'currency') {
221 defineWECProperty(result, 'currency', format.resolved.currency);
222 defineWECProperty(result, 'currencyDisplay',
223 format.resolved.currencyDisplay);
224 }
225
226 if (format.resolved.hasOwnProperty('minimumSignificantDigits')) {
227 defineWECProperty(result, 'minimumSignificantDigits',
228 format.resolved.minimumSignificantDigits);
229 }
230
231 if (format.resolved.hasOwnProperty('maximumSignificantDigits')) {
232 defineWECProperty(result, 'maximumSignificantDigits',
233 format.resolved.maximumSignificantDigits);
234 }
235
236 return result;
237 },
238 ATTRIBUTES.DONT_ENUM
239 );
240 %FunctionRemovePrototype(Intl.NumberFormat.prototype.resolvedOptions);
241
242
243 /**
244 * Returns the subset of the given locale list for which this locale list
245 * has a matching (possibly fallback) locale. Locales appear in the same
246 * order in the returned list as in the input list.
247 * Options are optional parameter.
248 */
249 %SetProperty(Intl.NumberFormat, 'supportedLocalesOf', function(locales) {
250 if (%_IsConstructCall()) {
251 throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
252 }
253
254 return supportedLocalesOf('numberformat', locales, arguments[1]);
255 },
256 ATTRIBUTES.DONT_ENUM
257 );
258 %FunctionRemovePrototype(Intl.NumberFormat.supportedLocalesOf);
259
260
261 /**
262 * Returns a String value representing the result of calling ToNumber(value)
263 * according to the effective locale and the formatting options of this
264 * NumberFormat.
265 */
266 function formatNumber(formatter, value) {
267 native function NativeJSInternalNumberFormat();
268
269 // Spec treats -0 and +0 as 0.
270 var number = Number(value);
271 if (number === -0) {
272 number = 0;
273 }
274
275 return NativeJSInternalNumberFormat(formatter.formatter, number);
276 }
277
278
279 /**
280 * Returns a Number that represents string value that was passed in.
281 */
282 function parseNumber(formatter, value) {
283 native function NativeJSInternalNumberParse();
284
285 return NativeJSInternalNumberParse(formatter.formatter, String(value));
286 }
287
288
289 addBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1);
290 addBoundMethod(Intl.NumberFormat, 'v8Parse', parseNumber, 1);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698