| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of intl; | 5 part of intl; |
| 6 /** | 6 /** |
| 7 * Provides the ability to format a number in a locale-specific way. The | 7 * Provides the ability to format a number in a locale-specific way. The |
| 8 * format is specified as a pattern using a subset of the ICU formatting | 8 * format is specified as a pattern using a subset of the ICU formatting |
| 9 * patterns. | 9 * patterns. |
| 10 * | 10 * |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 * is helpful in debugging. | 68 * is helpful in debugging. |
| 69 */ | 69 */ |
| 70 String _pattern; | 70 String _pattern; |
| 71 | 71 |
| 72 /** The locale in which we print numbers. */ | 72 /** The locale in which we print numbers. */ |
| 73 final String _locale; | 73 final String _locale; |
| 74 | 74 |
| 75 /** Caches the symbols used for our locale. */ | 75 /** Caches the symbols used for our locale. */ |
| 76 NumberSymbols _symbols; | 76 NumberSymbols _symbols; |
| 77 | 77 |
| 78 /** The name (or symbol) of the currency to print. */ |
| 79 String currencyName; |
| 80 |
| 78 /** | 81 /** |
| 79 * Transient internal state in which to build up the result of the format | 82 * Transient internal state in which to build up the result of the format |
| 80 * operation. We can have this be just an instance variable because Dart is | 83 * operation. We can have this be just an instance variable because Dart is |
| 81 * single-threaded and unless we do an asynchronous operation in the process | 84 * single-threaded and unless we do an asynchronous operation in the process |
| 82 * of formatting then there will only ever be one number being formatted | 85 * of formatting then there will only ever be one number being formatted |
| 83 * at a time. In languages with threads we'd need to pass this on the stack. | 86 * at a time. In languages with threads we'd need to pass this on the stack. |
| 84 */ | 87 */ |
| 85 final StringBuffer _buffer = new StringBuffer(); | 88 final StringBuffer _buffer = new StringBuffer(); |
| 86 | 89 |
| 87 /** | 90 /** |
| 88 * Create a number format that prints using [newPattern] as it applies in | 91 * Create a number format that prints using [newPattern] as it applies in |
| 89 * [locale]. | 92 * [locale]. |
| 90 */ | 93 */ |
| 91 factory NumberFormat([String newPattern, String locale]) => | 94 factory NumberFormat([String newPattern, String locale]) => |
| 92 new NumberFormat._forPattern(locale, (x) => newPattern); | 95 new NumberFormat._forPattern(locale, (x) => newPattern); |
| 93 | 96 |
| 94 /** Create a number format that prints as DECIMAL_PATTERN. */ | 97 /** Create a number format that prints as DECIMAL_PATTERN. */ |
| 95 NumberFormat.decimalPattern([String locale]) : | 98 NumberFormat.decimalPattern([String locale]) : |
| 96 this._forPattern(locale, (x) => x.DECIMAL_PATTERN); | 99 this._forPattern(locale, (x) => x.DECIMAL_PATTERN); |
| 97 | 100 |
| 98 /** Create a number format that prints as PERCENT_PATTERN. */ | 101 /** Create a number format that prints as PERCENT_PATTERN. */ |
| 99 NumberFormat.percentPattern([String locale]) : | 102 NumberFormat.percentPattern([String locale]) : |
| 100 this._forPattern(locale, (x) => x.PERCENT_PATTERN); | 103 this._forPattern(locale, (x) => x.PERCENT_PATTERN); |
| 101 | 104 |
| 102 /** Create a number format that prints as SCIENTIFIC_PATTERN. */ | 105 /** Create a number format that prints as SCIENTIFIC_PATTERN. */ |
| 103 NumberFormat.scientificPattern([String locale]) : | 106 NumberFormat.scientificPattern([String locale]) : |
| 104 this._forPattern(locale, (x) => x.SCIENTIFIC_PATTERN); | 107 this._forPattern(locale, (x) => x.SCIENTIFIC_PATTERN); |
| 105 | 108 |
| 106 /** Create a number format that prints as CURRENCY_PATTERN. */ | 109 /** Create a number format that prints as CURRENCY_PATTERN. */ |
| 107 NumberFormat.currencyPattern([String locale]) : | 110 NumberFormat.currencyPattern([String locale, String currency]) : |
| 108 this._forPattern(locale, (x) => x.CURRENCY_PATTERN); | 111 this._forPattern(locale, (x) => x.CURRENCY_PATTERN, currency); |
| 109 | 112 |
| 110 /** | 113 /** |
| 111 * Create a number format that prints in a pattern we get from | 114 * Create a number format that prints in a pattern we get from |
| 112 * the [getPattern] function using the locale [locale]. | 115 * the [getPattern] function using the locale [locale]. |
| 113 */ | 116 */ |
| 114 NumberFormat._forPattern(String locale, Function getPattern) : | 117 NumberFormat._forPattern(String locale, Function getPattern, |
| 115 _locale = Intl.verifiedLocale(locale, localeExists) { | 118 [this.currencyName]) : |
| 119 _locale = Intl.verifiedLocale(locale, localeExists) { |
| 116 _symbols = numberFormatSymbols[_locale]; | 120 _symbols = numberFormatSymbols[_locale]; |
| 121 if (currencyName == null) { |
| 122 currencyName = _symbols.DEF_CURRENCY_CODE; |
| 123 } |
| 117 _setPattern(getPattern(_symbols)); | 124 _setPattern(getPattern(_symbols)); |
| 118 } | 125 } |
| 119 | 126 |
| 120 /** | 127 /** |
| 121 * Return the locale code in which we operate, e.g. 'en_US' or 'pt'. | 128 * Return the locale code in which we operate, e.g. 'en_US' or 'pt'. |
| 122 */ | 129 */ |
| 123 String get locale => _locale; | 130 String get locale => _locale; |
| 124 | 131 |
| 125 /** | 132 /** |
| 126 * Return true if the locale exists, or if it is null. The null case | 133 * Return true if the locale exists, or if it is null. The null case |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 /** | 364 /** |
| 358 * Returns the suffix for [x] based on wether it's positive or negative. | 365 * Returns the suffix for [x] based on wether it's positive or negative. |
| 359 * In en_US there are no suffixes for positive or negative. | 366 * In en_US there are no suffixes for positive or negative. |
| 360 */ | 367 */ |
| 361 String _signSuffix(num x) => x.isNegative ? _negativeSuffix : _positiveSuffix; | 368 String _signSuffix(num x) => x.isNegative ? _negativeSuffix : _positiveSuffix; |
| 362 | 369 |
| 363 void _setPattern(String newPattern) { | 370 void _setPattern(String newPattern) { |
| 364 if (newPattern == null) return; | 371 if (newPattern == null) return; |
| 365 // Make spaces non-breaking | 372 // Make spaces non-breaking |
| 366 _pattern = newPattern.replaceAll(' ', '\u00a0'); | 373 _pattern = newPattern.replaceAll(' ', '\u00a0'); |
| 367 var parser = new _NumberFormatParser(this, newPattern); | 374 var parser = |
| 375 new _NumberFormatParser(this, newPattern, currencyName); |
| 368 parser.parse(); | 376 parser.parse(); |
| 369 } | 377 } |
| 370 | 378 |
| 371 String toString() => "NumberFormat($_locale, $_pattern)"; | 379 String toString() => "NumberFormat($_locale, $_pattern)"; |
| 372 } | 380 } |
| 373 | 381 |
| 374 /** | 382 /** |
| 375 * Private class that parses the numeric formatting pattern and sets the | 383 * Private class that parses the numeric formatting pattern and sets the |
| 376 * variables in [format] to appropriate values. Instances of this are | 384 * variables in [format] to appropriate values. Instances of this are |
| 377 * transient and store parsing state in instance variables, so can only be used | 385 * transient and store parsing state in instance variables, so can only be used |
| (...skipping 16 matching lines...) Expand all Loading... |
| 394 static const _PATTERN_PERCENT = '%'; | 402 static const _PATTERN_PERCENT = '%'; |
| 395 static const _PATTERN_EXPONENT = 'E'; | 403 static const _PATTERN_EXPONENT = 'E'; |
| 396 static const _PATTERN_PLUS = '+'; | 404 static const _PATTERN_PLUS = '+'; |
| 397 | 405 |
| 398 /** The format whose state we are setting. */ | 406 /** The format whose state we are setting. */ |
| 399 final NumberFormat format; | 407 final NumberFormat format; |
| 400 | 408 |
| 401 /** The pattern we are parsing. */ | 409 /** The pattern we are parsing. */ |
| 402 final _StringIterator pattern; | 410 final _StringIterator pattern; |
| 403 | 411 |
| 412 /** We can be passed a specific currency symbol, regardless of the locale. */ |
| 413 String currencyName; |
| 414 |
| 404 /** | 415 /** |
| 405 * Create a new [_NumberFormatParser] for a particular [NumberFormat] and | 416 * Create a new [_NumberFormatParser] for a particular [NumberFormat] and |
| 406 * [input] pattern. | 417 * [input] pattern. |
| 407 */ | 418 */ |
| 408 _NumberFormatParser(this.format, input) : pattern = _iterator(input) { | 419 _NumberFormatParser(this.format, input, this.currencyName) : |
| 409 pattern.moveNext(); | 420 pattern = _iterator(input) { |
| 421 pattern.moveNext(); |
| 410 } | 422 } |
| 411 | 423 |
| 412 /** The [NumberSymbols] for the locale in which our [format] prints. */ | 424 /** The [NumberSymbols] for the locale in which our [format] prints. */ |
| 413 NumberSymbols get symbols => format.symbols; | 425 NumberSymbols get symbols => format.symbols; |
| 414 | 426 |
| 415 /** Parse the input pattern and set the values. */ | 427 /** Parse the input pattern and set the values. */ |
| 416 void parse() { | 428 void parse() { |
| 417 format._positivePrefix = _parseAffix(); | 429 format._positivePrefix = _parseAffix(); |
| 418 var trunk = _parseTrunk(); | 430 var trunk = _parseTrunk(); |
| 419 format._positiveSuffix = _parseAffix(); | 431 format._positiveSuffix = _parseAffix(); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 } else { | 491 } else { |
| 480 switch (ch) { | 492 switch (ch) { |
| 481 case _PATTERN_DIGIT: | 493 case _PATTERN_DIGIT: |
| 482 case _PATTERN_ZERO_DIGIT: | 494 case _PATTERN_ZERO_DIGIT: |
| 483 case _PATTERN_GROUPING_SEPARATOR: | 495 case _PATTERN_GROUPING_SEPARATOR: |
| 484 case _PATTERN_DECIMAL_SEPARATOR: | 496 case _PATTERN_DECIMAL_SEPARATOR: |
| 485 case _PATTERN_SEPARATOR: | 497 case _PATTERN_SEPARATOR: |
| 486 return false; | 498 return false; |
| 487 case _PATTERN_CURRENCY_SIGN: | 499 case _PATTERN_CURRENCY_SIGN: |
| 488 // TODO(alanknight): Handle the local/global/portable currency signs | 500 // TODO(alanknight): Handle the local/global/portable currency signs |
| 489 affix.write(symbols.DEF_CURRENCY_CODE); | 501 affix.write(currencyName); |
| 490 break; | 502 break; |
| 491 case _PATTERN_PERCENT: | 503 case _PATTERN_PERCENT: |
| 492 if (format._multiplier != 1) { | 504 if (format._multiplier != 1) { |
| 493 throw new FormatException('Too many percent/permill'); | 505 throw new FormatException('Too many percent/permill'); |
| 494 } | 506 } |
| 495 format._multiplier = 100; | 507 format._multiplier = 100; |
| 496 affix.write(symbols.PERCENT); | 508 affix.write(symbols.PERCENT); |
| 497 break; | 509 break; |
| 498 case _PATTERN_PER_MILLE: | 510 case _PATTERN_PER_MILLE: |
| 499 if (format._multiplier != 1) { | 511 if (format._multiplier != 1) { |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 703 String get peek => nextIndex >= input.length ? null : input[nextIndex]; | 715 String get peek => nextIndex >= input.length ? null : input[nextIndex]; |
| 704 | 716 |
| 705 Iterator<String> get iterator => this; | 717 Iterator<String> get iterator => this; |
| 706 | 718 |
| 707 static String _validate(input) { | 719 static String _validate(input) { |
| 708 if (input is! String) throw new ArgumentError(input); | 720 if (input is! String) throw new ArgumentError(input); |
| 709 return input; | 721 return input; |
| 710 } | 722 } |
| 711 | 723 |
| 712 } | 724 } |
| OLD | NEW |