globalize-rpk 1.7.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/globalize/currency.js +590 -0
- package/globalize/date.js +3139 -0
- package/globalize/globalize-runtime.js +326 -0
- package/globalize/globalize.js +507 -0
- package/globalize/message.js +2076 -0
- package/globalize/number.js +1727 -0
- package/globalize/plural.js +376 -0
- package/globalize/relative-time.js +203 -0
- package/globalize/unit.js +301 -0
- package/node-main.js +27 -0
- package/package.json +3 -26
- package/CONTRIBUTING.md +0 -5
- package/README.md +0 -818
- package/doc/api/core/constructor.md +0 -28
- package/doc/api/core/load.md +0 -96
- package/doc/api/core/locale.md +0 -43
- package/doc/api/currency/currency-formatter.md +0 -196
- package/doc/api/currency/currency-to-parts-formatter.md +0 -117
- package/doc/api/date/date-formatter.md +0 -203
- package/doc/api/date/date-parser.md +0 -60
- package/doc/api/date/date-to-parts-formatter.md +0 -176
- package/doc/api/date/load-iana-time-zone.md +0 -29
- package/doc/api/message/load-messages.md +0 -105
- package/doc/api/message/message-formatter.md +0 -208
- package/doc/api/number/number-formatter.md +0 -202
- package/doc/api/number/number-parser.md +0 -130
- package/doc/api/number/number-to-parts-formatter.md +0 -140
- package/doc/api/plural/plural-generator.md +0 -84
- package/doc/api/relative-time/relative-time-formatter.md +0 -60
- package/doc/api/unit/unit-formatter.md +0 -72
- package/doc/blog-post/2017-07-xx-1.3.0-announcement.md +0 -177
- package/doc/cldr.md +0 -114
- package/doc/error/e-default-locale-not-defined.md +0 -9
- package/doc/error/e-invalid-cldr.md +0 -14
- package/doc/error/e-invalid-par-type.md +0 -12
- package/doc/error/e-invalid-par-value.md +0 -11
- package/doc/error/e-missing-cldr.md +0 -11
- package/doc/error/e-missing-parameter.md +0 -10
- package/doc/error/e-missing-plural-module.md +0 -9
- package/doc/error/e-par-missing-key.md +0 -11
- package/doc/error/e-par-out-of-range.md +0 -13
- package/doc/error/e-unsupported.md +0 -10
- package/doc/migrating-from-0.x.md +0 -64
- package/examples/amd-bower/.bowerrc +0 -7
- package/examples/amd-bower/README.md +0 -65
- package/examples/amd-bower/bower.json +0 -13
- package/examples/amd-bower/index.html +0 -46
- package/examples/amd-bower/main.js +0 -141
- package/examples/amd-bower/messages/en.json +0 -12
- package/examples/amd-bower/package.json +0 -14
- package/examples/app-npm-webpack/README.md +0 -74
- package/examples/app-npm-webpack/app/index.js +0 -89
- package/examples/app-npm-webpack/index-template.html +0 -71
- package/examples/app-npm-webpack/messages/ar.json +0 -25
- package/examples/app-npm-webpack/messages/de.json +0 -21
- package/examples/app-npm-webpack/messages/en.json +0 -21
- package/examples/app-npm-webpack/messages/es.json +0 -21
- package/examples/app-npm-webpack/messages/pt.json +0 -21
- package/examples/app-npm-webpack/messages/ru.json +0 -23
- package/examples/app-npm-webpack/messages/zh.json +0 -20
- package/examples/app-npm-webpack/package.json +0 -17
- package/examples/app-npm-webpack/webpack-config.js +0 -63
- package/examples/globalize-compiler/README.md +0 -45
- package/examples/globalize-compiler/app.js +0 -58
- package/examples/globalize-compiler/development.html +0 -121
- package/examples/globalize-compiler/messages.json +0 -12
- package/examples/globalize-compiler/package.json +0 -15
- package/examples/globalize-compiler/production.html +0 -75
- package/examples/node-npm/README.md +0 -57
- package/examples/node-npm/main.js +0 -65
- package/examples/node-npm/messages/en.json +0 -12
- package/examples/node-npm/package.json +0 -10
- package/examples/plain-javascript/README.md +0 -81
- package/examples/plain-javascript/index.html +0 -445
@@ -0,0 +1,1727 @@
|
|
1
|
+
/**
|
2
|
+
* Globalize v1.7.0
|
3
|
+
*
|
4
|
+
* https://github.com/globalizejs/globalize
|
5
|
+
*
|
6
|
+
* Copyright OpenJS Foundation and other contributors
|
7
|
+
* Released under the MIT license
|
8
|
+
* https://jquery.org/license
|
9
|
+
*
|
10
|
+
* Date: 2021-08-02T11:53Z
|
11
|
+
*/
|
12
|
+
/*!
|
13
|
+
* Globalize v1.7.0 2021-08-02T11:53Z Released under the MIT license
|
14
|
+
* http://git.io/TrdQbw
|
15
|
+
*/
|
16
|
+
(function( root, factory ) {
|
17
|
+
|
18
|
+
// UMD returnExports
|
19
|
+
if ( typeof define === "function" && define.amd ) {
|
20
|
+
|
21
|
+
// AMD
|
22
|
+
define([
|
23
|
+
"cldr",
|
24
|
+
"../globalize",
|
25
|
+
"cldr/event",
|
26
|
+
"cldr/supplemental"
|
27
|
+
], factory );
|
28
|
+
} else if ( typeof exports === "object" ) {
|
29
|
+
|
30
|
+
// Node, CommonJS
|
31
|
+
module.exports = factory( require( "cldrjs" ), require( "../globalize" ) );
|
32
|
+
} else {
|
33
|
+
|
34
|
+
// Global
|
35
|
+
factory( root.Cldr, root.Globalize );
|
36
|
+
}
|
37
|
+
}(this, function( Cldr, Globalize ) {
|
38
|
+
|
39
|
+
var createError = Globalize._createError,
|
40
|
+
partsJoin = Globalize._partsJoin,
|
41
|
+
partsPush = Globalize._partsPush,
|
42
|
+
regexpEscape = Globalize._regexpEscape,
|
43
|
+
runtimeBind = Globalize._runtimeBind,
|
44
|
+
stringPad = Globalize._stringPad,
|
45
|
+
validateCldr = Globalize._validateCldr,
|
46
|
+
validateDefaultLocale = Globalize._validateDefaultLocale,
|
47
|
+
validateParameterPresence = Globalize._validateParameterPresence,
|
48
|
+
validateParameterRange = Globalize._validateParameterRange,
|
49
|
+
validateParameterType = Globalize._validateParameterType,
|
50
|
+
validateParameterTypePlainObject = Globalize._validateParameterTypePlainObject;
|
51
|
+
|
52
|
+
|
53
|
+
var createErrorUnsupportedFeature = function( feature ) {
|
54
|
+
return createError( "E_UNSUPPORTED", "Unsupported {feature}.", {
|
55
|
+
feature: feature
|
56
|
+
});
|
57
|
+
};
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
var validateParameterTypeNumber = function( value, name ) {
|
63
|
+
validateParameterType(
|
64
|
+
value,
|
65
|
+
name,
|
66
|
+
value === undefined || typeof value === "number",
|
67
|
+
"Number"
|
68
|
+
);
|
69
|
+
};
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
var validateParameterTypeString = function( value, name ) {
|
75
|
+
validateParameterType(
|
76
|
+
value,
|
77
|
+
name,
|
78
|
+
value === undefined || typeof value === "string",
|
79
|
+
"a string"
|
80
|
+
);
|
81
|
+
};
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
var numberFormatterFn = function( numberToPartsFormatter ) {
|
87
|
+
return function numberFormatter( value ) {
|
88
|
+
return partsJoin( numberToPartsFormatter( value ));
|
89
|
+
};
|
90
|
+
};
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
/**
|
96
|
+
* NumberingSystem( cldr )
|
97
|
+
*
|
98
|
+
* - http://www.unicode.org/reports/tr35/tr35-numbers.html#otherNumberingSystems
|
99
|
+
* - http://cldr.unicode.org/index/bcp47-extension
|
100
|
+
* - http://www.unicode.org/reports/tr35/#u_Extension
|
101
|
+
*/
|
102
|
+
var numberNumberingSystem = function( cldr ) {
|
103
|
+
var nu = cldr.attributes[ "u-nu" ];
|
104
|
+
|
105
|
+
if ( nu ) {
|
106
|
+
if ( nu === "traditio" ) {
|
107
|
+
nu = "traditional";
|
108
|
+
}
|
109
|
+
if ( [ "native", "traditional", "finance" ].indexOf( nu ) !== -1 ) {
|
110
|
+
|
111
|
+
// Unicode locale extension `u-nu` is set using either (native, traditional or
|
112
|
+
// finance). So, lookup the respective locale's numberingSystem and return it.
|
113
|
+
return cldr.main([ "numbers/otherNumberingSystems", nu ]);
|
114
|
+
}
|
115
|
+
|
116
|
+
// Unicode locale extension `u-nu` is set with an explicit numberingSystem. Return it.
|
117
|
+
return nu;
|
118
|
+
}
|
119
|
+
|
120
|
+
// Return the default numberingSystem.
|
121
|
+
return cldr.main( "numbers/defaultNumberingSystem" );
|
122
|
+
};
|
123
|
+
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
/**
|
128
|
+
* Compact( name, cldr )
|
129
|
+
*
|
130
|
+
* @compactType [String] Compact mode, `short` or `long`.
|
131
|
+
*
|
132
|
+
* @cldr [Cldr instance].
|
133
|
+
*
|
134
|
+
* Return the localized compact map for the given compact mode.
|
135
|
+
*/
|
136
|
+
var numberCompact = function( compactType, cldr ) {
|
137
|
+
var maxExponent = 0;
|
138
|
+
|
139
|
+
var object = cldr.main([
|
140
|
+
"numbers/decimalFormats-numberSystem-" + numberNumberingSystem( cldr ),
|
141
|
+
compactType,
|
142
|
+
"decimalFormat"
|
143
|
+
]);
|
144
|
+
|
145
|
+
object = Object.keys( object ).reduce(function( newObject, compactKey ) {
|
146
|
+
var numberExponent = compactKey.split( "0" ).length - 1;
|
147
|
+
var pluralForm = compactKey.split( "-" )[ 2 ];
|
148
|
+
newObject[ numberExponent ] = newObject[ numberExponent ] || {};
|
149
|
+
newObject[ numberExponent ][ pluralForm ] = object[ compactKey ];
|
150
|
+
maxExponent = Math.max( numberExponent, maxExponent );
|
151
|
+
return newObject;
|
152
|
+
}, {});
|
153
|
+
|
154
|
+
object.maxExponent = maxExponent;
|
155
|
+
|
156
|
+
return object;
|
157
|
+
};
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
|
162
|
+
/**
|
163
|
+
* nuMap( cldr )
|
164
|
+
*
|
165
|
+
* @cldr [Cldr instance].
|
166
|
+
*
|
167
|
+
* Return digits map if numbering system is different than `latn`.
|
168
|
+
*/
|
169
|
+
var numberNumberingSystemDigitsMap = function( cldr ) {
|
170
|
+
var aux,
|
171
|
+
nu = numberNumberingSystem( cldr );
|
172
|
+
|
173
|
+
if ( nu === "latn" ) {
|
174
|
+
return;
|
175
|
+
}
|
176
|
+
|
177
|
+
aux = cldr.supplemental([ "numberingSystems", nu ]);
|
178
|
+
|
179
|
+
if ( aux._type !== "numeric" ) {
|
180
|
+
throw createErrorUnsupportedFeature( "`" + aux._type + "` numbering system" );
|
181
|
+
}
|
182
|
+
|
183
|
+
return aux._digits;
|
184
|
+
};
|
185
|
+
|
186
|
+
|
187
|
+
|
188
|
+
|
189
|
+
/**
|
190
|
+
* EBNF representation:
|
191
|
+
*
|
192
|
+
* number_pattern_re = prefix?
|
193
|
+
* padding?
|
194
|
+
* (integer_fraction_pattern | significant_pattern)
|
195
|
+
* scientific_notation?
|
196
|
+
* suffix?
|
197
|
+
*
|
198
|
+
* prefix = non_number_stuff
|
199
|
+
*
|
200
|
+
* padding = "*" regexp(.)
|
201
|
+
*
|
202
|
+
* integer_fraction_pattern = integer_pattern
|
203
|
+
* fraction_pattern?
|
204
|
+
*
|
205
|
+
* integer_pattern = regexp([#,]*[0,]*0+)
|
206
|
+
*
|
207
|
+
* fraction_pattern = "." regexp(0*[0-9]*#*)
|
208
|
+
*
|
209
|
+
* significant_pattern = regexp([#,]*@+#*)
|
210
|
+
*
|
211
|
+
* scientific_notation = regexp(E\+?0+)
|
212
|
+
*
|
213
|
+
* suffix = non_number_stuff
|
214
|
+
*
|
215
|
+
* non_number_stuff = regexp(('[^']+'|''|[^*#@0,.E])*)
|
216
|
+
*
|
217
|
+
*
|
218
|
+
* Regexp groups:
|
219
|
+
*
|
220
|
+
* 0: number_pattern_re
|
221
|
+
* 1: prefix
|
222
|
+
* 2: -
|
223
|
+
* 3: -
|
224
|
+
* 4: padding
|
225
|
+
* 5: (integer_fraction_pattern | significant_pattern)
|
226
|
+
* 6: integer_fraction_pattern
|
227
|
+
* 7: integer_pattern
|
228
|
+
* 8: fraction_pattern
|
229
|
+
* 9: significant_pattern
|
230
|
+
* 10: scientific_notation
|
231
|
+
* 11: suffix
|
232
|
+
* 12: -
|
233
|
+
*/
|
234
|
+
var numberPatternRe = ( /^(('([^']|'')*'|[^*#@0,.E])*)(\*.)?((([#,]*[0,]*0+)(\.0*[0-9]*#*)?)|([#,]*@+#*))(E\+?0+)?(('[^']+'|''|[^*#@0,.E])*)$/ );
|
235
|
+
|
236
|
+
|
237
|
+
|
238
|
+
|
239
|
+
/**
|
240
|
+
* format( number, pattern )
|
241
|
+
*
|
242
|
+
* @number [Number].
|
243
|
+
*
|
244
|
+
* @pattern [String] raw pattern for numbers.
|
245
|
+
*
|
246
|
+
* Return the formatted number.
|
247
|
+
* ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
|
248
|
+
*/
|
249
|
+
var numberPatternProperties = function( pattern ) {
|
250
|
+
var aux1, aux2, fractionPattern, integerFractionOrSignificantPattern, integerPattern,
|
251
|
+
maximumFractionDigits, maximumSignificantDigits, minimumFractionDigits,
|
252
|
+
minimumIntegerDigits, minimumSignificantDigits, padding, prefix, primaryGroupingSize,
|
253
|
+
roundIncrement, scientificNotation, secondaryGroupingSize, significantPattern, suffix;
|
254
|
+
|
255
|
+
pattern = pattern.match( numberPatternRe );
|
256
|
+
if ( !pattern ) {
|
257
|
+
throw new Error( "Invalid pattern: " + pattern );
|
258
|
+
}
|
259
|
+
|
260
|
+
prefix = pattern[ 1 ];
|
261
|
+
padding = pattern[ 4 ];
|
262
|
+
integerFractionOrSignificantPattern = pattern[ 5 ];
|
263
|
+
significantPattern = pattern[ 9 ];
|
264
|
+
scientificNotation = pattern[ 10 ];
|
265
|
+
suffix = pattern[ 11 ];
|
266
|
+
|
267
|
+
// Significant digit format
|
268
|
+
if ( significantPattern ) {
|
269
|
+
significantPattern.replace( /(@+)(#*)/, function( _match, minimumSignificantDigitsMatch, maximumSignificantDigitsMatch ) {
|
270
|
+
minimumSignificantDigits = minimumSignificantDigitsMatch.length;
|
271
|
+
maximumSignificantDigits = minimumSignificantDigits +
|
272
|
+
maximumSignificantDigitsMatch.length;
|
273
|
+
});
|
274
|
+
|
275
|
+
// Integer and fractional format
|
276
|
+
} else {
|
277
|
+
fractionPattern = pattern[ 8 ];
|
278
|
+
integerPattern = pattern[ 7 ];
|
279
|
+
|
280
|
+
if ( fractionPattern ) {
|
281
|
+
|
282
|
+
// Minimum fraction digits, and rounding.
|
283
|
+
fractionPattern.replace( /[0-9]+/, function( match ) {
|
284
|
+
minimumFractionDigits = match;
|
285
|
+
});
|
286
|
+
if ( minimumFractionDigits ) {
|
287
|
+
roundIncrement = +( "0." + minimumFractionDigits );
|
288
|
+
minimumFractionDigits = minimumFractionDigits.length;
|
289
|
+
} else {
|
290
|
+
minimumFractionDigits = 0;
|
291
|
+
}
|
292
|
+
|
293
|
+
// Maximum fraction digits
|
294
|
+
// 1: ignore decimal character
|
295
|
+
maximumFractionDigits = fractionPattern.length - 1; /* 1 */
|
296
|
+
} else {
|
297
|
+
minimumFractionDigits = 0;
|
298
|
+
maximumFractionDigits = 0;
|
299
|
+
}
|
300
|
+
|
301
|
+
// Minimum integer digits
|
302
|
+
integerPattern.replace( /0+$/, function( match ) {
|
303
|
+
minimumIntegerDigits = match.length;
|
304
|
+
});
|
305
|
+
}
|
306
|
+
|
307
|
+
// Scientific notation
|
308
|
+
if ( scientificNotation ) {
|
309
|
+
throw createErrorUnsupportedFeature({
|
310
|
+
feature: "scientific notation (not implemented)"
|
311
|
+
});
|
312
|
+
}
|
313
|
+
|
314
|
+
// Padding
|
315
|
+
if ( padding ) {
|
316
|
+
throw createErrorUnsupportedFeature({
|
317
|
+
feature: "padding (not implemented)"
|
318
|
+
});
|
319
|
+
}
|
320
|
+
|
321
|
+
// Grouping
|
322
|
+
if ( ( aux1 = integerFractionOrSignificantPattern.lastIndexOf( "," ) ) !== -1 ) {
|
323
|
+
|
324
|
+
// Primary grouping size is the interval between the last group separator and the end of
|
325
|
+
// the integer (or the end of the significant pattern).
|
326
|
+
aux2 = integerFractionOrSignificantPattern.split( "." )[ 0 ];
|
327
|
+
primaryGroupingSize = aux2.length - aux1 - 1;
|
328
|
+
|
329
|
+
// Secondary grouping size is the interval between the last two group separators.
|
330
|
+
if ( ( aux2 = integerFractionOrSignificantPattern.lastIndexOf( ",", aux1 - 1 ) ) !== -1 ) {
|
331
|
+
secondaryGroupingSize = aux1 - 1 - aux2;
|
332
|
+
}
|
333
|
+
}
|
334
|
+
|
335
|
+
// Return:
|
336
|
+
// 0: @prefix String
|
337
|
+
// 1: @padding Array [ <character>, <count> ] TODO
|
338
|
+
// 2: @minimumIntegerDigits non-negative integer Number value indicating the minimum integer
|
339
|
+
// digits to be used. Numbers will be padded with leading zeroes if necessary.
|
340
|
+
// 3: @minimumFractionDigits and
|
341
|
+
// 4: @maximumFractionDigits are non-negative integer Number values indicating the minimum and
|
342
|
+
// maximum fraction digits to be used. Numbers will be rounded or padded with trailing
|
343
|
+
// zeroes if necessary.
|
344
|
+
// 5: @minimumSignificantDigits and
|
345
|
+
// 6: @maximumSignificantDigits are positive integer Number values indicating the minimum and
|
346
|
+
// maximum fraction digits to be shown. Either none or both of these properties are
|
347
|
+
// present; if they are, they override minimum and maximum integer and fraction digits
|
348
|
+
// – the formatter uses however many integer and fraction digits are required to display
|
349
|
+
// the specified number of significant digits.
|
350
|
+
// 7: @roundIncrement Decimal round increment or null
|
351
|
+
// 8: @primaryGroupingSize
|
352
|
+
// 9: @secondaryGroupingSize
|
353
|
+
// 10: @suffix String
|
354
|
+
return [
|
355
|
+
prefix,
|
356
|
+
padding,
|
357
|
+
minimumIntegerDigits,
|
358
|
+
minimumFractionDigits,
|
359
|
+
maximumFractionDigits,
|
360
|
+
minimumSignificantDigits,
|
361
|
+
maximumSignificantDigits,
|
362
|
+
roundIncrement,
|
363
|
+
primaryGroupingSize,
|
364
|
+
secondaryGroupingSize,
|
365
|
+
suffix
|
366
|
+
];
|
367
|
+
};
|
368
|
+
|
369
|
+
|
370
|
+
|
371
|
+
|
372
|
+
/**
|
373
|
+
* Symbol( name, cldr )
|
374
|
+
*
|
375
|
+
* @name [String] Symbol name.
|
376
|
+
*
|
377
|
+
* @cldr [Cldr instance].
|
378
|
+
*
|
379
|
+
* Return the localized symbol given its name.
|
380
|
+
*/
|
381
|
+
var numberSymbol = function( name, cldr ) {
|
382
|
+
return cldr.main([
|
383
|
+
"numbers/symbols-numberSystem-" + numberNumberingSystem( cldr ),
|
384
|
+
name
|
385
|
+
]);
|
386
|
+
};
|
387
|
+
|
388
|
+
|
389
|
+
|
390
|
+
|
391
|
+
var numberSymbolName = {
|
392
|
+
".": "decimal",
|
393
|
+
",": "group",
|
394
|
+
"%": "percentSign",
|
395
|
+
"+": "plusSign",
|
396
|
+
"-": "minusSign",
|
397
|
+
"E": "exponential",
|
398
|
+
"\u2030": "perMille"
|
399
|
+
};
|
400
|
+
|
401
|
+
|
402
|
+
|
403
|
+
|
404
|
+
/**
|
405
|
+
* symbolMap( cldr )
|
406
|
+
*
|
407
|
+
* @cldr [Cldr instance].
|
408
|
+
*
|
409
|
+
* Return the (localized symbol, pattern symbol) key value pair, eg. {
|
410
|
+
* ".": "٫",
|
411
|
+
* ",": "٬",
|
412
|
+
* "%": "٪",
|
413
|
+
* ...
|
414
|
+
* };
|
415
|
+
*/
|
416
|
+
var numberSymbolMap = function( cldr ) {
|
417
|
+
var symbol,
|
418
|
+
symbolMap = {};
|
419
|
+
|
420
|
+
for ( symbol in numberSymbolName ) {
|
421
|
+
symbolMap[ symbol ] = numberSymbol( numberSymbolName[ symbol ], cldr );
|
422
|
+
}
|
423
|
+
|
424
|
+
return symbolMap;
|
425
|
+
};
|
426
|
+
|
427
|
+
|
428
|
+
|
429
|
+
|
430
|
+
var numberTruncate = function( value ) {
|
431
|
+
if ( isNaN( value ) ) {
|
432
|
+
return NaN;
|
433
|
+
}
|
434
|
+
return Math[ value < 0 ? "ceil" : "floor" ]( value );
|
435
|
+
};
|
436
|
+
|
437
|
+
|
438
|
+
|
439
|
+
|
440
|
+
/**
|
441
|
+
* round( method )
|
442
|
+
*
|
443
|
+
* @method [String] with either "round", "ceil", "floor", or "truncate".
|
444
|
+
*
|
445
|
+
* Return function( value, incrementOrExp ):
|
446
|
+
*
|
447
|
+
* @value [Number] eg. 123.45.
|
448
|
+
*
|
449
|
+
* @incrementOrExp [Number] optional, eg. 0.1; or
|
450
|
+
* [Object] Either { increment: <value> } or { exponent: <value> }
|
451
|
+
*
|
452
|
+
* Return the rounded number, eg:
|
453
|
+
* - round( "round" )( 123.45 ): 123;
|
454
|
+
* - round( "ceil" )( 123.45 ): 124;
|
455
|
+
* - round( "floor" )( 123.45 ): 123;
|
456
|
+
* - round( "truncate" )( 123.45 ): 123;
|
457
|
+
* - round( "round" )( 123.45, 0.1 ): 123.5;
|
458
|
+
* - round( "round" )( 123.45, 10 ): 120;
|
459
|
+
*
|
460
|
+
* Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
|
461
|
+
* Ref: #376
|
462
|
+
*/
|
463
|
+
var numberRound = function( method ) {
|
464
|
+
method = method || "round";
|
465
|
+
method = method === "truncate" ? numberTruncate : Math[ method ];
|
466
|
+
|
467
|
+
return function( value, incrementOrExp ) {
|
468
|
+
var exp, increment;
|
469
|
+
|
470
|
+
value = +value;
|
471
|
+
|
472
|
+
// If the value is not a number, return NaN.
|
473
|
+
if ( isNaN( value ) ) {
|
474
|
+
return NaN;
|
475
|
+
}
|
476
|
+
|
477
|
+
// Exponent given.
|
478
|
+
if ( typeof incrementOrExp === "object" && incrementOrExp.exponent ) {
|
479
|
+
exp = +incrementOrExp.exponent;
|
480
|
+
increment = 1;
|
481
|
+
|
482
|
+
if ( exp === 0 ) {
|
483
|
+
return method( value );
|
484
|
+
}
|
485
|
+
|
486
|
+
// If the exp is not an integer, return NaN.
|
487
|
+
if ( !( typeof exp === "number" && exp % 1 === 0 ) ) {
|
488
|
+
return NaN;
|
489
|
+
}
|
490
|
+
|
491
|
+
// Increment given.
|
492
|
+
} else {
|
493
|
+
increment = +incrementOrExp || 1;
|
494
|
+
|
495
|
+
if ( increment === 1 ) {
|
496
|
+
return method( value );
|
497
|
+
}
|
498
|
+
|
499
|
+
// If the increment is not a number, return NaN.
|
500
|
+
if ( isNaN( increment ) ) {
|
501
|
+
return NaN;
|
502
|
+
}
|
503
|
+
|
504
|
+
increment = increment.toExponential().split( "e" );
|
505
|
+
exp = +increment[ 1 ];
|
506
|
+
increment = +increment[ 0 ];
|
507
|
+
}
|
508
|
+
|
509
|
+
// Shift & Round
|
510
|
+
value = value.toString().split( "e" );
|
511
|
+
value[ 0 ] = +value[ 0 ] / increment;
|
512
|
+
value[ 1 ] = value[ 1 ] ? ( +value[ 1 ] - exp ) : -exp;
|
513
|
+
value = method( +( value[ 0 ] + "e" + value[ 1 ] ) );
|
514
|
+
|
515
|
+
// Shift back
|
516
|
+
value = value.toString().split( "e" );
|
517
|
+
value[ 0 ] = +value[ 0 ] * increment;
|
518
|
+
value[ 1 ] = value[ 1 ] ? ( +value[ 1 ] + exp ) : exp;
|
519
|
+
return +( value[ 0 ] + "e" + value[ 1 ] );
|
520
|
+
};
|
521
|
+
};
|
522
|
+
|
523
|
+
|
524
|
+
|
525
|
+
|
526
|
+
/**
|
527
|
+
* formatProperties( pattern, cldr [, options] )
|
528
|
+
*
|
529
|
+
* @pattern [String] raw pattern for numbers.
|
530
|
+
*
|
531
|
+
* @cldr [Cldr instance].
|
532
|
+
*
|
533
|
+
* @options [Object]:
|
534
|
+
* - minimumIntegerDigits [Number]
|
535
|
+
* - minimumFractionDigits, maximumFractionDigits [Number]
|
536
|
+
* - minimumSignificantDigits, maximumSignificantDigits [Number]
|
537
|
+
* - round [String] "ceil", "floor", "round" (default), or "truncate".
|
538
|
+
* - useGrouping [Boolean] default true.
|
539
|
+
*
|
540
|
+
* Return the processed properties that will be used in number/format.
|
541
|
+
* ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
|
542
|
+
*/
|
543
|
+
var numberFormatProperties = function( pattern, cldr, options ) {
|
544
|
+
var negativePattern, negativePrefix, negativeProperties, negativeSuffix, positivePattern,
|
545
|
+
roundFn, properties;
|
546
|
+
|
547
|
+
function getOptions( attribute, propertyIndex ) {
|
548
|
+
if ( attribute in options ) {
|
549
|
+
properties[ propertyIndex ] = options[ attribute ];
|
550
|
+
}
|
551
|
+
}
|
552
|
+
|
553
|
+
options = options || {};
|
554
|
+
pattern = pattern.split( ";" );
|
555
|
+
|
556
|
+
positivePattern = pattern[ 0 ];
|
557
|
+
|
558
|
+
negativePattern = pattern[ 1 ] || "-" + positivePattern;
|
559
|
+
negativeProperties = numberPatternProperties( negativePattern );
|
560
|
+
negativePrefix = negativeProperties[ 0 ];
|
561
|
+
negativeSuffix = negativeProperties[ 10 ];
|
562
|
+
|
563
|
+
// Have runtime code to refer to numberRound() instead of including it explicitly.
|
564
|
+
roundFn = numberRound( options.round );
|
565
|
+
roundFn.generatorString = function() {
|
566
|
+
return "numberRound(" + ( options.round ? "\"" + options.round + "\"" : "" ) + ")";
|
567
|
+
};
|
568
|
+
|
569
|
+
properties = numberPatternProperties( positivePattern ).concat([
|
570
|
+
positivePattern,
|
571
|
+
negativePrefix + positivePattern + negativeSuffix,
|
572
|
+
negativePrefix,
|
573
|
+
negativeSuffix,
|
574
|
+
roundFn,
|
575
|
+
numberSymbol( "infinity", cldr ),
|
576
|
+
numberSymbol( "nan", cldr ),
|
577
|
+
numberSymbolMap( cldr ),
|
578
|
+
numberNumberingSystemDigitsMap( cldr )
|
579
|
+
]);
|
580
|
+
|
581
|
+
if ( options.compact ) {
|
582
|
+
|
583
|
+
// The compact digits number pattern is always `0+`, so override the following properties.
|
584
|
+
// Note: minimumIntegerDigits would actually range from `0` to `000` based on the scale of
|
585
|
+
// the value to be formatted, though we're always using 1 as a simplification, because the
|
586
|
+
// number won't be zero-padded since we chose the right format based on the scale, i.e.,
|
587
|
+
// we'd never see something like `003M` anyway.
|
588
|
+
properties[ 2 ] = 1; // minimumIntegerDigits
|
589
|
+
properties[ 3 ] = 0; // minimumFractionDigits
|
590
|
+
properties[ 4 ] = 0; // maximumFractionDigits
|
591
|
+
properties[ 5 ] = // minimumSignificantDigits &
|
592
|
+
properties[ 6 ] = undefined; // maximumSignificantDigits
|
593
|
+
|
594
|
+
properties[ 20 ] = numberCompact( options.compact, cldr );
|
595
|
+
}
|
596
|
+
|
597
|
+
getOptions( "minimumIntegerDigits", 2 );
|
598
|
+
getOptions( "minimumFractionDigits", 3 );
|
599
|
+
getOptions( "maximumFractionDigits", 4 );
|
600
|
+
getOptions( "minimumSignificantDigits", 5 );
|
601
|
+
getOptions( "maximumSignificantDigits", 6 );
|
602
|
+
|
603
|
+
// Grouping separators
|
604
|
+
if ( options.useGrouping === false ) {
|
605
|
+
properties[ 8 ] = null;
|
606
|
+
}
|
607
|
+
|
608
|
+
// Normalize number of digits if only one of either minimumFractionDigits or
|
609
|
+
// maximumFractionDigits is passed in as an option
|
610
|
+
if ( "minimumFractionDigits" in options && !( "maximumFractionDigits" in options ) ) {
|
611
|
+
|
612
|
+
// maximumFractionDigits = Math.max( minimumFractionDigits, maximumFractionDigits );
|
613
|
+
properties[ 4 ] = Math.max( properties[ 3 ], properties[ 4 ] );
|
614
|
+
} else if ( !( "minimumFractionDigits" in options ) &&
|
615
|
+
"maximumFractionDigits" in options ) {
|
616
|
+
|
617
|
+
// minimumFractionDigits = Math.min( minimumFractionDigits, maximumFractionDigits );
|
618
|
+
properties[ 3 ] = Math.min( properties[ 3 ], properties[ 4 ] );
|
619
|
+
}
|
620
|
+
|
621
|
+
// Return:
|
622
|
+
// 0-10: see number/pattern-properties.
|
623
|
+
// 11: @positivePattern [String] Positive pattern.
|
624
|
+
// 12: @negativePattern [String] Negative pattern.
|
625
|
+
// 13: @negativePrefix [String] Negative prefix.
|
626
|
+
// 14: @negativeSuffix [String] Negative suffix.
|
627
|
+
// 15: @round [Function] Round function.
|
628
|
+
// 16: @infinitySymbol [String] Infinity symbol.
|
629
|
+
// 17: @nanSymbol [String] NaN symbol.
|
630
|
+
// 18: @symbolMap [Object] A bunch of other symbols.
|
631
|
+
// 19: @nuDigitsMap [Array] Digits map if numbering system is different than `latn`.
|
632
|
+
// 20: @compactMap [Object] Map of per-digit-count format patterns for specified compact mode.
|
633
|
+
return properties;
|
634
|
+
};
|
635
|
+
|
636
|
+
|
637
|
+
|
638
|
+
|
639
|
+
/**
|
640
|
+
* Generated by:
|
641
|
+
*
|
642
|
+
* var regenerate = require( "regenerate" );
|
643
|
+
* var formatSymbols = require( "@unicode/unicode-13.0.0/General_Category/Format/symbols" );
|
644
|
+
* regenerate().add( formatSymbols ).toString();
|
645
|
+
*
|
646
|
+
* https://github.com/mathiasbynens/regenerate
|
647
|
+
* https://github.com/node-unicode/unicode-13.0.0
|
648
|
+
*/
|
649
|
+
var regexpCfG = /[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804[\uDCBD\uDCCD]|\uD80D[\uDC30-\uDC38]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/g;
|
650
|
+
|
651
|
+
|
652
|
+
|
653
|
+
|
654
|
+
/**
|
655
|
+
* Generated by:
|
656
|
+
*
|
657
|
+
* var regenerate = require( "regenerate" );
|
658
|
+
* var dashSymbols = require( "https://github.com/node-unicode/unicode-13.0.0/General_Category/Dash_Punctuation/symbols" );
|
659
|
+
* regenerate().add( dashSymbols ).toString();
|
660
|
+
*
|
661
|
+
* https://github.com/mathiasbynens/regenerate
|
662
|
+
* https://github.com/node-unicode/unicode-13.0.0
|
663
|
+
*
|
664
|
+
* NOTE: In addition to [:dash:], the below includes MINUS SIGN U+2212.
|
665
|
+
*/
|
666
|
+
var regexpDashG = /[\x2D\u058A\u05BE\u1400\u1806\u2010-\u2015\u2E17\u2E1A\u2E3A\u2E3B\u2E40\u301C\u3030\u30A0\uFE31\uFE32\uFE58\uFE63\uFF0D\u2212]|\uD803\uDEAD/g;
|
667
|
+
|
668
|
+
|
669
|
+
|
670
|
+
|
671
|
+
/**
|
672
|
+
* Generated by:
|
673
|
+
*
|
674
|
+
* var regenerate = require( "regenerate" );
|
675
|
+
* var spaceSeparatorSymbols = require( "@unicode/unicode-13.0.0/General_Category/Space_Separator/symbols" );
|
676
|
+
* regenerate().add( spaceSeparatorSymbols ).toString();
|
677
|
+
*
|
678
|
+
* https://github.com/mathiasbynens/regenerate
|
679
|
+
* https://github.com/node-unicode/unicode-13.0.0
|
680
|
+
*/
|
681
|
+
var regexpZsG = /[ \xA0\u1680\u2000-\u200A\u202F\u205F\u3000]/g;
|
682
|
+
|
683
|
+
|
684
|
+
|
685
|
+
|
686
|
+
/**
|
687
|
+
* Loose Matching:
|
688
|
+
* - Ignore all format characters, which includes RLM, LRM or ALM used to control BIDI
|
689
|
+
* formatting.
|
690
|
+
* - Map all characters in [:Zs:] to U+0020 SPACE;
|
691
|
+
* - Map all characters in [:Dash:] to U+002D HYPHEN-MINUS;
|
692
|
+
*/
|
693
|
+
var looseMatching = function( value ) {
|
694
|
+
return value
|
695
|
+
.replace( regexpCfG, "" )
|
696
|
+
.replace( regexpDashG, "-" )
|
697
|
+
.replace( regexpZsG, " " );
|
698
|
+
};
|
699
|
+
|
700
|
+
|
701
|
+
|
702
|
+
|
703
|
+
/**
|
704
|
+
* parse( value, properties )
|
705
|
+
*
|
706
|
+
* @value [String].
|
707
|
+
*
|
708
|
+
* @properties [Object] Parser properties is a reduced pre-processed cldr
|
709
|
+
* data set returned by numberParserProperties().
|
710
|
+
*
|
711
|
+
* Return the parsed Number (including Infinity) or NaN when value is invalid.
|
712
|
+
* ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
|
713
|
+
*/
|
714
|
+
var numberParse = function( value, properties ) {
|
715
|
+
var grammar, invertedNuDigitsMap, invertedSymbolMap, negative, number, prefix, prefixNSuffix,
|
716
|
+
suffix, tokenizer, valid;
|
717
|
+
|
718
|
+
// Grammar:
|
719
|
+
// - Value <= NaN | PositiveNumber | NegativeNumber
|
720
|
+
// - PositiveNumber <= PositivePrefix NumberOrInf PositiveSufix
|
721
|
+
// - NegativeNumber <= NegativePrefix NumberOrInf
|
722
|
+
// - NumberOrInf <= Number | Inf
|
723
|
+
grammar = [
|
724
|
+
[ "nan" ],
|
725
|
+
[ "prefix", "infinity", "suffix" ],
|
726
|
+
[ "prefix", "number", "suffix" ],
|
727
|
+
[ "negativePrefix", "infinity", "negativeSuffix" ],
|
728
|
+
[ "negativePrefix", "number", "negativeSuffix" ]
|
729
|
+
];
|
730
|
+
|
731
|
+
invertedSymbolMap = properties[ 0 ];
|
732
|
+
invertedNuDigitsMap = properties[ 1 ] || {};
|
733
|
+
tokenizer = properties[ 2 ];
|
734
|
+
|
735
|
+
value = looseMatching( value );
|
736
|
+
|
737
|
+
function parse( type ) {
|
738
|
+
return function( lexeme ) {
|
739
|
+
|
740
|
+
// Reverse localized symbols and numbering system.
|
741
|
+
lexeme = lexeme.split( "" ).map(function( character ) {
|
742
|
+
return invertedSymbolMap[ character ] ||
|
743
|
+
invertedNuDigitsMap[ character ] ||
|
744
|
+
character;
|
745
|
+
}).join( "" );
|
746
|
+
|
747
|
+
switch ( type ) {
|
748
|
+
case "infinity":
|
749
|
+
number = Infinity;
|
750
|
+
break;
|
751
|
+
|
752
|
+
case "nan":
|
753
|
+
number = NaN;
|
754
|
+
break;
|
755
|
+
|
756
|
+
case "number":
|
757
|
+
|
758
|
+
// Remove grouping separators.
|
759
|
+
lexeme = lexeme.replace( /,/g, "" );
|
760
|
+
|
761
|
+
number = +lexeme;
|
762
|
+
break;
|
763
|
+
|
764
|
+
case "prefix":
|
765
|
+
case "negativePrefix":
|
766
|
+
prefix = lexeme;
|
767
|
+
break;
|
768
|
+
|
769
|
+
case "suffix":
|
770
|
+
suffix = lexeme;
|
771
|
+
break;
|
772
|
+
|
773
|
+
case "negativeSuffix":
|
774
|
+
suffix = lexeme;
|
775
|
+
negative = true;
|
776
|
+
break;
|
777
|
+
|
778
|
+
// This should never be reached.
|
779
|
+
default:
|
780
|
+
throw new Error( "Internal error" );
|
781
|
+
}
|
782
|
+
return "";
|
783
|
+
};
|
784
|
+
}
|
785
|
+
|
786
|
+
function tokenizeNParse( _value, grammar ) {
|
787
|
+
return grammar.some(function( statement ) {
|
788
|
+
var value = _value;
|
789
|
+
|
790
|
+
// The whole grammar statement should be used (i.e., .every() return true) and value be
|
791
|
+
// entirely consumed (i.e., !value.length).
|
792
|
+
return statement.every(function( type ) {
|
793
|
+
if ( value.match( tokenizer[ type ] ) === null ) {
|
794
|
+
return false;
|
795
|
+
}
|
796
|
+
|
797
|
+
// Consume and parse it.
|
798
|
+
value = value.replace( tokenizer[ type ], parse( type ) );
|
799
|
+
return true;
|
800
|
+
}) && !value.length;
|
801
|
+
});
|
802
|
+
}
|
803
|
+
|
804
|
+
valid = tokenizeNParse( value, grammar );
|
805
|
+
|
806
|
+
// NaN
|
807
|
+
if ( !valid || isNaN( number ) ) {
|
808
|
+
return NaN;
|
809
|
+
}
|
810
|
+
|
811
|
+
prefixNSuffix = "" + prefix + suffix;
|
812
|
+
|
813
|
+
// Percent
|
814
|
+
if ( prefixNSuffix.indexOf( "%" ) !== -1 ) {
|
815
|
+
number /= 100;
|
816
|
+
|
817
|
+
// Per mille
|
818
|
+
} else if ( prefixNSuffix.indexOf( "\u2030" ) !== -1 ) {
|
819
|
+
number /= 1000;
|
820
|
+
}
|
821
|
+
|
822
|
+
// Negative number
|
823
|
+
if ( negative ) {
|
824
|
+
number *= -1;
|
825
|
+
}
|
826
|
+
|
827
|
+
return number;
|
828
|
+
};
|
829
|
+
|
830
|
+
|
831
|
+
|
832
|
+
|
833
|
+
var numberParserFn = function( properties ) {
|
834
|
+
return function numberParser( value ) {
|
835
|
+
validateParameterPresence( value, "value" );
|
836
|
+
validateParameterTypeString( value, "value" );
|
837
|
+
|
838
|
+
return numberParse( value, properties );
|
839
|
+
};
|
840
|
+
|
841
|
+
};
|
842
|
+
|
843
|
+
|
844
|
+
|
845
|
+
|
846
|
+
/**
|
847
|
+
* symbolMap( cldr )
|
848
|
+
*
|
849
|
+
* @cldr [Cldr instance].
|
850
|
+
*
|
851
|
+
* Return the (localized symbol, pattern symbol) key value pair, eg. {
|
852
|
+
* "٫": ".",
|
853
|
+
* "٬": ",",
|
854
|
+
* "٪": "%",
|
855
|
+
* ...
|
856
|
+
* };
|
857
|
+
*/
|
858
|
+
var numberSymbolInvertedMap = function( cldr ) {
|
859
|
+
var symbol,
|
860
|
+
symbolMap = {};
|
861
|
+
|
862
|
+
for ( symbol in numberSymbolName ) {
|
863
|
+
symbolMap[ numberSymbol( numberSymbolName[ symbol ], cldr ) ] = symbol;
|
864
|
+
}
|
865
|
+
|
866
|
+
return symbolMap;
|
867
|
+
};
|
868
|
+
|
869
|
+
|
870
|
+
|
871
|
+
|
872
|
+
/**
|
873
|
+
* objectMap( object, fn)
|
874
|
+
*
|
875
|
+
* - object
|
876
|
+
*
|
877
|
+
* - fn( pair ) => pair
|
878
|
+
*/
|
879
|
+
var objectMap = function( object, fn ) {
|
880
|
+
return Object.keys( object ).map(function( key ) {
|
881
|
+
return fn([ key, object[ key ] ]);
|
882
|
+
}).reduce(function( object, pair ) {
|
883
|
+
object[ pair[ 0 ] ] = pair[ 1 ];
|
884
|
+
return object;
|
885
|
+
}, {});
|
886
|
+
};
|
887
|
+
|
888
|
+
|
889
|
+
|
890
|
+
|
891
|
+
/**
|
892
|
+
* removeLiteralQuotes( string )
|
893
|
+
*
|
894
|
+
* Return:
|
895
|
+
* - `'` if input string is `''`.
|
896
|
+
* - `o'clock` if input string is `'o''clock'`.
|
897
|
+
* - `foo` if input string is `foo`, i.e., return the same value in case it isn't a single-quoted
|
898
|
+
* string.
|
899
|
+
*/
|
900
|
+
var removeLiteralQuotes = function( string ) {
|
901
|
+
if ( string[ 0 ] + string[ string.length - 1 ] !== "''" ) {
|
902
|
+
return string;
|
903
|
+
}
|
904
|
+
if ( string === "''" ) {
|
905
|
+
return "'";
|
906
|
+
}
|
907
|
+
return string.replace( /''/g, "'" ).slice( 1, -1 );
|
908
|
+
};
|
909
|
+
|
910
|
+
|
911
|
+
|
912
|
+
|
913
|
+
/**
|
914
|
+
* parseProperties( pattern, cldr )
|
915
|
+
*
|
916
|
+
* @pattern [String] raw pattern for numbers.
|
917
|
+
*
|
918
|
+
* @cldr [Cldr instance].
|
919
|
+
*
|
920
|
+
* Return parser properties, used to feed parser function.
|
921
|
+
*
|
922
|
+
* TODO:
|
923
|
+
* - Scientific_notation;
|
924
|
+
* - Padding;
|
925
|
+
*/
|
926
|
+
var numberParseProperties = function( pattern, cldr, options ) {
|
927
|
+
var aux, decimalSymbolRe, digitsRe, groupingSeparatorRe, infinitySymbol, invertedNuDigitsMap,
|
928
|
+
invertedSymbolMap, maximumFractionDigits, maximumSignificantDigits,
|
929
|
+
minimumSignificantDigits, nanSymbol, negativePrefix, negativeSuffix, nuDigitsMap,
|
930
|
+
numberTokenizer, prefix, primaryGroupingSize, secondaryGroupingSize, suffix, symbolMap,
|
931
|
+
formatProperties = numberFormatProperties( pattern, cldr, options );
|
932
|
+
|
933
|
+
prefix = looseMatching( formatProperties[ 0 ] );
|
934
|
+
maximumFractionDigits = formatProperties[ 4 ];
|
935
|
+
minimumSignificantDigits = formatProperties[ 5 ];
|
936
|
+
maximumSignificantDigits = formatProperties[ 6 ];
|
937
|
+
primaryGroupingSize = formatProperties[ 8 ];
|
938
|
+
secondaryGroupingSize = formatProperties[ 9 ];
|
939
|
+
suffix = looseMatching( formatProperties[ 10 ] );
|
940
|
+
negativePrefix = looseMatching( formatProperties[ 13 ] );
|
941
|
+
negativeSuffix = looseMatching( formatProperties[ 14 ] );
|
942
|
+
infinitySymbol = looseMatching( formatProperties[ 16 ] );
|
943
|
+
nanSymbol = looseMatching( formatProperties[ 17 ] );
|
944
|
+
symbolMap = objectMap( formatProperties[ 18 ], function( pair ) {
|
945
|
+
return [ pair[ 0 ], looseMatching( pair[ 1 ] ) ];
|
946
|
+
});
|
947
|
+
nuDigitsMap = formatProperties[ 19 ];
|
948
|
+
|
949
|
+
invertedSymbolMap = objectMap( numberSymbolInvertedMap( cldr ), function( pair ) {
|
950
|
+
return [ looseMatching( pair[ 0 ] ), pair[ 1 ] ];
|
951
|
+
});
|
952
|
+
|
953
|
+
digitsRe = nuDigitsMap ? "[" + nuDigitsMap + "]" : "\\d";
|
954
|
+
groupingSeparatorRe = regexpEscape( symbolMap[ "," ] );
|
955
|
+
decimalSymbolRe = regexpEscape( symbolMap[ "." ] );
|
956
|
+
|
957
|
+
if ( nuDigitsMap ) {
|
958
|
+
invertedNuDigitsMap = nuDigitsMap.split( "" ).reduce(function( object, localizedDigit, i ) {
|
959
|
+
object[ localizedDigit ] = String( i );
|
960
|
+
return object;
|
961
|
+
}, {} );
|
962
|
+
}
|
963
|
+
|
964
|
+
aux = [ prefix, suffix, negativePrefix, negativeSuffix ].map(function( value ) {
|
965
|
+
return value.replace( /('([^']|'')+'|'')|./g, function( character, literal ) {
|
966
|
+
|
967
|
+
// Literals
|
968
|
+
if ( literal ) {
|
969
|
+
return removeLiteralQuotes( literal );
|
970
|
+
}
|
971
|
+
|
972
|
+
// Symbols
|
973
|
+
character = character.replace( /[\-+E%\u2030]/, function( symbol ) {
|
974
|
+
return symbolMap[ symbol ];
|
975
|
+
});
|
976
|
+
|
977
|
+
return character;
|
978
|
+
});
|
979
|
+
});
|
980
|
+
|
981
|
+
prefix = aux[ 0 ];
|
982
|
+
suffix = aux[ 1 ];
|
983
|
+
negativePrefix = aux[ 2 ];
|
984
|
+
negativeSuffix = aux[ 3 ];
|
985
|
+
|
986
|
+
// Number
|
987
|
+
//
|
988
|
+
// number_re = integer fraction?
|
989
|
+
//
|
990
|
+
// integer = digits | digits_using_grouping_separators
|
991
|
+
//
|
992
|
+
// fraction = regexp((.\d+)?)
|
993
|
+
//
|
994
|
+
// digits = regexp(\d+)
|
995
|
+
//
|
996
|
+
// digits_w_grouping_separators = digits_w_1_grouping_separators |
|
997
|
+
// digits_w_2_grouping_separators
|
998
|
+
//
|
999
|
+
// digits_w_1_grouping_separators = regexp(\d{1,3}(,\d{3})+)
|
1000
|
+
//
|
1001
|
+
// digits_w_2_grouping_separators = regexp(\d{1,2}((,\d{2})*(,\d{3})))
|
1002
|
+
|
1003
|
+
// Integer part
|
1004
|
+
numberTokenizer = digitsRe + "+";
|
1005
|
+
|
1006
|
+
// Grouping separators
|
1007
|
+
if ( primaryGroupingSize ) {
|
1008
|
+
if ( secondaryGroupingSize ) {
|
1009
|
+
aux = digitsRe + "{1," + secondaryGroupingSize + "}((" + groupingSeparatorRe +
|
1010
|
+
digitsRe + "{" + secondaryGroupingSize + "})*(" + groupingSeparatorRe +
|
1011
|
+
digitsRe + "{" + primaryGroupingSize + "}))";
|
1012
|
+
} else {
|
1013
|
+
aux = digitsRe + "{1," + primaryGroupingSize + "}(" + groupingSeparatorRe +
|
1014
|
+
digitsRe + "{" + primaryGroupingSize + "})+";
|
1015
|
+
}
|
1016
|
+
numberTokenizer = "(" + aux + "|" + numberTokenizer + ")";
|
1017
|
+
}
|
1018
|
+
|
1019
|
+
// Fraction part? Only included if 1 or 2.
|
1020
|
+
// 1: Using significant digit format.
|
1021
|
+
// 2: Using integer and fractional format && it has a maximumFractionDigits.
|
1022
|
+
if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) || /* 1 */
|
1023
|
+
maximumFractionDigits /* 2 */ ) {
|
1024
|
+
|
1025
|
+
// 1: Handle trailing decimal separator, e.g., `"1." => `1``.
|
1026
|
+
aux = decimalSymbolRe + digitsRe + "+";
|
1027
|
+
numberTokenizer = numberTokenizer + "(" + aux + "|" + decimalSymbolRe /* 1 */ + ")?" +
|
1028
|
+
|
1029
|
+
// Handle non-padded decimals, e.g., `".12"` => `0.12` by making the integer part
|
1030
|
+
// optional.
|
1031
|
+
"|(" + numberTokenizer + ")?" + aux;
|
1032
|
+
|
1033
|
+
numberTokenizer = "(" + numberTokenizer + ")";
|
1034
|
+
}
|
1035
|
+
|
1036
|
+
// 0: @invertedSymbolMap [Object] Inverted symbol map.
|
1037
|
+
// 1: @invertedNuDigitsMap [Object] Inverted digits map if numbering system is different than
|
1038
|
+
// `latn`.
|
1039
|
+
// 2: @tokenizer [Object] Tokenizer map, used by parser to consume input.
|
1040
|
+
return [
|
1041
|
+
invertedSymbolMap,
|
1042
|
+
invertedNuDigitsMap,
|
1043
|
+
{
|
1044
|
+
infinity: new RegExp( "^" + regexpEscape( infinitySymbol ) ),
|
1045
|
+
nan: new RegExp( "^" + regexpEscape( nanSymbol ) ),
|
1046
|
+
negativePrefix: new RegExp( "^" + regexpEscape( negativePrefix ) ),
|
1047
|
+
negativeSuffix: new RegExp( "^" + regexpEscape( negativeSuffix ) ),
|
1048
|
+
number: new RegExp( "^" + numberTokenizer ),
|
1049
|
+
prefix: new RegExp( "^" + regexpEscape( prefix ) ),
|
1050
|
+
suffix: new RegExp( "^" + regexpEscape( suffix ) )
|
1051
|
+
}
|
1052
|
+
];
|
1053
|
+
|
1054
|
+
};
|
1055
|
+
|
1056
|
+
|
1057
|
+
|
1058
|
+
|
1059
|
+
/**
|
1060
|
+
* Pattern( style )
|
1061
|
+
*
|
1062
|
+
* @style [String] "decimal" (default) or "percent".
|
1063
|
+
*
|
1064
|
+
* @cldr [Cldr instance].
|
1065
|
+
*/
|
1066
|
+
var numberPattern = function( style, cldr ) {
|
1067
|
+
if ( style !== "decimal" && style !== "percent" ) {
|
1068
|
+
throw new Error( "Invalid style" );
|
1069
|
+
}
|
1070
|
+
|
1071
|
+
return cldr.main([
|
1072
|
+
"numbers",
|
1073
|
+
style + "Formats-numberSystem-" + numberNumberingSystem( cldr ),
|
1074
|
+
"standard"
|
1075
|
+
]);
|
1076
|
+
};
|
1077
|
+
|
1078
|
+
|
1079
|
+
|
1080
|
+
|
1081
|
+
/**
|
1082
|
+
* EBNF representation:
|
1083
|
+
*
|
1084
|
+
* compact_pattern_re = prefix?
|
1085
|
+
* number_pattern_re
|
1086
|
+
* suffix?
|
1087
|
+
*
|
1088
|
+
* number_pattern_re = 0+
|
1089
|
+
*
|
1090
|
+
* Regexp groups:
|
1091
|
+
*
|
1092
|
+
* 0: compact_pattern_re
|
1093
|
+
* 1: prefix
|
1094
|
+
* 2: number_pattern_re (the number pattern to use in compact mode)
|
1095
|
+
* 3: suffix
|
1096
|
+
*/
|
1097
|
+
var numberCompactPatternRe = ( /^([^0]*)(0+)([^0]*)$/ );
|
1098
|
+
|
1099
|
+
|
1100
|
+
|
1101
|
+
|
1102
|
+
/**
|
1103
|
+
* goupingSeparator( number, primaryGroupingSize, secondaryGroupingSize )
|
1104
|
+
*
|
1105
|
+
* @number [Number].
|
1106
|
+
*
|
1107
|
+
* @primaryGroupingSize [Number]
|
1108
|
+
*
|
1109
|
+
* @secondaryGroupingSize [Number]
|
1110
|
+
*
|
1111
|
+
* Return the formatted number with group separator.
|
1112
|
+
*/
|
1113
|
+
var numberFormatGroupingSeparator = function( number, primaryGroupingSize, secondaryGroupingSize ) {
|
1114
|
+
var index,
|
1115
|
+
currentGroupingSize = primaryGroupingSize,
|
1116
|
+
ret = "",
|
1117
|
+
sep = ",",
|
1118
|
+
switchToSecondary = secondaryGroupingSize ? true : false;
|
1119
|
+
|
1120
|
+
number = String( number ).split( "." );
|
1121
|
+
index = number[ 0 ].length;
|
1122
|
+
|
1123
|
+
while ( index > currentGroupingSize ) {
|
1124
|
+
ret = number[ 0 ].slice( index - currentGroupingSize, index ) +
|
1125
|
+
( ret.length ? sep : "" ) + ret;
|
1126
|
+
index -= currentGroupingSize;
|
1127
|
+
if ( switchToSecondary ) {
|
1128
|
+
currentGroupingSize = secondaryGroupingSize;
|
1129
|
+
switchToSecondary = false;
|
1130
|
+
}
|
1131
|
+
}
|
1132
|
+
|
1133
|
+
number[ 0 ] = number[ 0 ].slice( 0, index ) + ( ret.length ? sep : "" ) + ret;
|
1134
|
+
return number.join( "." );
|
1135
|
+
};
|
1136
|
+
|
1137
|
+
|
1138
|
+
|
1139
|
+
|
1140
|
+
/**
|
1141
|
+
* integerFractionDigits( number, minimumIntegerDigits, minimumFractionDigits,
|
1142
|
+
* maximumFractionDigits, round, roundIncrement )
|
1143
|
+
*
|
1144
|
+
* @number [Number]
|
1145
|
+
*
|
1146
|
+
* @minimumIntegerDigits [Number]
|
1147
|
+
*
|
1148
|
+
* @minimumFractionDigits [Number]
|
1149
|
+
*
|
1150
|
+
* @maximumFractionDigits [Number]
|
1151
|
+
*
|
1152
|
+
* @round [Function]
|
1153
|
+
*
|
1154
|
+
* @roundIncrement [Function]
|
1155
|
+
*
|
1156
|
+
* Return the formatted integer and fraction digits.
|
1157
|
+
*/
|
1158
|
+
var numberFormatIntegerFractionDigits = function( number, minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, round,
|
1159
|
+
roundIncrement ) {
|
1160
|
+
|
1161
|
+
// Fraction
|
1162
|
+
if ( maximumFractionDigits ) {
|
1163
|
+
|
1164
|
+
// Rounding
|
1165
|
+
if ( roundIncrement ) {
|
1166
|
+
number = round( number, roundIncrement );
|
1167
|
+
|
1168
|
+
// Maximum fraction digits
|
1169
|
+
} else {
|
1170
|
+
number = round( number, { exponent: -maximumFractionDigits } );
|
1171
|
+
}
|
1172
|
+
|
1173
|
+
} else {
|
1174
|
+
number = round( number );
|
1175
|
+
}
|
1176
|
+
|
1177
|
+
number = String( number );
|
1178
|
+
|
1179
|
+
// Maximum integer digits (post string phase)
|
1180
|
+
if ( maximumFractionDigits && /e-/.test( number ) ) {
|
1181
|
+
|
1182
|
+
// Use toFixed( maximumFractionDigits ) to make sure small numbers like 1e-7 are
|
1183
|
+
// displayed using plain digits instead of scientific notation.
|
1184
|
+
// 1: Remove leading decimal zeros.
|
1185
|
+
// 2: Remove leading decimal separator.
|
1186
|
+
// Note: String() is still preferred so it doesn't mess up with a number precision
|
1187
|
+
// unnecessarily, e.g., (123456789.123).toFixed(10) === "123456789.1229999959",
|
1188
|
+
// String(123456789.123) === "123456789.123".
|
1189
|
+
number = ( +number ).toFixed( maximumFractionDigits )
|
1190
|
+
.replace( /0+$/, "" ) /* 1 */
|
1191
|
+
.replace( /\.$/, "" ); /* 2 */
|
1192
|
+
}
|
1193
|
+
|
1194
|
+
// Minimum fraction digits (post string phase)
|
1195
|
+
if ( minimumFractionDigits ) {
|
1196
|
+
number = number.split( "." );
|
1197
|
+
number[ 1 ] = stringPad( number[ 1 ] || "", minimumFractionDigits, true );
|
1198
|
+
number = number.join( "." );
|
1199
|
+
}
|
1200
|
+
|
1201
|
+
// Minimum integer digits
|
1202
|
+
if ( minimumIntegerDigits ) {
|
1203
|
+
number = number.split( "." );
|
1204
|
+
number[ 0 ] = stringPad( number[ 0 ], minimumIntegerDigits );
|
1205
|
+
number = number.join( "." );
|
1206
|
+
}
|
1207
|
+
|
1208
|
+
return number;
|
1209
|
+
};
|
1210
|
+
|
1211
|
+
|
1212
|
+
|
1213
|
+
|
1214
|
+
/**
|
1215
|
+
* toPrecision( number, precision, round )
|
1216
|
+
*
|
1217
|
+
* @number (Number)
|
1218
|
+
*
|
1219
|
+
* @precision (Number) significant figures precision (not decimal precision).
|
1220
|
+
*
|
1221
|
+
* @round (Function)
|
1222
|
+
*
|
1223
|
+
* Return number.toPrecision( precision ) using the given round function.
|
1224
|
+
*/
|
1225
|
+
var numberToPrecision = function( number, precision, round ) {
|
1226
|
+
var roundOrder;
|
1227
|
+
|
1228
|
+
if ( number === 0 ) { // Fix #706
|
1229
|
+
return number;
|
1230
|
+
}
|
1231
|
+
|
1232
|
+
roundOrder = Math.ceil( Math.log( Math.abs( number ) ) / Math.log( 10 ) );
|
1233
|
+
roundOrder -= precision;
|
1234
|
+
|
1235
|
+
return round( number, { exponent: roundOrder } );
|
1236
|
+
};
|
1237
|
+
|
1238
|
+
|
1239
|
+
|
1240
|
+
|
1241
|
+
/**
|
1242
|
+
* toPrecision( number, minimumSignificantDigits, maximumSignificantDigits, round )
|
1243
|
+
*
|
1244
|
+
* @number [Number]
|
1245
|
+
*
|
1246
|
+
* @minimumSignificantDigits [Number]
|
1247
|
+
*
|
1248
|
+
* @maximumSignificantDigits [Number]
|
1249
|
+
*
|
1250
|
+
* @round [Function]
|
1251
|
+
*
|
1252
|
+
* Return the formatted significant digits number.
|
1253
|
+
*/
|
1254
|
+
var numberFormatSignificantDigits = function( number, minimumSignificantDigits, maximumSignificantDigits, round ) {
|
1255
|
+
var atMinimum, atMaximum;
|
1256
|
+
|
1257
|
+
// Sanity check.
|
1258
|
+
if ( minimumSignificantDigits > maximumSignificantDigits ) {
|
1259
|
+
maximumSignificantDigits = minimumSignificantDigits;
|
1260
|
+
}
|
1261
|
+
|
1262
|
+
atMinimum = numberToPrecision( number, minimumSignificantDigits, round );
|
1263
|
+
atMaximum = numberToPrecision( number, maximumSignificantDigits, round );
|
1264
|
+
|
1265
|
+
// Use atMaximum only if it has more significant digits than atMinimum.
|
1266
|
+
number = +atMinimum === +atMaximum ? atMinimum : atMaximum;
|
1267
|
+
|
1268
|
+
// Expand integer numbers, eg. 123e5 to 12300.
|
1269
|
+
number = ( +number ).toString( 10 );
|
1270
|
+
|
1271
|
+
if ( ( /e/ ).test( number ) ) {
|
1272
|
+
throw createErrorUnsupportedFeature({
|
1273
|
+
feature: "integers out of (1e21, 1e-7)"
|
1274
|
+
});
|
1275
|
+
}
|
1276
|
+
|
1277
|
+
// Add trailing zeros if necessary.
|
1278
|
+
if ( minimumSignificantDigits - number.replace( /^0+|\./g, "" ).length > 0 ) {
|
1279
|
+
number = number.split( "." );
|
1280
|
+
number[ 1 ] = stringPad( number[ 1 ] || "", minimumSignificantDigits - number[ 0 ].replace( /^0+/, "" ).length, true );
|
1281
|
+
number = number.join( "." );
|
1282
|
+
}
|
1283
|
+
|
1284
|
+
return number;
|
1285
|
+
};
|
1286
|
+
|
1287
|
+
|
1288
|
+
|
1289
|
+
|
1290
|
+
/**
|
1291
|
+
* format( number, properties )
|
1292
|
+
*
|
1293
|
+
* @number [Number].
|
1294
|
+
*
|
1295
|
+
* @properties [Object] Output of number/format-properties.
|
1296
|
+
*
|
1297
|
+
* Return the formatted number.
|
1298
|
+
* ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
|
1299
|
+
*/
|
1300
|
+
var numberFormat = function( number, properties, pluralGenerator ) {
|
1301
|
+
var aux, compactMap, infinitySymbol, maximumFractionDigits, maximumSignificantDigits,
|
1302
|
+
minimumFractionDigits, minimumIntegerDigits, minimumSignificantDigits, nanSymbol,
|
1303
|
+
nuDigitsMap, prefix, primaryGroupingSize, pattern, round, roundIncrement,
|
1304
|
+
secondaryGroupingSize, stringToParts, suffix, symbolMap;
|
1305
|
+
|
1306
|
+
minimumIntegerDigits = properties[ 2 ];
|
1307
|
+
minimumFractionDigits = properties[ 3 ];
|
1308
|
+
maximumFractionDigits = properties[ 4 ];
|
1309
|
+
minimumSignificantDigits = properties[ 5 ];
|
1310
|
+
maximumSignificantDigits = properties[ 6 ];
|
1311
|
+
roundIncrement = properties[ 7 ];
|
1312
|
+
primaryGroupingSize = properties[ 8 ];
|
1313
|
+
secondaryGroupingSize = properties[ 9 ];
|
1314
|
+
round = properties[ 15 ];
|
1315
|
+
infinitySymbol = properties[ 16 ];
|
1316
|
+
nanSymbol = properties[ 17 ];
|
1317
|
+
symbolMap = properties[ 18 ];
|
1318
|
+
nuDigitsMap = properties[ 19 ];
|
1319
|
+
compactMap = properties[ 20 ];
|
1320
|
+
|
1321
|
+
// NaN
|
1322
|
+
if ( isNaN( number ) ) {
|
1323
|
+
return [ { type: "nan", value: nanSymbol } ];
|
1324
|
+
}
|
1325
|
+
|
1326
|
+
if ( number < 0 ) {
|
1327
|
+
pattern = properties[ 12 ];
|
1328
|
+
prefix = properties[ 13 ];
|
1329
|
+
suffix = properties[ 14 ];
|
1330
|
+
} else {
|
1331
|
+
pattern = properties[ 11 ];
|
1332
|
+
prefix = properties[ 0 ];
|
1333
|
+
suffix = properties[ 10 ];
|
1334
|
+
}
|
1335
|
+
|
1336
|
+
// For prefix, suffix, and number parts.
|
1337
|
+
stringToParts = function( string ) {
|
1338
|
+
var numberType = "integer",
|
1339
|
+
parts = [];
|
1340
|
+
|
1341
|
+
// TODO Move the tokenization of all parts that don't depend on number into
|
1342
|
+
// format-properties.
|
1343
|
+
string.replace( /('([^']|'')+'|'')|./g, function( character, literal ) {
|
1344
|
+
|
1345
|
+
// Literals
|
1346
|
+
if ( literal ) {
|
1347
|
+
partsPush( parts, "literal", removeLiteralQuotes( literal ) );
|
1348
|
+
return;
|
1349
|
+
}
|
1350
|
+
|
1351
|
+
// Currency symbol
|
1352
|
+
if ( character === "\u00A4" ) {
|
1353
|
+
partsPush( parts, "currency", character );
|
1354
|
+
return;
|
1355
|
+
}
|
1356
|
+
|
1357
|
+
// Symbols
|
1358
|
+
character = character.replace( /[.,\-+E%\u2030]/, function( symbol ) {
|
1359
|
+
if ( symbol === "." ) {
|
1360
|
+
numberType = "fraction";
|
1361
|
+
}
|
1362
|
+
partsPush( parts, numberSymbolName[ symbol ], symbolMap[ symbol ] );
|
1363
|
+
|
1364
|
+
// "Erase" handled character.
|
1365
|
+
return "";
|
1366
|
+
});
|
1367
|
+
|
1368
|
+
// Number
|
1369
|
+
character = character.replace( /[0-9]/, function( digit ) {
|
1370
|
+
|
1371
|
+
// Numbering system
|
1372
|
+
if ( nuDigitsMap ) {
|
1373
|
+
digit = nuDigitsMap[ +digit ];
|
1374
|
+
}
|
1375
|
+
partsPush( parts, numberType, digit );
|
1376
|
+
|
1377
|
+
// "Erase" handled character.
|
1378
|
+
return "";
|
1379
|
+
});
|
1380
|
+
|
1381
|
+
// Etc
|
1382
|
+
character.replace( /./, function( etc ) {
|
1383
|
+
partsPush( parts, "literal", etc );
|
1384
|
+
});
|
1385
|
+
});
|
1386
|
+
return parts;
|
1387
|
+
};
|
1388
|
+
|
1389
|
+
prefix = stringToParts( prefix );
|
1390
|
+
suffix = stringToParts( suffix );
|
1391
|
+
|
1392
|
+
// Infinity
|
1393
|
+
if ( !isFinite( number ) ) {
|
1394
|
+
return prefix.concat(
|
1395
|
+
{ type: "infinity", value: infinitySymbol },
|
1396
|
+
suffix
|
1397
|
+
);
|
1398
|
+
}
|
1399
|
+
|
1400
|
+
// Percent
|
1401
|
+
if ( pattern.indexOf( "%" ) !== -1 ) {
|
1402
|
+
number *= 100;
|
1403
|
+
|
1404
|
+
// Per mille
|
1405
|
+
} else if ( pattern.indexOf( "\u2030" ) !== -1 ) {
|
1406
|
+
number *= 1000;
|
1407
|
+
}
|
1408
|
+
|
1409
|
+
var compactPattern, compactDigits, compactProperties, divisor, numberExponent, pluralForm;
|
1410
|
+
|
1411
|
+
// Compact mode: initial number digit processing
|
1412
|
+
if ( compactMap ) {
|
1413
|
+
numberExponent = Math.abs( Math.floor( number ) ).toString().length - 1;
|
1414
|
+
numberExponent = Math.min( numberExponent, compactMap.maxExponent );
|
1415
|
+
|
1416
|
+
// Use default plural form to perform initial decimal shift
|
1417
|
+
if ( numberExponent >= 3 ) {
|
1418
|
+
compactPattern = compactMap[ numberExponent ] && compactMap[ numberExponent ].other;
|
1419
|
+
}
|
1420
|
+
|
1421
|
+
if ( compactPattern === "0" ) {
|
1422
|
+
compactPattern = null;
|
1423
|
+
} else if ( compactPattern ) {
|
1424
|
+
compactDigits = compactPattern.split( "0" ).length - 1;
|
1425
|
+
divisor = numberExponent - ( compactDigits - 1 );
|
1426
|
+
number = number / Math.pow( 10, divisor );
|
1427
|
+
}
|
1428
|
+
}
|
1429
|
+
|
1430
|
+
// Significant digit format
|
1431
|
+
if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) ) {
|
1432
|
+
number = numberFormatSignificantDigits( number, minimumSignificantDigits,
|
1433
|
+
maximumSignificantDigits, round );
|
1434
|
+
|
1435
|
+
// Integer and fractional format
|
1436
|
+
} else {
|
1437
|
+
number = numberFormatIntegerFractionDigits( number, minimumIntegerDigits,
|
1438
|
+
minimumFractionDigits, maximumFractionDigits, round, roundIncrement );
|
1439
|
+
}
|
1440
|
+
|
1441
|
+
// Compact mode: apply formatting
|
1442
|
+
if ( compactMap && compactPattern ) {
|
1443
|
+
|
1444
|
+
// Get plural form after possible roundings
|
1445
|
+
pluralForm = pluralGenerator ? pluralGenerator( +number ) : "other";
|
1446
|
+
|
1447
|
+
compactPattern = compactMap[ numberExponent ][ pluralForm ] || compactPattern;
|
1448
|
+
compactProperties = compactPattern.match( numberCompactPatternRe );
|
1449
|
+
|
1450
|
+
// TODO Move the tokenization of all parts that don't depend on number into
|
1451
|
+
// format-properties.
|
1452
|
+
aux = function( string ) {
|
1453
|
+
var parts = [];
|
1454
|
+
string.replace( /(\s+)|([^\s0]+)/g, function( _garbage, space, compact ) {
|
1455
|
+
|
1456
|
+
// Literals
|
1457
|
+
if ( space ) {
|
1458
|
+
partsPush( parts, "literal", space );
|
1459
|
+
return;
|
1460
|
+
}
|
1461
|
+
|
1462
|
+
// Compact value
|
1463
|
+
if ( compact ) {
|
1464
|
+
partsPush( parts, "compact", compact );
|
1465
|
+
return;
|
1466
|
+
}
|
1467
|
+
});
|
1468
|
+
return parts;
|
1469
|
+
};
|
1470
|
+
|
1471
|
+
// update prefix/suffix with compact prefix/suffix
|
1472
|
+
prefix = prefix.concat( aux( compactProperties[ 1 ] ) );
|
1473
|
+
suffix = aux( compactProperties[ 3 ] ).concat( suffix );
|
1474
|
+
}
|
1475
|
+
|
1476
|
+
// Remove the possible number minus sign
|
1477
|
+
number = number.replace( /^-/, "" );
|
1478
|
+
|
1479
|
+
// Grouping separators
|
1480
|
+
if ( primaryGroupingSize ) {
|
1481
|
+
number = numberFormatGroupingSeparator( number, primaryGroupingSize,
|
1482
|
+
secondaryGroupingSize );
|
1483
|
+
}
|
1484
|
+
|
1485
|
+
// Scientific notation
|
1486
|
+
// TODO implement here
|
1487
|
+
|
1488
|
+
// Padding/'([^']|'')+'|''|[.,\-+E%\u2030]/g
|
1489
|
+
// TODO implement here
|
1490
|
+
|
1491
|
+
return prefix.concat(
|
1492
|
+
stringToParts( number ),
|
1493
|
+
suffix
|
1494
|
+
);
|
1495
|
+
};
|
1496
|
+
|
1497
|
+
|
1498
|
+
|
1499
|
+
|
1500
|
+
var numberToPartsFormatterFn = function( properties, pluralGenerator ) {
|
1501
|
+
return function numberToPartsFormatter( value ) {
|
1502
|
+
validateParameterPresence( value, "value" );
|
1503
|
+
validateParameterTypeNumber( value, "value" );
|
1504
|
+
|
1505
|
+
return numberFormat( value, properties, pluralGenerator );
|
1506
|
+
};
|
1507
|
+
};
|
1508
|
+
|
1509
|
+
|
1510
|
+
|
1511
|
+
|
1512
|
+
function validateDigits( properties ) {
|
1513
|
+
var minimumIntegerDigits = properties[ 2 ],
|
1514
|
+
minimumFractionDigits = properties[ 3 ],
|
1515
|
+
maximumFractionDigits = properties[ 4 ],
|
1516
|
+
minimumSignificantDigits = properties[ 5 ],
|
1517
|
+
maximumSignificantDigits = properties[ 6 ];
|
1518
|
+
|
1519
|
+
// Validate significant digit format properties
|
1520
|
+
if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) ) {
|
1521
|
+
validateParameterRange( minimumSignificantDigits, "minimumSignificantDigits", 1, 21 );
|
1522
|
+
validateParameterRange( maximumSignificantDigits, "maximumSignificantDigits",
|
1523
|
+
minimumSignificantDigits, 21 );
|
1524
|
+
|
1525
|
+
} else if ( !isNaN( minimumSignificantDigits ) || !isNaN( maximumSignificantDigits ) ) {
|
1526
|
+
throw new Error( "Neither or both the minimum and maximum significant digits must be " +
|
1527
|
+
"present" );
|
1528
|
+
|
1529
|
+
// Validate integer and fractional format
|
1530
|
+
} else {
|
1531
|
+
validateParameterRange( minimumIntegerDigits, "minimumIntegerDigits", 1, 21 );
|
1532
|
+
validateParameterRange( minimumFractionDigits, "minimumFractionDigits", 0, 20 );
|
1533
|
+
validateParameterRange( maximumFractionDigits, "maximumFractionDigits",
|
1534
|
+
minimumFractionDigits, 20 );
|
1535
|
+
}
|
1536
|
+
}
|
1537
|
+
|
1538
|
+
/**
|
1539
|
+
* .numberFormatter( [options] )
|
1540
|
+
*
|
1541
|
+
* @options [Object]:
|
1542
|
+
* - style: [String] "decimal" (default) or "percent".
|
1543
|
+
* - see also number/format options.
|
1544
|
+
*
|
1545
|
+
* Return a function that formats a number according to the given options and default/instance
|
1546
|
+
* locale.
|
1547
|
+
*/
|
1548
|
+
Globalize.numberFormatter =
|
1549
|
+
Globalize.prototype.numberFormatter = function( options ) {
|
1550
|
+
var args, numberToPartsFormatter, returnFn;
|
1551
|
+
|
1552
|
+
validateParameterTypePlainObject( options, "options" );
|
1553
|
+
|
1554
|
+
options = options || {};
|
1555
|
+
args = [ options ];
|
1556
|
+
|
1557
|
+
numberToPartsFormatter = this.numberToPartsFormatter( options );
|
1558
|
+
returnFn = numberFormatterFn( numberToPartsFormatter );
|
1559
|
+
runtimeBind( args, this.cldr, returnFn, [ numberToPartsFormatter ] );
|
1560
|
+
|
1561
|
+
return returnFn;
|
1562
|
+
};
|
1563
|
+
|
1564
|
+
/**
|
1565
|
+
* .numberToPartsFormatter( [options] )
|
1566
|
+
*
|
1567
|
+
* @options [Object]:
|
1568
|
+
* - style: [String] "symbol" (default), "accounting", "code" or "name".
|
1569
|
+
* - see also number/format options.
|
1570
|
+
*
|
1571
|
+
* Return a function that formats a number to parts according to the given options and
|
1572
|
+
* default/instance locale.
|
1573
|
+
*/
|
1574
|
+
Globalize.numberToPartsFormatter =
|
1575
|
+
Globalize.prototype.numberToPartsFormatter = function( options ) {
|
1576
|
+
var args, cldr, fnArgs, pattern, properties, returnFn;
|
1577
|
+
|
1578
|
+
validateParameterTypePlainObject( options, "options" );
|
1579
|
+
|
1580
|
+
options = options || {};
|
1581
|
+
cldr = this.cldr;
|
1582
|
+
|
1583
|
+
args = [ options ];
|
1584
|
+
|
1585
|
+
validateDefaultLocale( cldr );
|
1586
|
+
|
1587
|
+
cldr.on( "get", validateCldr );
|
1588
|
+
try {
|
1589
|
+
if ( options.raw ) {
|
1590
|
+
pattern = options.raw;
|
1591
|
+
} else {
|
1592
|
+
pattern = numberPattern( options.style || "decimal", cldr );
|
1593
|
+
}
|
1594
|
+
|
1595
|
+
properties = numberFormatProperties( pattern, cldr, options );
|
1596
|
+
fnArgs = [ properties ];
|
1597
|
+
} finally {
|
1598
|
+
cldr.off( "get", validateCldr );
|
1599
|
+
}
|
1600
|
+
|
1601
|
+
validateDigits( properties );
|
1602
|
+
|
1603
|
+
if ( options.compact ) {
|
1604
|
+
fnArgs.push( this.pluralGenerator() );
|
1605
|
+
}
|
1606
|
+
returnFn = numberToPartsFormatterFn.apply( null, fnArgs );
|
1607
|
+
runtimeBind( args, cldr, returnFn, fnArgs );
|
1608
|
+
|
1609
|
+
return returnFn;
|
1610
|
+
};
|
1611
|
+
|
1612
|
+
/**
|
1613
|
+
* .numberParser( [options] )
|
1614
|
+
*
|
1615
|
+
* @options [Object]:
|
1616
|
+
* - style: [String] "decimal" (default) or "percent".
|
1617
|
+
*
|
1618
|
+
* Return the number parser according to the default/instance locale.
|
1619
|
+
*/
|
1620
|
+
Globalize.numberParser =
|
1621
|
+
Globalize.prototype.numberParser = function( options ) {
|
1622
|
+
var args, cldr, pattern, properties, returnFn;
|
1623
|
+
|
1624
|
+
validateParameterTypePlainObject( options, "options" );
|
1625
|
+
|
1626
|
+
options = options || {};
|
1627
|
+
cldr = this.cldr;
|
1628
|
+
|
1629
|
+
args = [ options ];
|
1630
|
+
|
1631
|
+
validateDefaultLocale( cldr );
|
1632
|
+
if ( options.compact ) {
|
1633
|
+
throw createErrorUnsupportedFeature({
|
1634
|
+
feature: "compact number parsing (not implemented)"
|
1635
|
+
});
|
1636
|
+
}
|
1637
|
+
|
1638
|
+
cldr.on( "get", validateCldr );
|
1639
|
+
|
1640
|
+
if ( options.raw ) {
|
1641
|
+
pattern = options.raw;
|
1642
|
+
} else {
|
1643
|
+
pattern = numberPattern( options.style || "decimal", cldr );
|
1644
|
+
}
|
1645
|
+
|
1646
|
+
properties = numberParseProperties( pattern, cldr, options );
|
1647
|
+
|
1648
|
+
cldr.off( "get", validateCldr );
|
1649
|
+
|
1650
|
+
returnFn = numberParserFn( properties );
|
1651
|
+
|
1652
|
+
runtimeBind( args, cldr, returnFn, [ properties ] );
|
1653
|
+
|
1654
|
+
return returnFn;
|
1655
|
+
};
|
1656
|
+
|
1657
|
+
/**
|
1658
|
+
* .formatNumber( value [, options] )
|
1659
|
+
*
|
1660
|
+
* @value [Number] number to be formatted.
|
1661
|
+
*
|
1662
|
+
* @options [Object]: see number/format-properties.
|
1663
|
+
*
|
1664
|
+
* Format a number according to the given options and default/instance locale.
|
1665
|
+
*/
|
1666
|
+
Globalize.formatNumber =
|
1667
|
+
Globalize.prototype.formatNumber = function( value, options ) {
|
1668
|
+
validateParameterPresence( value, "value" );
|
1669
|
+
validateParameterTypeNumber( value, "value" );
|
1670
|
+
|
1671
|
+
return this.numberFormatter( options )( value );
|
1672
|
+
};
|
1673
|
+
|
1674
|
+
/**
|
1675
|
+
* .formatNumberToParts( value [, options] )
|
1676
|
+
*
|
1677
|
+
* @value [Number] number to be formatted.
|
1678
|
+
*
|
1679
|
+
* @options [Object]: see number/format-properties.
|
1680
|
+
*
|
1681
|
+
* Format a number to pars according to the given options and default/instance locale.
|
1682
|
+
*/
|
1683
|
+
Globalize.formatNumberToParts =
|
1684
|
+
Globalize.prototype.formatNumberToParts = function( value, options ) {
|
1685
|
+
validateParameterPresence( value, "value" );
|
1686
|
+
validateParameterTypeNumber( value, "value" );
|
1687
|
+
|
1688
|
+
return this.numberToPartsFormatter( options )( value );
|
1689
|
+
};
|
1690
|
+
|
1691
|
+
/**
|
1692
|
+
* .parseNumber( value [, options] )
|
1693
|
+
*
|
1694
|
+
* @value [String]
|
1695
|
+
*
|
1696
|
+
* @options [Object]: See numberParser().
|
1697
|
+
*
|
1698
|
+
* Return the parsed Number (including Infinity) or NaN when value is invalid.
|
1699
|
+
*/
|
1700
|
+
Globalize.parseNumber =
|
1701
|
+
Globalize.prototype.parseNumber = function( value, options ) {
|
1702
|
+
validateParameterPresence( value, "value" );
|
1703
|
+
validateParameterTypeString( value, "value" );
|
1704
|
+
|
1705
|
+
return this.numberParser( options )( value );
|
1706
|
+
};
|
1707
|
+
|
1708
|
+
/**
|
1709
|
+
* Optimization to avoid duplicating some internal functions across modules.
|
1710
|
+
*/
|
1711
|
+
Globalize._createErrorUnsupportedFeature = createErrorUnsupportedFeature;
|
1712
|
+
Globalize._numberNumberingSystem = numberNumberingSystem;
|
1713
|
+
Globalize._numberNumberingSystemDigitsMap = numberNumberingSystemDigitsMap;
|
1714
|
+
Globalize._numberPattern = numberPattern;
|
1715
|
+
Globalize._numberSymbol = numberSymbol;
|
1716
|
+
Globalize._looseMatching = looseMatching;
|
1717
|
+
Globalize._removeLiteralQuotes = removeLiteralQuotes;
|
1718
|
+
Globalize._stringPad = stringPad;
|
1719
|
+
Globalize._validateParameterTypeNumber = validateParameterTypeNumber;
|
1720
|
+
Globalize._validateParameterTypeString = validateParameterTypeString;
|
1721
|
+
|
1722
|
+
return Globalize;
|
1723
|
+
|
1724
|
+
|
1725
|
+
|
1726
|
+
|
1727
|
+
}));
|