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 Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Number to be formatted, eg. `9.99`.

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

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

```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( "BRL" )( 1 )` | `R$1.00` | `1,00 R$` | `R$ 1.00` |

#### Configuring style

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

```javascript
Expand Down Expand Up @@ -109,6 +115,8 @@ formatter( 9.99 );
// > "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).

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

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

formatter = Globalize.currencyFormatter( "USD", {
maximumFractionDigits: 0,
#### Formatting Compact Currencies

```js
var shortFormatter = Globalize( "en" ).currencyFormatter( "USD", {
compact: "short"
});

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

shortFormatter( 12830000000 );
// > "$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.

```javascript
Expand Down
19 changes: 13 additions & 6 deletions doc/api/number/number-formatter.md
Original file line number 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
var shortFormatter = Globalize( "en" ).numberFormatter({
compact: "short",
maximumFractionDigits: 0,
style: "decimal"
compact: "short"
});

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

shortFormatter( 27588910 );
Expand All @@ -167,6 +163,17 @@ longFormatter( 27588910 );
// > "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

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 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 Diff line number Diff line change
@@ -1,5 +1,5 @@
define([
"./numbering-system"
"./numbering-system"
], function( numberNumberingSystem ) {

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

var object = cldr.main([
"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 Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ return function( pattern, cldr, options ) {
]);

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 );
}

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

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

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

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

// use default plural form to perform initial decimal shift
compactPattern = compactMap[ "1" + zeroes + "-count-other" ];

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

// Some languages specify no pattern for certain digit lengths, represented as "0".
// If no pattern, original number should remain uncompacted.
if ( compactPattern === "0" ) {
number = originalNumber;
}
}
numberExponent = Math.floor( number ).toString().length - 1;
numberExponent = Math.min( numberExponent, compactMap.maxExponent );

// Use default plural form to perform initial decimal shift
if ( numberExponent >= 3 ) {
compactPattern = compactMap[ numberExponent ] && compactMap[ numberExponent ].other;
}

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

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

// Compact mode: apply formatting
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".
// Only apply compact pattern if one is specified.
if ( compactPattern !== "0" ) {
compactProperties = compactPattern.match( numberPatternRe );
// Get plural form after possible roundings
pluralForm = pluralGenerator ? pluralGenerator( +number ) : "other";

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

// update prefix/suffix with compact prefix/suffix
prefix += compactProperties[ 1 ];
suffix = compactProperties[ 3 ] + suffix;
}

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