Skip to content

Commit 6d0e5a0

Browse files
sieverkrxaviers
authored andcommitted
Number: Add support for compact option (short/long) (1/2)
1 parent 7fe1fc7 commit 6d0e5a0

File tree

10 files changed

+266
-21
lines changed

10 files changed

+266
-21
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,9 @@ Return a function that formats a number according to the given options or locale
461461
.numberFormatter({ style: "percent" })( 0.5 )
462462
// > "50%"
463463
```
464+
.numberFormatter({ compact: "short", maximumFractionDigits: 0 })( 14305 )
465+
// > "14K"
466+
```
464467
465468
[Read more...](doc/api/number/number-formatter.md)
466469

doc/api/currency/currency-formatter.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ formatter = Globalize.currencyFormatter( "USD", {
129129

130130
formatter( 1.491 );
131131
// > "$1.50"
132+
133+
formatter = Globalize.currencyFormatter( "USD", {
134+
maximumFractionDigits: 0,
135+
compact: "short"
136+
});
137+
138+
formatter( 12830000000 );
139+
// > "$13B"
132140
```
133141

134142
For improved performance on iterations, first create the formatter. Then, reuse it on each loop.

doc/api/number/number-formatter.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ Optional. String with rounding method `ceil`, `floor`, `round` (default), or `tr
3030

3131
Optional. Boolean (default is true) value indicating whether a grouping separator should be used.
3232

33+
#### options.compact
34+
35+
Optional. String `short` or `long` indicating which compact number format should be used to represent the number.
36+
3337
### Examples
3438

3539
#### Static Formatter
@@ -139,6 +143,30 @@ frFormatter( 0.0005 );
139143
// > "0,05 %"
140144
```
141145

146+
#### Formatting Compact Numbers
147+
148+
Long numbers can be represented in a compact format, with `short` using abbreviated units and `long` using the full unit name.
149+
150+
```javascript
151+
var shortFormatter = Globalize( "en" ).numberFormatter({
152+
compact: "short",
153+
maximumFractionDigits: 0,
154+
style: "decimal"
155+
});
156+
157+
var longFormatter = Globalize( "en" ).numberFormatter({
158+
compact: "long",
159+
maximumFractionDigits: 0,
160+
style: "decimal"
161+
});
162+
163+
shortFormatter( 27588910 );
164+
// > "28M"
165+
166+
longFormatter( 27588910 );
167+
// > "28 million"
168+
```
169+
142170
#### Configuring Rounding
143171

144172
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.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ function validateDigits( properties ) {
6868
*/
6969
Globalize.numberFormatter =
7070
Globalize.prototype.numberFormatter = function( options ) {
71-
var args, cldr, pattern, properties, returnFn;
71+
var args, cldr, pattern, pluralGenerator, properties, returnFn;
7272

7373
validateParameterTypePlainObject( options, "options" );
7474

@@ -93,9 +93,14 @@ Globalize.prototype.numberFormatter = function( options ) {
9393

9494
validateDigits( properties );
9595

96-
returnFn = numberFormatterFn( properties );
97-
98-
runtimeBind( args, cldr, returnFn, [ properties ] );
96+
if ( options.compact ) {
97+
pluralGenerator = this.pluralGenerator();
98+
returnFn = numberFormatterFn( properties, pluralGenerator );
99+
runtimeBind( args, cldr, returnFn, [ properties, pluralGenerator ] );
100+
} else {
101+
returnFn = numberFormatterFn( properties );
102+
runtimeBind( args, cldr, returnFn, [ properties ] );
103+
}
99104

100105
return returnFn;
101106
};

src/number/compact.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
define([
2+
"./numbering-system"
3+
], function( numberNumberingSystem ) {
4+
5+
/**
6+
* Compact( name, cldr )
7+
*
8+
* @compactType [String] Compact mode, `short` or `long`.
9+
*
10+
* @cldr [Cldr instance].
11+
*
12+
* Return the localized compact map for the given compact mode.
13+
*/
14+
return function( compactType, cldr ) {
15+
return cldr.main([
16+
"numbers/decimalFormats-numberSystem-" + numberNumberingSystem( cldr ),
17+
compactType,
18+
"decimalFormat"
19+
]);
20+
};
21+
22+
});

src/number/format-properties.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
define([
2+
"./compact",
23
"./numbering-system-digits-map",
34
"./pattern-properties",
45
"./symbol",
56
"./symbol/map",
67
"./symbol/name",
78
"../util/number/round"
8-
], function( numberNumberingSystemDigitsMap, numberPatternProperties, numberSymbol, numberSymbolMap,
9-
numberSymbolName, numberRound ) {
9+
], function( numberCompact, numberNumberingSystemDigitsMap, numberPatternProperties, numberSymbol,
10+
numberSymbolMap, numberSymbolName, numberRound ) {
1011

1112
/**
1213
* formatProperties( pattern, cldr [, options] )
@@ -63,6 +64,10 @@ return function( pattern, cldr, options ) {
6364
numberNumberingSystemDigitsMap( cldr )
6465
]);
6566

67+
if ( options.compact ) {
68+
properties[20] = numberCompact( options.compact, cldr );
69+
}
70+
6671
getOptions( "minimumIntegerDigits", 2 );
6772
getOptions( "minimumFractionDigits", 3 );
6873
getOptions( "maximumFractionDigits", 4 );
@@ -98,6 +103,7 @@ return function( pattern, cldr, options ) {
98103
// 17: @nanSymbol [String] NaN symbol.
99104
// 18: @symbolMap [Object] A bunch of other symbols.
100105
// 19: @nuDigitsMap [Array] Digits map if numbering system is different than `latn`.
106+
// 20: @compactMap [Object] Map of per-digit-count format patterns for specified compact mode.
101107
return properties;
102108
};
103109

src/number/format.js

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ define([
22
"./format/grouping-separator",
33
"./format/integer-fraction-digits",
44
"./format/significant-digits",
5+
"./pattern-re",
56
"../util/remove-literal-quotes"
67
], function( numberFormatGroupingSeparator, numberFormatIntegerFractionDigits,
7-
numberFormatSignificantDigits, removeLiteralQuotes ) {
8+
numberFormatSignificantDigits, numberPatternRe, removeLiteralQuotes ) {
89

910
/**
1011
* format( number, properties )
@@ -16,11 +17,11 @@ define([
1617
* Return the formatted number.
1718
* ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
1819
*/
19-
return function( number, properties ) {
20-
var infinitySymbol, maximumFractionDigits, maximumSignificantDigits, minimumFractionDigits,
21-
minimumIntegerDigits, minimumSignificantDigits, nanSymbol, nuDigitsMap, padding, prefix,
22-
primaryGroupingSize, pattern, ret, round, roundIncrement, secondaryGroupingSize, suffix,
23-
symbolMap;
20+
return function( number, properties, pluralGenerator ) {
21+
var compactMap, infinitySymbol, maximumFractionDigits, maximumSignificantDigits,
22+
minimumFractionDigits, minimumIntegerDigits, minimumSignificantDigits, nanSymbol, nuDigitsMap,
23+
padding, prefix, primaryGroupingSize, pattern, ret, round, roundIncrement,
24+
secondaryGroupingSize, suffix, symbolMap;
2425

2526
padding = properties[ 1 ];
2627
minimumIntegerDigits = properties[ 2 ];
@@ -36,6 +37,7 @@ return function( number, properties ) {
3637
nanSymbol = properties[ 17 ];
3738
symbolMap = properties[ 18 ];
3839
nuDigitsMap = properties[ 19 ];
40+
compactMap = properties[ 20 ];
3941

4042
// NaN
4143
if ( isNaN( number ) ) {
@@ -57,8 +59,6 @@ return function( number, properties ) {
5759
return prefix + infinitySymbol + suffix;
5860
}
5961

60-
ret = prefix;
61-
6262
// Percent
6363
if ( pattern.indexOf( "%" ) !== -1 ) {
6464
number *= 100;
@@ -68,6 +68,32 @@ return function( number, properties ) {
6868
number *= 1000;
6969
}
7070

71+
var compactPattern, compactDigits, compactProperties, divisor, pluralForm, zeroes,
72+
originalNumber;
73+
74+
// Compact mode: initial number digit processing
75+
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+
}
94+
}
95+
}
96+
7197
// Significant digit format
7298
if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) ) {
7399
number = numberFormatSignificantDigits( number, minimumSignificantDigits,
@@ -79,6 +105,22 @@ return function( number, properties ) {
79105
minimumFractionDigits, maximumFractionDigits, round, roundIncrement );
80106
}
81107

108+
// Compact mode: apply formatting
109+
if ( compactMap && compactPattern ) {
110+
pluralForm = pluralGenerator ? pluralGenerator( number ) : "other";
111+
compactPattern = compactMap[ "1" + zeroes + "-count-" + pluralForm ] || compactPattern;
112+
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 );
117+
118+
// update prefix/suffix with compact prefix/suffix
119+
prefix += compactProperties[ 1 ];
120+
suffix = compactProperties[ 11 ] + suffix;
121+
}
122+
}
123+
82124
// Remove the possible number minus sign
83125
number = number.replace( /^-/, "" );
84126

@@ -88,6 +130,8 @@ return function( number, properties ) {
88130
secondaryGroupingSize );
89131
}
90132

133+
ret = prefix;
134+
91135
ret += number;
92136

93137
// Scientific notation

src/number/formatter-fn.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ define([
44
"./format"
55
], function( validateParameterPresence, validateParameterTypeNumber, numberFormat ) {
66

7-
return function( properties ) {
7+
return function( properties, pluralGenerator ) {
88
return function numberFormatter( value ) {
99
validateParameterPresence( value, "value" );
1010
validateParameterTypeNumber( value, "value" );
1111

12-
return numberFormat( value, properties );
12+
return numberFormat( value, properties, pluralGenerator );
1313
};
1414
};
1515

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(('[^']+'|''|[^*#@0,.E])*)
29+
* non_number_stuff = regexp(.*?)
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+)?(('[^']+'|''|[^*#@0,.E])*)$/ );
48+
return ( /^(('([^']|'')*'|[^*#@0,.E])*)(\*.)?((([#,]*[0,]*0+)(\.0*[0-9]*#*)?)|([#,]*@+#*))(E\+?0+)?(.*?)$/ );
4949

5050
});

0 commit comments

Comments
 (0)