| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275 |
- /**
- * Globalize v1.0.1
- *
- * http://github.com/jquery/globalize
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license
- * http://jquery.org/license
- *
- * Date: 2016-01-20T16:57Z
- */
- /*!
- * Globalize v1.0.1 2016-01-20T16:57Z Released under the MIT license
- * http://git.io/TrdQbw
- */
- (function( root, factory ) {
- // UMD returnExports
- if ( typeof define === "function" && define.amd ) {
- // AMD
- define([
- "cldr",
- "../globalize",
- "cldr/event",
- "cldr/supplemental"
- ], factory );
- } else if ( typeof exports === "object" ) {
- // Node, CommonJS
- module.exports = factory( require( "cldrjs" ), require( "globalize" ) );
- } else {
- // Global
- factory( root.Cldr, root.Globalize );
- }
- }(this, function( Cldr, Globalize ) {
- var createError = Globalize._createError,
- objectExtend = Globalize._objectExtend,
- regexpEscape = Globalize._regexpEscape,
- stringPad = Globalize._stringPad,
- validateCldr = Globalize._validateCldr,
- validateDefaultLocale = Globalize._validateDefaultLocale,
- validateParameterPresence = Globalize._validateParameterPresence,
- validateParameterRange = Globalize._validateParameterRange,
- validateParameterType = Globalize._validateParameterType,
- validateParameterTypePlainObject = Globalize._validateParameterTypePlainObject;
- var createErrorUnsupportedFeature = function( feature ) {
- return createError( "E_UNSUPPORTED", "Unsupported {feature}.", {
- feature: feature
- });
- };
- var validateParameterTypeNumber = function( value, name ) {
- validateParameterType(
- value,
- name,
- value === undefined || typeof value === "number",
- "Number"
- );
- };
- var validateParameterTypeString = function( value, name ) {
- validateParameterType(
- value,
- name,
- value === undefined || typeof value === "string",
- "a string"
- );
- };
- /**
- * goupingSeparator( number, primaryGroupingSize, secondaryGroupingSize )
- *
- * @number [Number].
- *
- * @primaryGroupingSize [Number]
- *
- * @secondaryGroupingSize [Number]
- *
- * Return the formatted number with group separator.
- */
- var numberFormatGroupingSeparator = function( number, primaryGroupingSize, secondaryGroupingSize ) {
- var index,
- currentGroupingSize = primaryGroupingSize,
- ret = "",
- sep = ",",
- switchToSecondary = secondaryGroupingSize ? true : false;
- number = String( number ).split( "." );
- index = number[ 0 ].length;
- while ( index > currentGroupingSize ) {
- ret = number[ 0 ].slice( index - currentGroupingSize, index ) +
- ( ret.length ? sep : "" ) + ret;
- index -= currentGroupingSize;
- if ( switchToSecondary ) {
- currentGroupingSize = secondaryGroupingSize;
- switchToSecondary = false;
- }
- }
- number[ 0 ] = number[ 0 ].slice( 0, index ) + ( ret.length ? sep : "" ) + ret;
- return number.join( "." );
- };
- /**
- * integerFractionDigits( number, minimumIntegerDigits, minimumFractionDigits,
- * maximumFractionDigits, round, roundIncrement )
- *
- * @number [Number]
- *
- * @minimumIntegerDigits [Number]
- *
- * @minimumFractionDigits [Number]
- *
- * @maximumFractionDigits [Number]
- *
- * @round [Function]
- *
- * @roundIncrement [Function]
- *
- * Return the formatted integer and fraction digits.
- */
- var numberFormatIntegerFractionDigits = function( number, minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, round,
- roundIncrement ) {
- // Fraction
- if ( maximumFractionDigits ) {
- // Rounding
- if ( roundIncrement ) {
- number = round( number, roundIncrement );
- // Maximum fraction digits
- } else {
- number = round( number, { exponent: -maximumFractionDigits } );
- }
- // Minimum fraction digits
- if ( minimumFractionDigits ) {
- number = String( number ).split( "." );
- number[ 1 ] = stringPad( number[ 1 ] || "", minimumFractionDigits, true );
- number = number.join( "." );
- }
- } else {
- number = round( number );
- }
- number = String( number );
- // Minimum integer digits
- if ( minimumIntegerDigits ) {
- number = number.split( "." );
- number[ 0 ] = stringPad( number[ 0 ], minimumIntegerDigits );
- number = number.join( "." );
- }
- return number;
- };
- /**
- * toPrecision( number, precision, round )
- *
- * @number (Number)
- *
- * @precision (Number) significant figures precision (not decimal precision).
- *
- * @round (Function)
- *
- * Return number.toPrecision( precision ) using the given round function.
- */
- var numberToPrecision = function( number, precision, round ) {
- var roundOrder;
- // Get number at two extra significant figure precision.
- number = number.toPrecision( precision + 2 );
- // Then, round it to the required significant figure precision.
- roundOrder = Math.ceil( Math.log( Math.abs( number ) ) / Math.log( 10 ) );
- roundOrder -= precision;
- return round( number, { exponent: roundOrder } );
- };
- /**
- * toPrecision( number, minimumSignificantDigits, maximumSignificantDigits, round )
- *
- * @number [Number]
- *
- * @minimumSignificantDigits [Number]
- *
- * @maximumSignificantDigits [Number]
- *
- * @round [Function]
- *
- * Return the formatted significant digits number.
- */
- var numberFormatSignificantDigits = function( number, minimumSignificantDigits, maximumSignificantDigits, round ) {
- var atMinimum, atMaximum;
- // Sanity check.
- if ( minimumSignificantDigits > maximumSignificantDigits ) {
- maximumSignificantDigits = minimumSignificantDigits;
- }
- atMinimum = numberToPrecision( number, minimumSignificantDigits, round );
- atMaximum = numberToPrecision( number, maximumSignificantDigits, round );
- // Use atMaximum only if it has more significant digits than atMinimum.
- number = +atMinimum === +atMaximum ? atMinimum : atMaximum;
- // Expand integer numbers, eg. 123e5 to 12300.
- number = ( +number ).toString( 10 );
- if ( ( /e/ ).test( number ) ) {
- throw createErrorUnsupportedFeature({
- feature: "integers out of (1e21, 1e-7)"
- });
- }
- // Add trailing zeros if necessary.
- if ( minimumSignificantDigits - number.replace( /^0+|\./g, "" ).length > 0 ) {
- number = number.split( "." );
- number[ 1 ] = stringPad( number[ 1 ] || "", minimumSignificantDigits - number[ 0 ].replace( /^0+/, "" ).length, true );
- number = number.join( "." );
- }
- return number;
- };
- /**
- * format( number, properties )
- *
- * @number [Number].
- *
- * @properties [Object] Output of number/format-properties.
- *
- * Return the formatted number.
- * ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
- */
- var numberFormat = function( number, properties ) {
- var infinitySymbol, maximumFractionDigits, maximumSignificantDigits, minimumFractionDigits,
- minimumIntegerDigits, minimumSignificantDigits, nanSymbol, nuDigitsMap, padding, prefix,
- primaryGroupingSize, pattern, ret, round, roundIncrement, secondaryGroupingSize, suffix,
- symbolMap;
- padding = properties[ 1 ];
- minimumIntegerDigits = properties[ 2 ];
- minimumFractionDigits = properties[ 3 ];
- maximumFractionDigits = properties[ 4 ];
- minimumSignificantDigits = properties[ 5 ];
- maximumSignificantDigits = properties[ 6 ];
- roundIncrement = properties[ 7 ];
- primaryGroupingSize = properties[ 8 ];
- secondaryGroupingSize = properties[ 9 ];
- round = properties[ 15 ];
- infinitySymbol = properties[ 16 ];
- nanSymbol = properties[ 17 ];
- symbolMap = properties[ 18 ];
- nuDigitsMap = properties[ 19 ];
- // NaN
- if ( isNaN( number ) ) {
- return nanSymbol;
- }
- if ( number < 0 ) {
- pattern = properties[ 12 ];
- prefix = properties[ 13 ];
- suffix = properties[ 14 ];
- } else {
- pattern = properties[ 11 ];
- prefix = properties[ 0 ];
- suffix = properties[ 10 ];
- }
- // Infinity
- if ( !isFinite( number ) ) {
- return prefix + infinitySymbol + suffix;
- }
- ret = prefix;
- // Percent
- if ( pattern.indexOf( "%" ) !== -1 ) {
- number *= 100;
- // Per mille
- } else if ( pattern.indexOf( "\u2030" ) !== -1 ) {
- number *= 1000;
- }
- // Significant digit format
- if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) ) {
- number = numberFormatSignificantDigits( number, minimumSignificantDigits,
- maximumSignificantDigits, round );
- // Integer and fractional format
- } else {
- number = numberFormatIntegerFractionDigits( number, minimumIntegerDigits,
- minimumFractionDigits, maximumFractionDigits, round, roundIncrement );
- }
- // Remove the possible number minus sign
- number = number.replace( /^-/, "" );
- // Grouping separators
- if ( primaryGroupingSize ) {
- number = numberFormatGroupingSeparator( number, primaryGroupingSize,
- secondaryGroupingSize );
- }
- ret += number;
- // Scientific notation
- // TODO implement here
- // Padding/'([^']|'')+'|''|[.,\-+E%\u2030]/g
- // TODO implement here
- ret += suffix;
- return ret.replace( /('([^']|'')+'|'')|./g, function( character, literal ) {
- // Literals
- if ( literal ) {
- literal = literal.replace( /''/, "'" );
- if ( literal.length > 2 ) {
- literal = literal.slice( 1, -1 );
- }
- return literal;
- }
- // Symbols
- character = character.replace( /[.,\-+E%\u2030]/, function( symbol ) {
- return symbolMap[ symbol ];
- });
- // Numbering system
- if ( nuDigitsMap ) {
- character = character.replace( /[0-9]/, function( digit ) {
- return nuDigitsMap[ +digit ];
- });
- }
- return character;
- });
- };
- /**
- * NumberingSystem( cldr )
- *
- * - http://www.unicode.org/reports/tr35/tr35-numbers.html#otherNumberingSystems
- * - http://cldr.unicode.org/index/bcp47-extension
- * - http://www.unicode.org/reports/tr35/#u_Extension
- */
- var numberNumberingSystem = function( cldr ) {
- var nu = cldr.attributes[ "u-nu" ];
- if ( nu ) {
- if ( nu === "traditio" ) {
- nu = "traditional";
- }
- if ( [ "native", "traditional", "finance" ].indexOf( nu ) !== -1 ) {
- // Unicode locale extension `u-nu` is set using either (native, traditional or
- // finance). So, lookup the respective locale's numberingSystem and return it.
- return cldr.main([ "numbers/otherNumberingSystems", nu ]);
- }
- // Unicode locale extension `u-nu` is set with an explicit numberingSystem. Return it.
- return nu;
- }
- // Return the default numberingSystem.
- return cldr.main( "numbers/defaultNumberingSystem" );
- };
- /**
- * nuMap( cldr )
- *
- * @cldr [Cldr instance].
- *
- * Return digits map if numbering system is different than `latn`.
- */
- var numberNumberingSystemDigitsMap = function( cldr ) {
- var aux,
- nu = numberNumberingSystem( cldr );
- if ( nu === "latn" ) {
- return;
- }
- aux = cldr.supplemental([ "numberingSystems", nu ]);
- if ( aux._type !== "numeric" ) {
- throw createErrorUnsupportedFeature( "`" + aux._type + "` numbering system" );
- }
- return aux._digits;
- };
- /**
- * EBNF representation:
- *
- * number_pattern_re = prefix?
- * padding?
- * (integer_fraction_pattern | significant_pattern)
- * scientific_notation?
- * suffix?
- *
- * prefix = non_number_stuff
- *
- * padding = "*" regexp(.)
- *
- * integer_fraction_pattern = integer_pattern
- * fraction_pattern?
- *
- * integer_pattern = regexp([#,]*[0,]*0+)
- *
- * fraction_pattern = "." regexp(0*[0-9]*#*)
- *
- * significant_pattern = regexp([#,]*@+#*)
- *
- * scientific_notation = regexp(E\+?0+)
- *
- * suffix = non_number_stuff
- *
- * non_number_stuff = regexp(('[^']+'|''|[^*#@0,.E])*)
- *
- *
- * Regexp groups:
- *
- * 0: number_pattern_re
- * 1: prefix
- * 2: -
- * 3: padding
- * 4: (integer_fraction_pattern | significant_pattern)
- * 5: integer_fraction_pattern
- * 6: integer_pattern
- * 7: fraction_pattern
- * 8: significant_pattern
- * 9: scientific_notation
- * 10: suffix
- * 11: -
- */
- var numberPatternRe = ( /^(('[^']+'|''|[^*#@0,.E])*)(\*.)?((([#,]*[0,]*0+)(\.0*[0-9]*#*)?)|([#,]*@+#*))(E\+?0+)?(('[^']+'|''|[^*#@0,.E])*)$/ );
- /**
- * format( number, pattern )
- *
- * @number [Number].
- *
- * @pattern [String] raw pattern for numbers.
- *
- * Return the formatted number.
- * ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
- */
- var numberPatternProperties = function( pattern ) {
- var aux1, aux2, fractionPattern, integerFractionOrSignificantPattern, integerPattern,
- maximumFractionDigits, maximumSignificantDigits, minimumFractionDigits,
- minimumIntegerDigits, minimumSignificantDigits, padding, prefix, primaryGroupingSize,
- roundIncrement, scientificNotation, secondaryGroupingSize, significantPattern, suffix;
- pattern = pattern.match( numberPatternRe );
- if ( !pattern ) {
- throw new Error( "Invalid pattern: " + pattern );
- }
- prefix = pattern[ 1 ];
- padding = pattern[ 3 ];
- integerFractionOrSignificantPattern = pattern[ 4 ];
- significantPattern = pattern[ 8 ];
- scientificNotation = pattern[ 9 ];
- suffix = pattern[ 10 ];
- // Significant digit format
- if ( significantPattern ) {
- significantPattern.replace( /(@+)(#*)/, function( match, minimumSignificantDigitsMatch, maximumSignificantDigitsMatch ) {
- minimumSignificantDigits = minimumSignificantDigitsMatch.length;
- maximumSignificantDigits = minimumSignificantDigits +
- maximumSignificantDigitsMatch.length;
- });
- // Integer and fractional format
- } else {
- fractionPattern = pattern[ 7 ];
- integerPattern = pattern[ 6 ];
- if ( fractionPattern ) {
- // Minimum fraction digits, and rounding.
- fractionPattern.replace( /[0-9]+/, function( match ) {
- minimumFractionDigits = match;
- });
- if ( minimumFractionDigits ) {
- roundIncrement = +( "0." + minimumFractionDigits );
- minimumFractionDigits = minimumFractionDigits.length;
- } else {
- minimumFractionDigits = 0;
- }
- // Maximum fraction digits
- // 1: ignore decimal character
- maximumFractionDigits = fractionPattern.length - 1 /* 1 */;
- }
- // Minimum integer digits
- integerPattern.replace( /0+$/, function( match ) {
- minimumIntegerDigits = match.length;
- });
- }
- // Scientific notation
- if ( scientificNotation ) {
- throw createErrorUnsupportedFeature({
- feature: "scientific notation (not implemented)"
- });
- }
- // Padding
- if ( padding ) {
- throw createErrorUnsupportedFeature({
- feature: "padding (not implemented)"
- });
- }
- // Grouping
- if ( ( aux1 = integerFractionOrSignificantPattern.lastIndexOf( "," ) ) !== -1 ) {
- // Primary grouping size is the interval between the last group separator and the end of
- // the integer (or the end of the significant pattern).
- aux2 = integerFractionOrSignificantPattern.split( "." )[ 0 ];
- primaryGroupingSize = aux2.length - aux1 - 1;
- // Secondary grouping size is the interval between the last two group separators.
- if ( ( aux2 = integerFractionOrSignificantPattern.lastIndexOf( ",", aux1 - 1 ) ) !== -1 ) {
- secondaryGroupingSize = aux1 - 1 - aux2;
- }
- }
- // Return:
- // 0: @prefix String
- // 1: @padding Array [ <character>, <count> ] TODO
- // 2: @minimumIntegerDigits non-negative integer Number value indicating the minimum integer
- // digits to be used. Numbers will be padded with leading zeroes if necessary.
- // 3: @minimumFractionDigits and
- // 4: @maximumFractionDigits are non-negative integer Number values indicating the minimum and
- // maximum fraction digits to be used. Numbers will be rounded or padded with trailing
- // zeroes if necessary.
- // 5: @minimumSignificantDigits and
- // 6: @maximumSignificantDigits are positive integer Number values indicating the minimum and
- // maximum fraction digits to be shown. Either none or both of these properties are
- // present; if they are, they override minimum and maximum integer and fraction digits
- // – the formatter uses however many integer and fraction digits are required to display
- // the specified number of significant digits.
- // 7: @roundIncrement Decimal round increment or null
- // 8: @primaryGroupingSize
- // 9: @secondaryGroupingSize
- // 10: @suffix String
- return [
- prefix,
- padding,
- minimumIntegerDigits,
- minimumFractionDigits,
- maximumFractionDigits,
- minimumSignificantDigits,
- maximumSignificantDigits,
- roundIncrement,
- primaryGroupingSize,
- secondaryGroupingSize,
- suffix
- ];
- };
- /**
- * Symbol( name, cldr )
- *
- * @name [String] Symbol name.
- *
- * @cldr [Cldr instance].
- *
- * Return the localized symbol given its name.
- */
- var numberSymbol = function( name, cldr ) {
- return cldr.main([
- "numbers/symbols-numberSystem-" + numberNumberingSystem( cldr ),
- name
- ]);
- };
- var numberSymbolName = {
- ".": "decimal",
- ",": "group",
- "%": "percentSign",
- "+": "plusSign",
- "-": "minusSign",
- "E": "exponential",
- "\u2030": "perMille"
- };
- /**
- * symbolMap( cldr )
- *
- * @cldr [Cldr instance].
- *
- * Return the (localized symbol, pattern symbol) key value pair, eg. {
- * ".": "٫",
- * ",": "٬",
- * "%": "٪",
- * ...
- * };
- */
- var numberSymbolMap = function( cldr ) {
- var symbol,
- symbolMap = {};
- for ( symbol in numberSymbolName ) {
- symbolMap[ symbol ] = numberSymbol( numberSymbolName[ symbol ], cldr );
- }
- return symbolMap;
- };
- var numberTruncate = function( value ) {
- if ( isNaN( value ) ) {
- return NaN;
- }
- return Math[ value < 0 ? "ceil" : "floor" ]( value );
- };
- /**
- * round( method )
- *
- * @method [String] with either "round", "ceil", "floor", or "truncate".
- *
- * Return function( value, incrementOrExp ):
- *
- * @value [Number] eg. 123.45.
- *
- * @incrementOrExp [Number] optional, eg. 0.1; or
- * [Object] Either { increment: <value> } or { exponent: <value> }
- *
- * Return the rounded number, eg:
- * - round( "round" )( 123.45 ): 123;
- * - round( "ceil" )( 123.45 ): 124;
- * - round( "floor" )( 123.45 ): 123;
- * - round( "truncate" )( 123.45 ): 123;
- * - round( "round" )( 123.45, 0.1 ): 123.5;
- * - round( "round" )( 123.45, 10 ): 120;
- *
- * Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
- * Ref: #376
- */
- var numberRound = function( method ) {
- method = method || "round";
- method = method === "truncate" ? numberTruncate : Math[ method ];
- return function( value, incrementOrExp ) {
- var exp, increment;
- value = +value;
- // If the value is not a number, return NaN.
- if ( isNaN( value ) ) {
- return NaN;
- }
- // Exponent given.
- if ( typeof incrementOrExp === "object" && incrementOrExp.exponent ) {
- exp = +incrementOrExp.exponent;
- increment = 1;
- if ( exp === 0 ) {
- return method( value );
- }
- // If the exp is not an integer, return NaN.
- if ( !( typeof exp === "number" && exp % 1 === 0 ) ) {
- return NaN;
- }
- // Increment given.
- } else {
- increment = +incrementOrExp || 1;
- if ( increment === 1 ) {
- return method( value );
- }
- // If the increment is not a number, return NaN.
- if ( isNaN( increment ) ) {
- return NaN;
- }
- increment = increment.toExponential().split( "e" );
- exp = +increment[ 1 ];
- increment = +increment[ 0 ];
- }
- // Shift & Round
- value = value.toString().split( "e" );
- value[ 0 ] = +value[ 0 ] / increment;
- value[ 1 ] = value[ 1 ] ? ( +value[ 1 ] - exp ) : -exp;
- value = method( +( value[ 0 ] + "e" + value[ 1 ] ) );
- // Shift back
- value = value.toString().split( "e" );
- value[ 0 ] = +value[ 0 ] * increment;
- value[ 1 ] = value[ 1 ] ? ( +value[ 1 ] + exp ) : exp;
- return +( value[ 0 ] + "e" + value[ 1 ] );
- };
- };
- /**
- * formatProperties( pattern, cldr [, options] )
- *
- * @pattern [String] raw pattern for numbers.
- *
- * @cldr [Cldr instance].
- *
- * @options [Object]:
- * - minimumIntegerDigits [Number]
- * - minimumFractionDigits, maximumFractionDigits [Number]
- * - minimumSignificantDigits, maximumSignificantDigits [Number]
- * - round [String] "ceil", "floor", "round" (default), or "truncate".
- * - useGrouping [Boolean] default true.
- *
- * Return the processed properties that will be used in number/format.
- * ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
- */
- var numberFormatProperties = function( pattern, cldr, options ) {
- var negativePattern, negativePrefix, negativeProperties, negativeSuffix, positivePattern,
- properties;
- function getOptions( attribute, propertyIndex ) {
- if ( attribute in options ) {
- properties[ propertyIndex ] = options[ attribute ];
- }
- }
- options = options || {};
- pattern = pattern.split( ";" );
- positivePattern = pattern[ 0 ];
- negativePattern = pattern[ 1 ] || "-" + positivePattern;
- negativeProperties = numberPatternProperties( negativePattern );
- negativePrefix = negativeProperties[ 0 ];
- negativeSuffix = negativeProperties[ 10 ];
- properties = numberPatternProperties( positivePattern ).concat([
- positivePattern,
- negativePrefix + positivePattern + negativeSuffix,
- negativePrefix,
- negativeSuffix,
- numberRound( options.round ),
- numberSymbol( "infinity", cldr ),
- numberSymbol( "nan", cldr ),
- numberSymbolMap( cldr ),
- numberNumberingSystemDigitsMap( cldr )
- ]);
- getOptions( "minimumIntegerDigits", 2 );
- getOptions( "minimumFractionDigits", 3 );
- getOptions( "maximumFractionDigits", 4 );
- getOptions( "minimumSignificantDigits", 5 );
- getOptions( "maximumSignificantDigits", 6 );
- // Grouping separators
- if ( options.useGrouping === false ) {
- properties[ 8 ] = null;
- }
- // Normalize number of digits if only one of either minimumFractionDigits or
- // maximumFractionDigits is passed in as an option
- if ( "minimumFractionDigits" in options && !( "maximumFractionDigits" in options ) ) {
- // maximumFractionDigits = Math.max( minimumFractionDigits, maximumFractionDigits );
- properties[ 4 ] = Math.max( properties[ 3 ], properties[ 4 ] );
- } else if ( !( "minimumFractionDigits" in options ) &&
- "maximumFractionDigits" in options ) {
- // minimumFractionDigits = Math.min( minimumFractionDigits, maximumFractionDigits );
- properties[ 3 ] = Math.min( properties[ 3 ], properties[ 4 ] );
- }
- // Return:
- // 0-10: see number/pattern-properties.
- // 11: @positivePattern [String] Positive pattern.
- // 12: @negativePattern [String] Negative pattern.
- // 13: @negativePrefix [String] Negative prefix.
- // 14: @negativeSuffix [String] Negative suffix.
- // 15: @round [Function] Round function.
- // 16: @infinitySymbol [String] Infinity symbol.
- // 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`.
- return properties;
- };
- /**
- * EBNF representation:
- *
- * number_pattern_re = prefix_including_padding?
- * number
- * scientific_notation?
- * suffix?
- *
- * number = integer_including_group_separator fraction_including_decimal_separator
- *
- * integer_including_group_separator =
- * regexp([0-9,]*[0-9]+)
- *
- * fraction_including_decimal_separator =
- * regexp((\.[0-9]+)?)
- * prefix_including_padding = non_number_stuff
- *
- * scientific_notation = regexp(E[+-]?[0-9]+)
- *
- * suffix = non_number_stuff
- *
- * non_number_stuff = regexp([^0-9]*)
- *
- *
- * Regexp groups:
- *
- * 0: number_pattern_re
- * 1: prefix
- * 2: integer_including_group_separator fraction_including_decimal_separator
- * 3: integer_including_group_separator
- * 4: fraction_including_decimal_separator
- * 5: scientific_notation
- * 6: suffix
- */
- var numberNumberRe = ( /^([^0-9]*)(([0-9,]*[0-9]+)(\.[0-9]+)?)(E[+-]?[0-9]+)?([^0-9]*)$/ );
- /**
- * parse( value, properties )
- *
- * @value [String].
- *
- * @properties [Object] Parser properties is a reduced pre-processed cldr
- * data set returned by numberParserProperties().
- *
- * Return the parsed Number (including Infinity) or NaN when value is invalid.
- * ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
- */
- var numberParse = function( value, properties ) {
- var aux, infinitySymbol, invertedNuDigitsMap, invertedSymbolMap, localizedDigitRe,
- localizedSymbolsRe, negativePrefix, negativeSuffix, number, prefix, suffix;
- infinitySymbol = properties[ 0 ];
- invertedSymbolMap = properties[ 1 ];
- negativePrefix = properties[ 2 ];
- negativeSuffix = properties[ 3 ];
- invertedNuDigitsMap = properties[ 4 ];
- // Infinite number.
- if ( aux = value.match( infinitySymbol ) ) {
- number = Infinity;
- prefix = value.slice( 0, aux.length );
- suffix = value.slice( aux.length + 1 );
- // Finite number.
- } else {
- // TODO: Create it during setup, i.e., make it a property.
- localizedSymbolsRe = new RegExp(
- Object.keys( invertedSymbolMap ).map(function( localizedSymbol ) {
- return regexpEscape( localizedSymbol );
- }).join( "|" ),
- "g"
- );
- // Reverse localized symbols.
- value = value.replace( localizedSymbolsRe, function( localizedSymbol ) {
- return invertedSymbolMap[ localizedSymbol ];
- });
- // Reverse localized numbering system.
- if ( invertedNuDigitsMap ) {
- // TODO: Create it during setup, i.e., make it a property.
- localizedDigitRe = new RegExp(
- Object.keys( invertedNuDigitsMap ).map(function( localizedDigit ) {
- return regexpEscape( localizedDigit );
- }).join( "|" ),
- "g"
- );
- value = value.replace( localizedDigitRe, function( localizedDigit ) {
- return invertedNuDigitsMap[ localizedDigit ];
- });
- }
- // Add padding zero to leading decimal.
- if ( value.charAt( 0 ) === "." ) {
- value = "0" + value;
- }
- // Is it a valid number?
- value = value.match( numberNumberRe );
- if ( !value ) {
- // Invalid number.
- return NaN;
- }
- prefix = value[ 1 ];
- suffix = value[ 6 ];
- // Remove grouping separators.
- number = value[ 2 ].replace( /,/g, "" );
- // Scientific notation
- if ( value[ 5 ] ) {
- number += value[ 5 ];
- }
- number = +number;
- // Is it a valid number?
- if ( isNaN( number ) ) {
- // Invalid number.
- return NaN;
- }
- // Percent
- if ( value[ 0 ].indexOf( "%" ) !== -1 ) {
- number /= 100;
- suffix = suffix.replace( "%", "" );
- // Per mille
- } else if ( value[ 0 ].indexOf( "\u2030" ) !== -1 ) {
- number /= 1000;
- suffix = suffix.replace( "\u2030", "" );
- }
- }
- // Negative number
- // "If there is an explicit negative subpattern, it serves only to specify the negative prefix
- // and suffix. If there is no explicit negative subpattern, the negative subpattern is the
- // localized minus sign prefixed to the positive subpattern" UTS#35
- if ( prefix === negativePrefix && suffix === negativeSuffix ) {
- number *= -1;
- }
- return number;
- };
- /**
- * symbolMap( cldr )
- *
- * @cldr [Cldr instance].
- *
- * Return the (localized symbol, pattern symbol) key value pair, eg. {
- * "٫": ".",
- * "٬": ",",
- * "٪": "%",
- * ...
- * };
- */
- var numberSymbolInvertedMap = function( cldr ) {
- var symbol,
- symbolMap = {};
- for ( symbol in numberSymbolName ) {
- symbolMap[ numberSymbol( numberSymbolName[ symbol ], cldr ) ] = symbol;
- }
- return symbolMap;
- };
- /**
- * parseProperties( pattern, cldr )
- *
- * @pattern [String] raw pattern for numbers.
- *
- * @cldr [Cldr instance].
- *
- * Return parser properties, used to feed parser function.
- */
- var numberParseProperties = function( pattern, cldr ) {
- var invertedNuDigitsMap, invertedNuDigitsMapSanityCheck, negativePattern, negativeProperties,
- nuDigitsMap = numberNumberingSystemDigitsMap( cldr );
- pattern = pattern.split( ";" );
- negativePattern = pattern[ 1 ] || "-" + pattern[ 0 ];
- negativeProperties = numberPatternProperties( negativePattern );
- if ( nuDigitsMap ) {
- invertedNuDigitsMap = nuDigitsMap.split( "" ).reduce(function( object, localizedDigit, i ) {
- object[ localizedDigit ] = String( i );
- return object;
- }, {} );
- invertedNuDigitsMapSanityCheck = "0123456789".split( "" ).reduce(function( object, digit ) {
- object[ digit ] = "invalid";
- return object;
- }, {} );
- invertedNuDigitsMap = objectExtend(
- invertedNuDigitsMapSanityCheck,
- invertedNuDigitsMap
- );
- }
- // 0: @infinitySymbol [String] Infinity symbol.
- // 1: @invertedSymbolMap [Object] Inverted symbol map augmented with sanity check.
- // The sanity check prevents permissive parsing, i.e., it prevents symbols that doesn't
- // belong to the localized set to pass through. This is obtained with the result of the
- // inverted map object overloading symbol name map object (the remaining symbol name
- // mappings will invalidate parsing, working as the sanity check).
- // 2: @negativePrefix [String] Negative prefix.
- // 3: @negativeSuffix [String] Negative suffix with percent or per mille stripped out.
- // 4: @invertedNuDigitsMap [Object] Inverted digits map if numbering system is different than
- // `latn` augmented with sanity check (similar to invertedSymbolMap).
- return [
- numberSymbol( "infinity", cldr ),
- objectExtend( {}, numberSymbolName, numberSymbolInvertedMap( cldr ) ),
- negativeProperties[ 0 ],
- negativeProperties[ 10 ].replace( "%", "" ).replace( "\u2030", "" ),
- invertedNuDigitsMap
- ];
- };
- /**
- * Pattern( style )
- *
- * @style [String] "decimal" (default) or "percent".
- *
- * @cldr [Cldr instance].
- */
- var numberPattern = function( style, cldr ) {
- if ( style !== "decimal" && style !== "percent" ) {
- throw new Error( "Invalid style" );
- }
- return cldr.main([
- "numbers",
- style + "Formats-numberSystem-" + numberNumberingSystem( cldr ),
- "standard"
- ]);
- };
- function validateDigits( properties ) {
- var minimumIntegerDigits = properties[ 2 ],
- minimumFractionDigits = properties[ 3 ],
- maximumFractionDigits = properties[ 4 ],
- minimumSignificantDigits = properties[ 5 ],
- maximumSignificantDigits = properties[ 6 ];
- // Validate significant digit format properties
- if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) ) {
- validateParameterRange( minimumSignificantDigits, "minimumSignificantDigits", 1, 21 );
- validateParameterRange( maximumSignificantDigits, "maximumSignificantDigits",
- minimumSignificantDigits, 21 );
- } else if ( !isNaN( minimumSignificantDigits ) || !isNaN( maximumSignificantDigits ) ) {
- throw new Error( "Neither or both the minimum and maximum significant digits must be " +
- "present" );
- // Validate integer and fractional format
- } else {
- validateParameterRange( minimumIntegerDigits, "minimumIntegerDigits", 1, 21 );
- validateParameterRange( minimumFractionDigits, "minimumFractionDigits", 0, 20 );
- validateParameterRange( maximumFractionDigits, "maximumFractionDigits",
- minimumFractionDigits, 20 );
- }
- }
- /**
- * .numberFormatter( [options] )
- *
- * @options [Object]:
- * - style: [String] "decimal" (default) or "percent".
- * - see also number/format options.
- *
- * Return a function that formats a number according to the given options and default/instance
- * locale.
- */
- Globalize.numberFormatter =
- Globalize.prototype.numberFormatter = function( options ) {
- var cldr, pattern, properties;
- validateParameterTypePlainObject( options, "options" );
- options = options || {};
- cldr = this.cldr;
- validateDefaultLocale( cldr );
- cldr.on( "get", validateCldr );
- if ( options.raw ) {
- pattern = options.raw;
- } else {
- pattern = numberPattern( options.style || "decimal", cldr );
- }
- properties = numberFormatProperties( pattern, cldr, options );
- cldr.off( "get", validateCldr );
- validateDigits( properties );
- return function( value ) {
- validateParameterPresence( value, "value" );
- validateParameterTypeNumber( value, "value" );
- return numberFormat( value, properties );
- };
- };
- /**
- * .numberParser( [options] )
- *
- * @options [Object]:
- * - style: [String] "decimal" (default) or "percent".
- *
- * Return the number parser according to the default/instance locale.
- */
- Globalize.numberParser =
- Globalize.prototype.numberParser = function( options ) {
- var cldr, pattern, properties;
- validateParameterTypePlainObject( options, "options" );
- options = options || {};
- cldr = this.cldr;
- validateDefaultLocale( cldr );
- cldr.on( "get", validateCldr );
- if ( options.raw ) {
- pattern = options.raw;
- } else {
- pattern = numberPattern( options.style || "decimal", cldr );
- }
- properties = numberParseProperties( pattern, cldr );
- cldr.off( "get", validateCldr );
- return function( value ) {
- validateParameterPresence( value, "value" );
- validateParameterTypeString( value, "value" );
- return numberParse( value, properties );
- };
- };
- /**
- * .formatNumber( value [, options] )
- *
- * @value [Number] number to be formatted.
- *
- * @options [Object]: see number/format-properties.
- *
- * Format a number according to the given options and default/instance locale.
- */
- Globalize.formatNumber =
- Globalize.prototype.formatNumber = function( value, options ) {
- validateParameterPresence( value, "value" );
- validateParameterTypeNumber( value, "value" );
- return this.numberFormatter( options )( value );
- };
- /**
- * .parseNumber( value [, options] )
- *
- * @value [String]
- *
- * @options [Object]: See numberParser().
- *
- * Return the parsed Number (including Infinity) or NaN when value is invalid.
- */
- Globalize.parseNumber =
- Globalize.prototype.parseNumber = function( value, options ) {
- validateParameterPresence( value, "value" );
- validateParameterTypeString( value, "value" );
- return this.numberParser( options )( value );
- };
- /**
- * Optimization to avoid duplicating some internal functions across modules.
- */
- Globalize._createErrorUnsupportedFeature = createErrorUnsupportedFeature;
- Globalize._numberNumberingSystem = numberNumberingSystem;
- Globalize._numberPattern = numberPattern;
- Globalize._numberSymbol = numberSymbol;
- Globalize._stringPad = stringPad;
- Globalize._validateParameterTypeNumber = validateParameterTypeNumber;
- Globalize._validateParameterTypeString = validateParameterTypeString;
- return Globalize;
- }));
|