@@ -460,6 +460,9 @@ Return a function that formats a number according to the given options or locale
.numberFormatter({ style: "percent" })( 0.5 )
// > "50%"
.numberFormatter({ compact: "short", maximumFractionDigits: 0 })( 14305 )
// > "14K"
```

[Read more...](doc/api/number/number-formatter.md)
@@ -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
@@ -37,6 +39,8 @@ formatter( 9.99 );
```

#### Instance Formatter

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

```javascript
@@ -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
@@ -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
@@ -131,6 +139,37 @@ formatter( 1.491 );
// > "$1.50"
```

#### Formatting Compact Currencies

```js
var shortFormatter = Globalize( "en" ).currencyFormatter( "USD", {
compact: "short"
});
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
@@ -30,6 +30,10 @@ Optional. String with rounding method `ceil`, `floor`, `round` (default), or `tr

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

#### options.compact

Optional. String `short` or `long` indicating which compact number format should be used to represent the number.

### Examples

#### Static Formatter
@@ -139,6 +143,37 @@ frFormatter( 0.0005 );
// > "0,05 %"
```

#### Formatting Compact Numbers

Long numbers can be represented in a compact format, with `short` using abbreviated units and `long` using the full unit name.

```javascript
var shortFormatter = Globalize( "en" ).numberFormatter({
compact: "short"
});
var longFormatter = Globalize( "en" ).numberFormatter({
compact: "long"
});
shortFormatter( 27588910 );
// > "28M"
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`.
@@ -68,7 +68,7 @@ function validateDigits( properties ) {
*/
Globalize.numberFormatter =
Globalize.prototype.numberFormatter = function( options ) {
var args, cldr, pattern, properties, returnFn;
var args, cldr, pattern, pluralGenerator, properties, returnFn;

validateParameterTypePlainObject( options, "options" );

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

validateDigits( properties );

returnFn = numberFormatterFn( properties );

runtimeBind( args, cldr, returnFn, [ properties ] );
if ( options.compact ) {
pluralGenerator = this.pluralGenerator();
returnFn = numberFormatterFn( properties, pluralGenerator );
runtimeBind( args, cldr, returnFn, [ properties, pluralGenerator ] );
} else {
returnFn = numberFormatterFn( properties );
runtimeBind( args, cldr, returnFn, [ properties ] );
}

return returnFn;
};
@@ -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]*)$/ );

});
@@ -0,0 +1,37 @@
define([
"./numbering-system"
], function( numberNumberingSystem ) {

/**
* Compact( name, cldr )
*
* @compactType [String] Compact mode, `short` or `long`.
*
* @cldr [Cldr instance].
*
* Return the localized compact map for the given compact mode.
*/
return function( compactType, cldr ) {
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;
};

});
@@ -1,12 +1,13 @@
define([
"./compact",
"./numbering-system-digits-map",
"./pattern-properties",
"./symbol",
"./symbol/map",
"./symbol/name",
"../util/number/round"
], function( numberNumberingSystemDigitsMap, numberPatternProperties, numberSymbol, numberSymbolMap,
numberSymbolName, numberRound ) {
], function( numberCompact, numberNumberingSystemDigitsMap, numberPatternProperties, numberSymbol,
numberSymbolMap, numberSymbolName, numberRound ) {

/**
* formatProperties( pattern, cldr [, options] )
@@ -63,6 +64,22 @@ return function( pattern, cldr, options ) {
numberNumberingSystemDigitsMap( cldr )
]);

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

getOptions( "minimumIntegerDigits", 2 );
getOptions( "minimumFractionDigits", 3 );
getOptions( "maximumFractionDigits", 4 );
@@ -98,6 +115,7 @@ return function( pattern, cldr, options ) {
// 17: @nanSymbol [String] NaN symbol.
// 18: @symbolMap [Object] A bunch of other symbols.
// 19: @nuDigitsMap [Array] Digits map if numbering system is different than `latn`.
// 20: @compactMap [Object] Map of per-digit-count format patterns for specified compact mode.
return properties;
};

@@ -1,10 +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, removeLiteralQuotes ) {
], function( numberCompactPatternRe, numberFormatGroupingSeparator,
numberFormatIntegerFractionDigits, numberFormatSignificantDigits, numberPatternRe,
removeLiteralQuotes ) {

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

padding = properties[ 1 ];
minimumIntegerDigits = properties[ 2 ];
@@ -36,6 +39,7 @@ return function( number, properties ) {
nanSymbol = properties[ 17 ];
symbolMap = properties[ 18 ];
nuDigitsMap = properties[ 19 ];
compactMap = properties[ 20 ];

// NaN
if ( isNaN( number ) ) {
@@ -57,8 +61,6 @@ return function( number, properties ) {
return prefix + infinitySymbol + suffix;
}

ret = prefix;

// Percent
if ( pattern.indexOf( "%" ) !== -1 ) {
number *= 100;
@@ -68,6 +70,27 @@ return function( number, properties ) {
number *= 1000;
}

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

// Compact mode: initial number digit processing
if ( compactMap ) {
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 );
}
}

// Significant digit format
if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) ) {
number = numberFormatSignificantDigits( number, minimumSignificantDigits,
@@ -79,6 +102,20 @@ return function( number, properties ) {
minimumFractionDigits, maximumFractionDigits, round, roundIncrement );
}

// Compact mode: apply formatting
if ( compactMap && compactPattern ) {

// Get plural form after possible roundings
pluralForm = pluralGenerator ? pluralGenerator( +number ) : "other";

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
number = number.replace( /^-/, "" );

@@ -88,6 +125,8 @@ return function( number, properties ) {
secondaryGroupingSize );
}

ret = prefix;

ret += number;

// Scientific notation
@@ -4,12 +4,12 @@ define([
"./format"
], function( validateParameterPresence, validateParameterTypeNumber, numberFormat ) {

return function( properties ) {
return function( properties, pluralGenerator ) {
return function numberFormatter( value ) {
validateParameterPresence( value, "value" );
validateParameterTypeNumber( value, "value" );

return numberFormat( value, properties );
return numberFormat( value, properties, pluralGenerator );
};
};