Skip to content

Commit 14b358e

Browse files
committed
Number: Add support for compact option (short/long) (2/2)
1 parent 6d0e5a0 commit 14b358e

File tree

8 files changed

+330
-172
lines changed

8 files changed

+330
-172
lines changed

doc/api/currency/currency-formatter.md

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Number to be formatted, eg. `9.99`.
2020

2121
### Example
2222

23+
#### Static Formatter
24+
2325
Prior to using any currency methods, you must load `cldr/main/{locale}/currencies.json`, `cldr/supplemental/currencyData.json`, and the CLDR content required by the number module. If using plural messages, you also must load the CLDR content required by the plural module. Read [CLDR content][] if you need more information.
2426

2527
[CLDR content]: ../../../README.md#2-cldr-content
@@ -37,6 +39,8 @@ formatter( 9.99 );
3739

3840
```
3941

42+
#### Instance Formatter
43+
4044
You can use the instance method `.currencyFormatter()`, which uses the instance locale.
4145

4246
```javascript
@@ -62,6 +66,8 @@ For comparison, follow the formatting output of different symbols in different l
6266
| `.currencyFormatter( "GBP" )( 1 )` | `£1.00` | `1,00 £` | `£ 1.00` |
6367
| `.currencyFormatter( "BRL" )( 1 )` | `R$1.00` | `1,00 R$` | `R$ 1.00` |
6468

69+
#### Configuring style
70+
6571
For the accounting variation of the symbol format, use `style: "accounting"`.
6672

6773
```javascript
@@ -109,6 +115,8 @@ formatter( 9.99 );
109115
// > "9.99 USD"
110116
```
111117

118+
#### Configuring inherited number options
119+
112120
Override the number of digits, grouping separators, rounding function or any other [`.numberFormatter()` options](../number/number-formatter.md).
113121

114122
```javascript
@@ -129,16 +137,39 @@ formatter = Globalize.currencyFormatter( "USD", {
129137

130138
formatter( 1.491 );
131139
// > "$1.50"
140+
```
132141

133-
formatter = Globalize.currencyFormatter( "USD", {
134-
maximumFractionDigits: 0,
142+
#### Formatting Compact Currencies
143+
144+
```js
145+
var shortFormatter = Globalize( "en" ).currencyFormatter( "USD", {
135146
compact: "short"
136147
});
137148

138-
formatter( 12830000000 );
149+
var longFormatter = Globalize( "en" ).currencyFormatter( "USD", {
150+
compact: "long"
151+
});
152+
153+
shortFormatter( 12830000000 );
139154
// > "$13B"
155+
156+
longFormatter( 12830000000 );
157+
// > "$13 billion"
140158
```
141159

160+
The minimumSignificantDigits and maximumSignificantDigits options are specially useful to control the number of digits to display.
161+
162+
```js
163+
Globalize( "en" ).formatCurrency( 12830000000, "USD", {
164+
compact: "short",
165+
minimumSignificantDigits: 3,
166+
maximumSignificantDigits: 3
167+
});
168+
// > "$12.8B"
169+
```
170+
171+
#### Performance Suggestion
172+
142173
For improved performance on iterations, first create the formatter. Then, reuse it on each loop.
143174

144175
```javascript

doc/api/number/number-formatter.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,11 @@ Long numbers can be represented in a compact format, with `short` using abbrevia
149149

150150
```javascript
151151
var shortFormatter = Globalize( "en" ).numberFormatter({
152-
compact: "short",
153-
maximumFractionDigits: 0,
154-
style: "decimal"
152+
compact: "short"
155153
});
156154

157155
var longFormatter = Globalize( "en" ).numberFormatter({
158-
compact: "long",
159-
maximumFractionDigits: 0,
160-
style: "decimal"
156+
compact: "long"
161157
});
162158

163159
shortFormatter( 27588910 );
@@ -167,6 +163,17 @@ longFormatter( 27588910 );
167163
// > "28 million"
168164
```
169165

166+
The minimumSignificantDigits and maximumSignificantDigits options are specially useful to control the number of digits to display.
167+
168+
```js
169+
Globalize( "en" ).formatNumber( 27588910, {
170+
compact: "short",
171+
minimumSignificantDigits: 3,
172+
maximumSignificantDigits: 3
173+
});
174+
// > "27.6M"
175+
```
176+
170177
#### Configuring Rounding
171178

172179
Numbers with a decreased amount of decimal places can be rounded up, rounded down, rounded arithmetically, or truncated by setting the `round` option to `ceil`, `floor`, `round` (default), or `truncate`.

src/number/compact-pattern-re.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
define(function() {
2+
3+
/**
4+
* EBNF representation:
5+
*
6+
* compact_pattern_re = prefix?
7+
* number_pattern_re
8+
* suffix?
9+
*
10+
* number_pattern_re = 0+
11+
*
12+
* Regexp groups:
13+
*
14+
* 0: compact_pattern_re
15+
* 1: prefix
16+
* 2: number_pattern_re (the number pattern to use in compact mode)
17+
* 3: suffix
18+
*/
19+
return ( /^([^0]*)(0+)([^0]*)$/ );
20+
21+
});

src/number/compact.js

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
define([
2-
"./numbering-system"
2+
"./numbering-system"
33
], function( numberNumberingSystem ) {
44

55
/**
@@ -12,11 +12,26 @@ define([
1212
* Return the localized compact map for the given compact mode.
1313
*/
1414
return function( compactType, cldr ) {
15-
return cldr.main([
16-
"numbers/decimalFormats-numberSystem-" + numberNumberingSystem( cldr ),
17-
compactType,
18-
"decimalFormat"
19-
]);
15+
var maxExponent = 0;
16+
17+
var object = cldr.main([
18+
"numbers/decimalFormats-numberSystem-" + numberNumberingSystem( cldr ),
19+
compactType,
20+
"decimalFormat"
21+
]);
22+
23+
object = Object.keys( object ).reduce(function( newObject, compactKey ) {
24+
var numberExponent = compactKey.split( "0" ).length - 1;
25+
var pluralForm = compactKey.split( "-" )[ 2 ];
26+
newObject[ numberExponent ] = newObject[ numberExponent ] || {};
27+
newObject[ numberExponent ][ pluralForm ] = object[ compactKey ];
28+
maxExponent = Math.max( numberExponent, maxExponent );
29+
return newObject;
30+
}, {});
31+
32+
object.maxExponent = maxExponent;
33+
34+
return object;
2035
};
2136

2237
});

src/number/format-properties.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ return function( pattern, cldr, options ) {
6565
]);
6666

6767
if ( options.compact ) {
68+
69+
// The compact digits number pattern is always `0+`, so override the following properties.
70+
// Note: minimumIntegerDigits would actually range from `0` to `000` based on the scale of
71+
// the value to be formatted, though we're always using 1 as a simplification, because the
72+
// number won't be zero-padded since we chose the right format based on the scale, i.e.,
73+
// we'd never see something like `003M` anyway.
74+
properties[ 2 ] = negativeSuffix[ 2 ] = 1; // minimumIntegerDigits
75+
properties[ 3 ] = negativeSuffix[ 3 ] = 0; // minimumFractionDigits
76+
properties[ 4 ] = negativeSuffix[ 4 ] = 0; // maximumFractionDigits
77+
properties[ 5 ] = negativeSuffix[ 5 ] = // minimumSignificantDigits &
78+
properties[ 6 ] = negativeSuffix[ 6 ] = undefined ; // maximumSignificantDigits
79+
6880
properties[20] = numberCompact( options.compact, cldr );
6981
}
7082

src/number/format.js

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
define([
2+
"./compact-pattern-re",
23
"./format/grouping-separator",
34
"./format/integer-fraction-digits",
45
"./format/significant-digits",
56
"./pattern-re",
67
"../util/remove-literal-quotes"
7-
], function( numberFormatGroupingSeparator, numberFormatIntegerFractionDigits,
8-
numberFormatSignificantDigits, numberPatternRe, removeLiteralQuotes ) {
8+
], function( numberCompactPatternRe, numberFormatGroupingSeparator,
9+
numberFormatIntegerFractionDigits, numberFormatSignificantDigits, numberPatternRe,
10+
removeLiteralQuotes ) {
911

1012
/**
1113
* format( number, properties )
@@ -68,29 +70,24 @@ return function( number, properties, pluralGenerator ) {
6870
number *= 1000;
6971
}
7072

71-
var compactPattern, compactDigits, compactProperties, divisor, pluralForm, zeroes,
72-
originalNumber;
73+
var compactPattern, compactDigits, compactProperties, divisor, numberExponent, pluralForm;
7374

7475
// Compact mode: initial number digit processing
7576
if ( compactMap ) {
76-
originalNumber = number;
77-
zeroes = Array( Math.floor( number ).toString().length ).join( "0" );
78-
if ( zeroes.length >= 3 ) {
79-
80-
// use default plural form to perform initial decimal shift
81-
compactPattern = compactMap[ "1" + zeroes + "-count-other" ];
82-
83-
if ( compactPattern ) {
84-
compactDigits = compactPattern.split( "0" ).length - 1;
85-
divisor = zeroes.length - ( compactDigits - 1 );
86-
number = number / Math.pow( 10, divisor );
87-
88-
// Some languages specify no pattern for certain digit lengths, represented as "0".
89-
// If no pattern, original number should remain uncompacted.
90-
if ( compactPattern === "0" ) {
91-
number = originalNumber;
92-
}
93-
}
77+
numberExponent = Math.floor( number ).toString().length - 1;
78+
numberExponent = Math.min( numberExponent, compactMap.maxExponent );
79+
80+
// Use default plural form to perform initial decimal shift
81+
if ( numberExponent >= 3 ) {
82+
compactPattern = compactMap[ numberExponent ] && compactMap[ numberExponent ].other;
83+
}
84+
85+
if ( compactPattern === "0" ) {
86+
compactPattern = null;
87+
} else if ( compactPattern ) {
88+
compactDigits = compactPattern.split( "0" ).length - 1;
89+
divisor = numberExponent - ( compactDigits - 1 );
90+
number = number / Math.pow( 10, divisor );
9491
}
9592
}
9693

@@ -107,18 +104,16 @@ return function( number, properties, pluralGenerator ) {
107104

108105
// Compact mode: apply formatting
109106
if ( compactMap && compactPattern ) {
110-
pluralForm = pluralGenerator ? pluralGenerator( number ) : "other";
111-
compactPattern = compactMap[ "1" + zeroes + "-count-" + pluralForm ] || compactPattern;
112107

113-
// Some languages specify no pattern for certain digit lengths, represented as "0".
114-
// Only apply compact pattern if one is specified.
115-
if ( compactPattern !== "0" ) {
116-
compactProperties = compactPattern.match( numberPatternRe );
108+
// Get plural form after possible roundings
109+
pluralForm = pluralGenerator ? pluralGenerator( +number ) : "other";
117110

118-
// update prefix/suffix with compact prefix/suffix
119-
prefix += compactProperties[ 1 ];
120-
suffix = compactProperties[ 11 ] + suffix;
121-
}
111+
compactPattern = compactMap[ numberExponent ][ pluralForm ] || compactPattern;
112+
compactProperties = compactPattern.match( numberCompactPatternRe );
113+
114+
// update prefix/suffix with compact prefix/suffix
115+
prefix += compactProperties[ 1 ];
116+
suffix = compactProperties[ 3 ] + suffix;
122117
}
123118

124119
// Remove the possible number minus sign

src/number/pattern-re.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ define(function() {
2626
*
2727
* suffix = non_number_stuff
2828
*
29-
* non_number_stuff = regexp(.*?)
29+
* non_number_stuff = regexp(('[^']+'|''|[^*#@0,.E])*)
3030
*
3131
*
3232
* Regexp groups:
@@ -45,6 +45,6 @@ define(function() {
4545
* 11: suffix
4646
* 12: -
4747
*/
48-
return ( /^(('([^']|'')*'|[^*#@0,.E])*)(\*.)?((([#,]*[0,]*0+)(\.0*[0-9]*#*)?)|([#,]*@+#*))(E\+?0+)?(.*?)$/ );
48+
return ( /^(('([^']|'')*'|[^*#@0,.E])*)(\*.)?((([#,]*[0,]*0+)(\.0*[0-9]*#*)?)|([#,]*@+#*))(E\+?0+)?(('[^']+'|''|[^*#@0,.E])*)$/ );
4949

5050
});

0 commit comments

Comments
 (0)