Skip to content

Commit

Permalink
Number: Add support for compact option (short/long) (2/2)
Browse files Browse the repository at this point in the history
  • Loading branch information
rxaviers committed Aug 22, 2017
1 parent e4e1276 commit a975fd7
Show file tree
Hide file tree
Showing 8 changed files with 330 additions and 172 deletions.
37 changes: 34 additions & 3 deletions doc/api/currency/currency-formatter.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Number to be formatted, eg. `9.99`.


### Example ### Example


#### Static Formatter

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


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


``` ```


#### Instance Formatter

You can use the instance method `.currencyFormatter()`, which uses the instance locale. You can use the instance method `.currencyFormatter()`, which uses the instance locale.


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


#### Configuring style

For the accounting variation of the symbol format, use `style: "accounting"`. For the accounting variation of the symbol format, use `style: "accounting"`.


```javascript ```javascript
Expand Down Expand Up @@ -109,6 +115,8 @@ formatter( 9.99 );
// > "9.99 USD" // > "9.99 USD"
``` ```


#### Configuring inherited number options

Override the number of digits, grouping separators, rounding function or any other [`.numberFormatter()` options](../number/number-formatter.md). Override the number of digits, grouping separators, rounding function or any other [`.numberFormatter()` options](../number/number-formatter.md).


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


formatter( 1.491 ); formatter( 1.491 );
// > "$1.50" // > "$1.50"
```


formatter = Globalize.currencyFormatter( "USD", { #### Formatting Compact Currencies
maximumFractionDigits: 0,
```js
var shortFormatter = Globalize( "en" ).currencyFormatter( "USD", {
compact: "short" compact: "short"
}); });


formatter( 12830000000 ); var longFormatter = Globalize( "en" ).currencyFormatter( "USD", {
compact: "long"
});

shortFormatter( 12830000000 );
// > "$13B" // > "$13B"

longFormatter( 12830000000 );
// > "$13 billion"
``` ```


The minimumSignificantDigits and maximumSignificantDigits options are specially useful to control the number of digits to display.

```js
Globalize( "en" ).formatCurrency( 12830000000, "USD", {
compact: "short",
minimumSignificantDigits: 3,
maximumSignificantDigits: 3
});
// > "$12.8B"
```

#### Performance Suggestion

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


```javascript ```javascript
Expand Down
19 changes: 13 additions & 6 deletions doc/api/number/number-formatter.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -149,15 +149,11 @@ Long numbers can be represented in a compact format, with `short` using abbrevia


```javascript ```javascript
var shortFormatter = Globalize( "en" ).numberFormatter({ var shortFormatter = Globalize( "en" ).numberFormatter({
compact: "short", compact: "short"
maximumFractionDigits: 0,
style: "decimal"
}); });


var longFormatter = Globalize( "en" ).numberFormatter({ var longFormatter = Globalize( "en" ).numberFormatter({
compact: "long", compact: "long"
maximumFractionDigits: 0,
style: "decimal"
}); });


shortFormatter( 27588910 ); shortFormatter( 27588910 );
Expand All @@ -167,6 +163,17 @@ longFormatter( 27588910 );
// > "28 million" // > "28 million"
``` ```


The minimumSignificantDigits and maximumSignificantDigits options are specially useful to control the number of digits to display.

```js
Globalize( "en" ).formatNumber( 27588910, {
compact: "short",
minimumSignificantDigits: 3,
maximumSignificantDigits: 3
});
// > "27.6M"
```

#### Configuring Rounding #### Configuring Rounding


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`. 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`.
Expand Down
21 changes: 21 additions & 0 deletions src/number/compact-pattern-re.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,21 @@
define(function() {

/**
* EBNF representation:
*
* compact_pattern_re = prefix?
* number_pattern_re
* suffix?
*
* number_pattern_re = 0+
*
* Regexp groups:
*
* 0: compact_pattern_re
* 1: prefix
* 2: number_pattern_re (the number pattern to use in compact mode)
* 3: suffix
*/
return ( /^([^0]*)(0+)([^0]*)$/ );

});
27 changes: 21 additions & 6 deletions src/number/compact.js
Original file line number Original file line Diff line number Diff line change
@@ -1,5 +1,5 @@
define([ define([
"./numbering-system" "./numbering-system"
], function( numberNumberingSystem ) { ], function( numberNumberingSystem ) {


/** /**
Expand All @@ -12,11 +12,26 @@ define([
* Return the localized compact map for the given compact mode. * Return the localized compact map for the given compact mode.
*/ */
return function( compactType, cldr ) { return function( compactType, cldr ) {
return cldr.main([ var maxExponent = 0;
"numbers/decimalFormats-numberSystem-" + numberNumberingSystem( cldr ),
compactType, var object = cldr.main([
"decimalFormat" "numbers/decimalFormats-numberSystem-" + numberNumberingSystem( cldr ),
]); compactType,
"decimalFormat"
]);

object = Object.keys( object ).reduce(function( newObject, compactKey ) {
var numberExponent = compactKey.split( "0" ).length - 1;
var pluralForm = compactKey.split( "-" )[ 2 ];
newObject[ numberExponent ] = newObject[ numberExponent ] || {};
newObject[ numberExponent ][ pluralForm ] = object[ compactKey ];
maxExponent = Math.max( numberExponent, maxExponent );
return newObject;
}, {});

object.maxExponent = maxExponent;

return object;
}; };


}); });
12 changes: 12 additions & 0 deletions src/number/format-properties.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ return function( pattern, cldr, options ) {
]); ]);


if ( options.compact ) { if ( options.compact ) {

// The compact digits number pattern is always `0+`, so override the following properties.
// Note: minimumIntegerDigits would actually range from `0` to `000` based on the scale of
// the value to be formatted, though we're always using 1 as a simplification, because the
// number won't be zero-padded since we chose the right format based on the scale, i.e.,
// we'd never see something like `003M` anyway.
properties[ 2 ] = negativeSuffix[ 2 ] = 1; // minimumIntegerDigits
properties[ 3 ] = negativeSuffix[ 3 ] = 0; // minimumFractionDigits
properties[ 4 ] = negativeSuffix[ 4 ] = 0; // maximumFractionDigits
properties[ 5 ] = negativeSuffix[ 5 ] = // minimumSignificantDigits &
properties[ 6 ] = negativeSuffix[ 6 ] = undefined ; // maximumSignificantDigits

properties[20] = numberCompact( options.compact, cldr ); properties[20] = numberCompact( options.compact, cldr );
} }


Expand Down
59 changes: 27 additions & 32 deletions src/number/format.js
Original file line number Original file line Diff line number Diff line change
@@ -1,11 +1,13 @@
define([ define([
"./compact-pattern-re",
"./format/grouping-separator", "./format/grouping-separator",
"./format/integer-fraction-digits", "./format/integer-fraction-digits",
"./format/significant-digits", "./format/significant-digits",
"./pattern-re", "./pattern-re",
"../util/remove-literal-quotes" "../util/remove-literal-quotes"
], function( numberFormatGroupingSeparator, numberFormatIntegerFractionDigits, ], function( numberCompactPatternRe, numberFormatGroupingSeparator,
numberFormatSignificantDigits, numberPatternRe, removeLiteralQuotes ) { numberFormatIntegerFractionDigits, numberFormatSignificantDigits, numberPatternRe,
removeLiteralQuotes ) {


/** /**
* format( number, properties ) * format( number, properties )
Expand Down Expand Up @@ -68,29 +70,24 @@ return function( number, properties, pluralGenerator ) {
number *= 1000; number *= 1000;
} }


var compactPattern, compactDigits, compactProperties, divisor, pluralForm, zeroes, var compactPattern, compactDigits, compactProperties, divisor, numberExponent, pluralForm;
originalNumber;


// Compact mode: initial number digit processing // Compact mode: initial number digit processing
if ( compactMap ) { if ( compactMap ) {
originalNumber = number; numberExponent = Math.floor( number ).toString().length - 1;
zeroes = Array( Math.floor( number ).toString().length ).join( "0" ); numberExponent = Math.min( numberExponent, compactMap.maxExponent );
if ( zeroes.length >= 3 ) {

// Use default plural form to perform initial decimal shift
// use default plural form to perform initial decimal shift if ( numberExponent >= 3 ) {
compactPattern = compactMap[ "1" + zeroes + "-count-other" ]; compactPattern = compactMap[ numberExponent ] && compactMap[ numberExponent ].other;

}
if ( compactPattern ) {
compactDigits = compactPattern.split( "0" ).length - 1; if ( compactPattern === "0" ) {
divisor = zeroes.length - ( compactDigits - 1 ); compactPattern = null;
number = number / Math.pow( 10, divisor ); } else if ( compactPattern ) {

compactDigits = compactPattern.split( "0" ).length - 1;
// Some languages specify no pattern for certain digit lengths, represented as "0". divisor = numberExponent - ( compactDigits - 1 );
// If no pattern, original number should remain uncompacted. number = number / Math.pow( 10, divisor );
if ( compactPattern === "0" ) {
number = originalNumber;
}
}
} }
} }


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


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


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


// update prefix/suffix with compact prefix/suffix compactPattern = compactMap[ numberExponent ][ pluralForm ] || compactPattern;
prefix += compactProperties[ 1 ]; compactProperties = compactPattern.match( numberCompactPatternRe );
suffix = compactProperties[ 11 ] + suffix;
} // update prefix/suffix with compact prefix/suffix
prefix += compactProperties[ 1 ];
suffix = compactProperties[ 3 ] + suffix;
} }


// Remove the possible number minus sign // Remove the possible number minus sign
Expand Down
4 changes: 2 additions & 2 deletions src/number/pattern-re.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ define(function() {
* *
* suffix = non_number_stuff * suffix = non_number_stuff
* *
* non_number_stuff = regexp(.*?) * non_number_stuff = regexp(('[^']+'|''|[^*#@0,.E])*)
* *
* *
* Regexp groups: * Regexp groups:
Expand All @@ -45,6 +45,6 @@ define(function() {
* 11: suffix * 11: suffix
* 12: - * 12: -
*/ */
return ( /^(('([^']|'')*'|[^*#@0,.E])*)(\*.)?((([#,]*[0,]*0+)(\.0*[0-9]*#*)?)|([#,]*@+#*))(E\+?0+)?(.*?)$/ ); return ( /^(('([^']|'')*'|[^*#@0,.E])*)(\*.)?((([#,]*[0,]*0+)(\.0*[0-9]*#*)?)|([#,]*@+#*))(E\+?0+)?(('[^']+'|''|[^*#@0,.E])*)$/ );


}); });
Loading

0 comments on commit a975fd7

Please sign in to comment.