fix(common): remove deprecated support for intl API (#29250)
BREAKING CHANGE: In v5, we deprecated support for the intl API in order to improve the browser support. We are now removing these deprecated APIs for v9. See the original change here for more info on why: #18284. PR Close #29250
This commit is contained in:
parent
5dfbcd5631
commit
9e7668f16b
|
@ -256,30 +256,6 @@ Some features of Angular may require additional polyfills.
|
|||
|
||||
</tr>
|
||||
|
||||
<tr style="vertical-align: top">
|
||||
|
||||
<td>
|
||||
|
||||
If you use the following deprecated i18n pipes:
|
||||
[date](api/common/DeprecatedDatePipe),
|
||||
[currency](api/common/DeprecatedCurrencyPipe),
|
||||
[decimal](api/common/DeprecatedDecimalPipe),
|
||||
[percent](api/common/DeprecatedPercentPipe)
|
||||
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
||||
[Intl API](guide/browser-support#intl)
|
||||
|
||||
</td>
|
||||
|
||||
<td>
|
||||
All but Chrome, Firefox, Edge, IE 11 and Safari 10
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr style="vertical-align: top">
|
||||
|
||||
<td>
|
||||
|
|
|
@ -34,7 +34,6 @@ v8 - v11
|
|||
|
||||
| Area | API or Feature | May be removed in |
|
||||
| ---- | -------------- | ----------------- |
|
||||
| `@angular/common` | [Pipes using Intl API](#i18n-pipes) | <!--v8--> v9 |
|
||||
| `@angular/common` | [`ReflectiveInjector`](#reflectiveinjector) | <!--v8--> v9 |
|
||||
| `@angular/core` | [`CollectionChangeRecord`](#core) | <!--v7--> v9 |
|
||||
| `@angular/core` | [`DefaultIterableDiffer`](#core) | <!--v7--> v9 |
|
||||
|
@ -67,21 +66,6 @@ Tip: In the [API reference section](api) of this doc site, deprecated APIs are i
|
|||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{@a common}
|
||||
### @angular/common
|
||||
|
||||
|
||||
| API | Replacement | Deprecation announced | Notes |
|
||||
| --- | ----------- | --------------------- | ----- |
|
||||
| [`DeprecatedI18NPipesModule`](api/common/DeprecatedI18NPipesModule) | [`CommonModule`](api/common/CommonModule#pipes) | v5 | See [Pipes](#i18n-pipes) |
|
||||
| [`DeprecatedCurrencyPipe`](api/common/DeprecatedCurrencyPipe) | [`CurrencyPipe`](api/common/CurrencyPipe) | v5 | See [Pipes](#i18n-pipes) |
|
||||
| [`DeprecatedDatePipe`](api/common/DeprecatedDatePipe) | [`DatePipe`](api/common/DatePipe) | v5 | See [Pipes](#i18n-pipes) |
|
||||
| [`DeprecatedDecimalPipe`](api/common/DeprecatedDecimalPipe) | [`DecimalPipe`](api/common/DecimalPipe) | v5 | See [Pipes](#i18n-pipes) |
|
||||
| [`DeprecatedPercentPipe`](api/common/DeprecatedPercentPipe) | [`PercentPipe`](api/common/PercentPipe) | v5 | See [Pipes](#i18n-pipes) |
|
||||
|
||||
|
||||
{@a core}
|
||||
### @angular/core
|
||||
|
||||
|
@ -198,23 +182,6 @@ After:
|
|||
Injector.create({providers});
|
||||
```
|
||||
|
||||
{@a i18n-pipes}
|
||||
### Pipes using Intl API
|
||||
|
||||
<!--
|
||||
From https://blog.angular.io/version-5-0-0-of-angular-now-available-37e414935ced
|
||||
-->
|
||||
|
||||
Angular used to rely on the browser to provide number, date, and currency formatting using browser i18n APIs. This practice meant that most apps needed to use a polyfill, users were seeing inconsistent results across browsers, and common formats (such as the currency pipe) didn’t match developer expectations out of the box.
|
||||
|
||||
In version 4.3, Angular introduced new number, date, and currency pipes that increase standardization across browsers and eliminate the need for i18n polyfills. These pipes use the Unicode Common Locale Data Repository (CLDR) instead of the JS Intl API to provide extensive locale support.
|
||||
|
||||
In version 5.0.0, Angular updated its standard pipes to use the CLRD implementation.
|
||||
At that time, Angular also added [`DeprecatedI18NPipesModule`](api/common/DeprecatedI18NPipesModule) and related APIs to provide limited-time access to the old behavior. If you need to use these `Deprecated*` pipes, see [Angular change log](https://github.com/angular/angular/blob/master/CHANGELOG.md#i18n-pipes) and the [Date Formats mappings](https://docs.google.com/spreadsheets/d/12iygt-_cakNP1VO7MV9g4lq9NsxVWG4tSfc98HpHb0k/edit#gid=0 "Date Formats Google sheet").
|
||||
|
||||
Reminder: If you use these `Deprecated*` pipes, you should migrate to the current APIs listed above as soon as possible. These deprecated APIs are candidates for removal in version 9.
|
||||
|
||||
|
||||
{@a loadChildren}
|
||||
### loadChildren string syntax
|
||||
|
||||
|
|
|
@ -19,11 +19,10 @@ export {NgLocaleLocalization, NgLocalization} from './i18n/localization';
|
|||
export {registerLocaleData} from './i18n/locale_data';
|
||||
export {Plural, NumberFormatStyle, FormStyle, Time, TranslationWidth, FormatWidth, NumberSymbol, WeekDay, getNumberOfCurrencyDigits, getCurrencySymbol, getLocaleDayPeriods, getLocaleDayNames, getLocaleMonthNames, getLocaleId, getLocaleEraNames, getLocaleWeekEndRange, getLocaleFirstDayOfWeek, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocalePluralCase, getLocaleTimeFormat, getLocaleNumberSymbol, getLocaleNumberFormat, getLocaleCurrencyName, getLocaleCurrencySymbol} from './i18n/locale_data_api';
|
||||
export {parseCookieValue as ɵparseCookieValue} from './cookie';
|
||||
export {CommonModule, DeprecatedI18NPipesModule} from './common_module';
|
||||
export {CommonModule} from './common_module';
|
||||
export {NgClass, NgClassBase, NgForOf, NgForOfContext, NgIf, NgIfContext, NgPlural, NgPluralCase, NgStyle, NgStyleBase, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NgComponentOutlet} from './directives/index';
|
||||
export {DOCUMENT} from './dom_tokens';
|
||||
export {AsyncPipe, DatePipe, I18nPluralPipe, I18nSelectPipe, JsonPipe, LowerCasePipe, CurrencyPipe, DecimalPipe, PercentPipe, SlicePipe, UpperCasePipe, TitleCasePipe, KeyValuePipe, KeyValue} from './pipes/index';
|
||||
export {DeprecatedDatePipe, DeprecatedCurrencyPipe, DeprecatedDecimalPipe, DeprecatedPercentPipe} from './pipes/deprecated/index';
|
||||
export {PLATFORM_BROWSER_ID as ɵPLATFORM_BROWSER_ID, PLATFORM_SERVER_ID as ɵPLATFORM_SERVER_ID, PLATFORM_WORKER_APP_ID as ɵPLATFORM_WORKER_APP_ID, PLATFORM_WORKER_UI_ID as ɵPLATFORM_WORKER_UI_ID, isPlatformBrowser, isPlatformServer, isPlatformWorkerApp, isPlatformWorkerUi} from './platform_id';
|
||||
export {VERSION} from './version';
|
||||
export {ViewportScroller, NullViewportScroller as ɵNullViewportScroller} from './viewport_scroller';
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {COMMON_DIRECTIVES} from './directives/index';
|
||||
import {DEPRECATED_PLURAL_FN, NgLocaleLocalization, NgLocalization, getPluralCase} from './i18n/localization';
|
||||
import {COMMON_DEPRECATED_I18N_PIPES} from './pipes/deprecated/index';
|
||||
import {NgLocaleLocalization, NgLocalization} from './i18n/localization';
|
||||
import {COMMON_PIPES} from './pipes/index';
|
||||
|
||||
|
||||
|
@ -37,17 +36,3 @@ import {COMMON_PIPES} from './pipes/index';
|
|||
})
|
||||
export class CommonModule {
|
||||
}
|
||||
|
||||
/**
|
||||
* A module that contains the deprecated i18n pipes.
|
||||
*
|
||||
* @deprecated from v5
|
||||
* @publicApi
|
||||
*/
|
||||
@NgModule({
|
||||
declarations: [COMMON_DEPRECATED_I18N_PIPES],
|
||||
exports: [COMMON_DEPRECATED_I18N_PIPES],
|
||||
providers: [{provide: DEPRECATED_PLURAL_FN, useValue: getPluralCase}],
|
||||
})
|
||||
export class DeprecatedI18NPipesModule {
|
||||
}
|
||||
|
|
|
@ -6,15 +6,10 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Inject, Injectable, InjectionToken, LOCALE_ID, Optional} from '@angular/core';
|
||||
import {Inject, Injectable, LOCALE_ID} from '@angular/core';
|
||||
import {Plural, getLocalePluralCase} from './locale_data_api';
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated from v5
|
||||
*/
|
||||
export const DEPRECATED_PLURAL_FN = new InjectionToken<boolean>('UseV4Plurals');
|
||||
|
||||
/**
|
||||
* @publicApi
|
||||
*/
|
||||
|
@ -56,17 +51,10 @@ export function getPluralCategory(
|
|||
*/
|
||||
@Injectable()
|
||||
export class NgLocaleLocalization extends NgLocalization {
|
||||
constructor(
|
||||
@Inject(LOCALE_ID) protected locale: string,
|
||||
/** @deprecated from v5 */
|
||||
@Optional() @Inject(DEPRECATED_PLURAL_FN) protected deprecatedPluralFn?:
|
||||
((locale: string, value: number|string) => Plural)|null) {
|
||||
super();
|
||||
}
|
||||
constructor(@Inject(LOCALE_ID) protected locale: string) { super(); }
|
||||
|
||||
getPluralCategory(value: any, locale?: string): string {
|
||||
const plural = this.deprecatedPluralFn ? this.deprecatedPluralFn(locale || this.locale, value) :
|
||||
getLocalePluralCase(locale || this.locale)(value);
|
||||
const plural = getLocalePluralCase(locale || this.locale)(value);
|
||||
|
||||
switch (plural) {
|
||||
case Plural.Zero:
|
||||
|
@ -84,320 +72,3 @@ export class NgLocaleLocalization extends NgLocalization {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plural case based on the locale
|
||||
*
|
||||
* @deprecated from v5 the plural case function is in locale data files common/locales/*.ts
|
||||
* @publicApi
|
||||
*/
|
||||
export function getPluralCase(locale: string, nLike: number | string): Plural {
|
||||
// TODO(vicb): lazy compute
|
||||
if (typeof nLike === 'string') {
|
||||
nLike = parseInt(nLike, 10);
|
||||
}
|
||||
const n: number = nLike;
|
||||
const nDecimal = n.toString().replace(/^[^.]*\.?/, '');
|
||||
const i = Math.floor(Math.abs(n));
|
||||
const v = nDecimal.length;
|
||||
const f = parseInt(nDecimal, 10);
|
||||
const t = parseInt(n.toString().replace(/^[^.]*\.?|0+$/g, ''), 10) || 0;
|
||||
|
||||
const lang = locale.split('-')[0].toLowerCase();
|
||||
|
||||
switch (lang) {
|
||||
case 'af':
|
||||
case 'asa':
|
||||
case 'az':
|
||||
case 'bem':
|
||||
case 'bez':
|
||||
case 'bg':
|
||||
case 'brx':
|
||||
case 'ce':
|
||||
case 'cgg':
|
||||
case 'chr':
|
||||
case 'ckb':
|
||||
case 'ee':
|
||||
case 'el':
|
||||
case 'eo':
|
||||
case 'es':
|
||||
case 'eu':
|
||||
case 'fo':
|
||||
case 'fur':
|
||||
case 'gsw':
|
||||
case 'ha':
|
||||
case 'haw':
|
||||
case 'hu':
|
||||
case 'jgo':
|
||||
case 'jmc':
|
||||
case 'ka':
|
||||
case 'kk':
|
||||
case 'kkj':
|
||||
case 'kl':
|
||||
case 'ks':
|
||||
case 'ksb':
|
||||
case 'ky':
|
||||
case 'lb':
|
||||
case 'lg':
|
||||
case 'mas':
|
||||
case 'mgo':
|
||||
case 'ml':
|
||||
case 'mn':
|
||||
case 'nb':
|
||||
case 'nd':
|
||||
case 'ne':
|
||||
case 'nn':
|
||||
case 'nnh':
|
||||
case 'nyn':
|
||||
case 'om':
|
||||
case 'or':
|
||||
case 'os':
|
||||
case 'ps':
|
||||
case 'rm':
|
||||
case 'rof':
|
||||
case 'rwk':
|
||||
case 'saq':
|
||||
case 'seh':
|
||||
case 'sn':
|
||||
case 'so':
|
||||
case 'sq':
|
||||
case 'ta':
|
||||
case 'te':
|
||||
case 'teo':
|
||||
case 'tk':
|
||||
case 'tr':
|
||||
case 'ug':
|
||||
case 'uz':
|
||||
case 'vo':
|
||||
case 'vun':
|
||||
case 'wae':
|
||||
case 'xog':
|
||||
if (n === 1) return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'ak':
|
||||
case 'ln':
|
||||
case 'mg':
|
||||
case 'pa':
|
||||
case 'ti':
|
||||
if (n === Math.floor(n) && n >= 0 && n <= 1) return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'am':
|
||||
case 'as':
|
||||
case 'bn':
|
||||
case 'fa':
|
||||
case 'gu':
|
||||
case 'hi':
|
||||
case 'kn':
|
||||
case 'mr':
|
||||
case 'zu':
|
||||
if (i === 0 || n === 1) return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'ar':
|
||||
if (n === 0) return Plural.Zero;
|
||||
if (n === 1) return Plural.One;
|
||||
if (n === 2) return Plural.Two;
|
||||
if (n % 100 === Math.floor(n % 100) && n % 100 >= 3 && n % 100 <= 10) return Plural.Few;
|
||||
if (n % 100 === Math.floor(n % 100) && n % 100 >= 11 && n % 100 <= 99) return Plural.Many;
|
||||
return Plural.Other;
|
||||
case 'ast':
|
||||
case 'ca':
|
||||
case 'de':
|
||||
case 'en':
|
||||
case 'et':
|
||||
case 'fi':
|
||||
case 'fy':
|
||||
case 'gl':
|
||||
case 'it':
|
||||
case 'nl':
|
||||
case 'sv':
|
||||
case 'sw':
|
||||
case 'ur':
|
||||
case 'yi':
|
||||
if (i === 1 && v === 0) return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'be':
|
||||
if (n % 10 === 1 && !(n % 100 === 11)) return Plural.One;
|
||||
if (n % 10 === Math.floor(n % 10) && n % 10 >= 2 && n % 10 <= 4 &&
|
||||
!(n % 100 >= 12 && n % 100 <= 14))
|
||||
return Plural.Few;
|
||||
if (n % 10 === 0 || n % 10 === Math.floor(n % 10) && n % 10 >= 5 && n % 10 <= 9 ||
|
||||
n % 100 === Math.floor(n % 100) && n % 100 >= 11 && n % 100 <= 14)
|
||||
return Plural.Many;
|
||||
return Plural.Other;
|
||||
case 'br':
|
||||
if (n % 10 === 1 && !(n % 100 === 11 || n % 100 === 71 || n % 100 === 91)) return Plural.One;
|
||||
if (n % 10 === 2 && !(n % 100 === 12 || n % 100 === 72 || n % 100 === 92)) return Plural.Two;
|
||||
if (n % 10 === Math.floor(n % 10) && (n % 10 >= 3 && n % 10 <= 4 || n % 10 === 9) &&
|
||||
!(n % 100 >= 10 && n % 100 <= 19 || n % 100 >= 70 && n % 100 <= 79 ||
|
||||
n % 100 >= 90 && n % 100 <= 99))
|
||||
return Plural.Few;
|
||||
if (!(n === 0) && n % 1e6 === 0) return Plural.Many;
|
||||
return Plural.Other;
|
||||
case 'bs':
|
||||
case 'hr':
|
||||
case 'sr':
|
||||
if (v === 0 && i % 10 === 1 && !(i % 100 === 11) || f % 10 === 1 && !(f % 100 === 11))
|
||||
return Plural.One;
|
||||
if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 &&
|
||||
!(i % 100 >= 12 && i % 100 <= 14) ||
|
||||
f % 10 === Math.floor(f % 10) && f % 10 >= 2 && f % 10 <= 4 &&
|
||||
!(f % 100 >= 12 && f % 100 <= 14))
|
||||
return Plural.Few;
|
||||
return Plural.Other;
|
||||
case 'cs':
|
||||
case 'sk':
|
||||
if (i === 1 && v === 0) return Plural.One;
|
||||
if (i === Math.floor(i) && i >= 2 && i <= 4 && v === 0) return Plural.Few;
|
||||
if (!(v === 0)) return Plural.Many;
|
||||
return Plural.Other;
|
||||
case 'cy':
|
||||
if (n === 0) return Plural.Zero;
|
||||
if (n === 1) return Plural.One;
|
||||
if (n === 2) return Plural.Two;
|
||||
if (n === 3) return Plural.Few;
|
||||
if (n === 6) return Plural.Many;
|
||||
return Plural.Other;
|
||||
case 'da':
|
||||
if (n === 1 || !(t === 0) && (i === 0 || i === 1)) return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'dsb':
|
||||
case 'hsb':
|
||||
if (v === 0 && i % 100 === 1 || f % 100 === 1) return Plural.One;
|
||||
if (v === 0 && i % 100 === 2 || f % 100 === 2) return Plural.Two;
|
||||
if (v === 0 && i % 100 === Math.floor(i % 100) && i % 100 >= 3 && i % 100 <= 4 ||
|
||||
f % 100 === Math.floor(f % 100) && f % 100 >= 3 && f % 100 <= 4)
|
||||
return Plural.Few;
|
||||
return Plural.Other;
|
||||
case 'ff':
|
||||
case 'fr':
|
||||
case 'hy':
|
||||
case 'kab':
|
||||
if (i === 0 || i === 1) return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'fil':
|
||||
if (v === 0 && (i === 1 || i === 2 || i === 3) ||
|
||||
v === 0 && !(i % 10 === 4 || i % 10 === 6 || i % 10 === 9) ||
|
||||
!(v === 0) && !(f % 10 === 4 || f % 10 === 6 || f % 10 === 9))
|
||||
return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'ga':
|
||||
if (n === 1) return Plural.One;
|
||||
if (n === 2) return Plural.Two;
|
||||
if (n === Math.floor(n) && n >= 3 && n <= 6) return Plural.Few;
|
||||
if (n === Math.floor(n) && n >= 7 && n <= 10) return Plural.Many;
|
||||
return Plural.Other;
|
||||
case 'gd':
|
||||
if (n === 1 || n === 11) return Plural.One;
|
||||
if (n === 2 || n === 12) return Plural.Two;
|
||||
if (n === Math.floor(n) && (n >= 3 && n <= 10 || n >= 13 && n <= 19)) return Plural.Few;
|
||||
return Plural.Other;
|
||||
case 'gv':
|
||||
if (v === 0 && i % 10 === 1) return Plural.One;
|
||||
if (v === 0 && i % 10 === 2) return Plural.Two;
|
||||
if (v === 0 &&
|
||||
(i % 100 === 0 || i % 100 === 20 || i % 100 === 40 || i % 100 === 60 || i % 100 === 80))
|
||||
return Plural.Few;
|
||||
if (!(v === 0)) return Plural.Many;
|
||||
return Plural.Other;
|
||||
case 'he':
|
||||
if (i === 1 && v === 0) return Plural.One;
|
||||
if (i === 2 && v === 0) return Plural.Two;
|
||||
if (v === 0 && !(n >= 0 && n <= 10) && n % 10 === 0) return Plural.Many;
|
||||
return Plural.Other;
|
||||
case 'is':
|
||||
if (t === 0 && i % 10 === 1 && !(i % 100 === 11) || !(t === 0)) return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'ksh':
|
||||
if (n === 0) return Plural.Zero;
|
||||
if (n === 1) return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'kw':
|
||||
case 'naq':
|
||||
case 'se':
|
||||
case 'smn':
|
||||
if (n === 1) return Plural.One;
|
||||
if (n === 2) return Plural.Two;
|
||||
return Plural.Other;
|
||||
case 'lag':
|
||||
if (n === 0) return Plural.Zero;
|
||||
if ((i === 0 || i === 1) && !(n === 0)) return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'lt':
|
||||
if (n % 10 === 1 && !(n % 100 >= 11 && n % 100 <= 19)) return Plural.One;
|
||||
if (n % 10 === Math.floor(n % 10) && n % 10 >= 2 && n % 10 <= 9 &&
|
||||
!(n % 100 >= 11 && n % 100 <= 19))
|
||||
return Plural.Few;
|
||||
if (!(f === 0)) return Plural.Many;
|
||||
return Plural.Other;
|
||||
case 'lv':
|
||||
case 'prg':
|
||||
if (n % 10 === 0 || n % 100 === Math.floor(n % 100) && n % 100 >= 11 && n % 100 <= 19 ||
|
||||
v === 2 && f % 100 === Math.floor(f % 100) && f % 100 >= 11 && f % 100 <= 19)
|
||||
return Plural.Zero;
|
||||
if (n % 10 === 1 && !(n % 100 === 11) || v === 2 && f % 10 === 1 && !(f % 100 === 11) ||
|
||||
!(v === 2) && f % 10 === 1)
|
||||
return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'mk':
|
||||
if (v === 0 && i % 10 === 1 || f % 10 === 1) return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'mt':
|
||||
if (n === 1) return Plural.One;
|
||||
if (n === 0 || n % 100 === Math.floor(n % 100) && n % 100 >= 2 && n % 100 <= 10)
|
||||
return Plural.Few;
|
||||
if (n % 100 === Math.floor(n % 100) && n % 100 >= 11 && n % 100 <= 19) return Plural.Many;
|
||||
return Plural.Other;
|
||||
case 'pl':
|
||||
if (i === 1 && v === 0) return Plural.One;
|
||||
if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 &&
|
||||
!(i % 100 >= 12 && i % 100 <= 14))
|
||||
return Plural.Few;
|
||||
if (v === 0 && !(i === 1) && i % 10 === Math.floor(i % 10) && i % 10 >= 0 && i % 10 <= 1 ||
|
||||
v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 5 && i % 10 <= 9 ||
|
||||
v === 0 && i % 100 === Math.floor(i % 100) && i % 100 >= 12 && i % 100 <= 14)
|
||||
return Plural.Many;
|
||||
return Plural.Other;
|
||||
case 'pt':
|
||||
if (n === Math.floor(n) && n >= 0 && n <= 2 && !(n === 2)) return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'ro':
|
||||
if (i === 1 && v === 0) return Plural.One;
|
||||
if (!(v === 0) || n === 0 ||
|
||||
!(n === 1) && n % 100 === Math.floor(n % 100) && n % 100 >= 1 && n % 100 <= 19)
|
||||
return Plural.Few;
|
||||
return Plural.Other;
|
||||
case 'ru':
|
||||
case 'uk':
|
||||
if (v === 0 && i % 10 === 1 && !(i % 100 === 11)) return Plural.One;
|
||||
if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 &&
|
||||
!(i % 100 >= 12 && i % 100 <= 14))
|
||||
return Plural.Few;
|
||||
if (v === 0 && i % 10 === 0 ||
|
||||
v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 5 && i % 10 <= 9 ||
|
||||
v === 0 && i % 100 === Math.floor(i % 100) && i % 100 >= 11 && i % 100 <= 14)
|
||||
return Plural.Many;
|
||||
return Plural.Other;
|
||||
case 'shi':
|
||||
if (i === 0 || n === 1) return Plural.One;
|
||||
if (n === Math.floor(n) && n >= 2 && n <= 10) return Plural.Few;
|
||||
return Plural.Other;
|
||||
case 'si':
|
||||
if (n === 0 || n === 1 || i === 0 && f === 1) return Plural.One;
|
||||
return Plural.Other;
|
||||
case 'sl':
|
||||
if (v === 0 && i % 100 === 1) return Plural.One;
|
||||
if (v === 0 && i % 100 === 2) return Plural.Two;
|
||||
if (v === 0 && i % 100 === Math.floor(i % 100) && i % 100 >= 3 && i % 100 <= 4 || !(v === 0))
|
||||
return Plural.Few;
|
||||
return Plural.Other;
|
||||
case 'tzm':
|
||||
if (n === Math.floor(n) && n >= 0 && n <= 1 || n === Math.floor(n) && n >= 11 && n <= 99)
|
||||
return Plural.One;
|
||||
return Plural.Other;
|
||||
// When there is no specification, the default is always "other"
|
||||
// Spec: http://cldr.unicode.org/index/cldr-spec/plural-rules
|
||||
// > other (required—general plural form — also used if the language only has a single form)
|
||||
default:
|
||||
return Plural.Other;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core';
|
||||
import {ISO8601_DATE_REGEX, isoStringToDate} from '../../i18n/format_date';
|
||||
import {invalidPipeArgumentError} from '../invalid_pipe_argument_error';
|
||||
import {DateFormatter} from './intl';
|
||||
|
||||
/**
|
||||
* @ngModule CommonModule
|
||||
* @description
|
||||
*
|
||||
* Formats a date according to locale rules.
|
||||
*
|
||||
* Where:
|
||||
* - `expression` is a date object or a number (milliseconds since UTC epoch) or an ISO string
|
||||
* (https://www.w3.org/TR/NOTE-datetime).
|
||||
* - `format` indicates which date/time components to include. The format can be predefined as
|
||||
* shown below or custom as shown in the table.
|
||||
* - `'medium'`: equivalent to `'yMMMdjms'` (e.g. `Sep 3, 2010, 12:05:08 PM` for `en-US`)
|
||||
* - `'short'`: equivalent to `'yMdjm'` (e.g. `9/3/2010, 12:05 PM` for `en-US`)
|
||||
* - `'fullDate'`: equivalent to `'yMMMMEEEEd'` (e.g. `Friday, September 3, 2010` for `en-US`)
|
||||
* - `'longDate'`: equivalent to `'yMMMMd'` (e.g. `September 3, 2010` for `en-US`)
|
||||
* - `'mediumDate'`: equivalent to `'yMMMd'` (e.g. `Sep 3, 2010` for `en-US`)
|
||||
* - `'shortDate'`: equivalent to `'yMd'` (e.g. `9/3/2010` for `en-US`)
|
||||
* - `'mediumTime'`: equivalent to `'jms'` (e.g. `12:05:08 PM` for `en-US`)
|
||||
* - `'shortTime'`: equivalent to `'jm'` (e.g. `12:05 PM` for `en-US`)
|
||||
*
|
||||
*
|
||||
* | Component | Symbol | Narrow | Short Form | Long Form | Numeric | 2-digit |
|
||||
* |-----------|:------:|--------|--------------|-------------------|-----------|-----------|
|
||||
* | era | G | G (A) | GGG (AD) | GGGG (Anno Domini)| - | - |
|
||||
* | year | y | - | - | - | y (2015) | yy (15) |
|
||||
* | month | M | L (S) | MMM (Sep) | MMMM (September) | M (9) | MM (09) |
|
||||
* | day | d | - | - | - | d (3) | dd (03) |
|
||||
* | weekday | E | E (S) | EEE (Sun) | EEEE (Sunday) | - | - |
|
||||
* | hour | j | - | - | - | j (13) | jj (13) |
|
||||
* | hour12 | h | - | - | - | h (1 PM) | hh (01 PM)|
|
||||
* | hour24 | H | - | - | - | H (13) | HH (13) |
|
||||
* | minute | m | - | - | - | m (5) | mm (05) |
|
||||
* | second | s | - | - | - | s (9) | ss (09) |
|
||||
* | timezone | z | - | - | z (Pacific Standard Time)| - | - |
|
||||
* | timezone | Z | - | Z (GMT-8:00) | - | - | - |
|
||||
* | timezone | a | - | a (PM) | - | - | - |
|
||||
*
|
||||
* In javascript, only the components specified will be respected (not the ordering,
|
||||
* punctuations, ...) and details of the formatting will be dependent on the locale.
|
||||
*
|
||||
* Timezone of the formatted text will be the local system timezone of the end-user's machine.
|
||||
*
|
||||
* When the expression is a ISO string without time (e.g. 2016-09-19) the time zone offset is not
|
||||
* applied and the formatted text will have the same day, month and year of the expression.
|
||||
*
|
||||
* WARNINGS:
|
||||
* - this pipe is marked as pure hence it will not be re-evaluated when the input is mutated.
|
||||
* Instead users should treat the date as an immutable object and change the reference when the
|
||||
* pipe needs to re-run (this is to avoid reformatting the date on every change detection run
|
||||
* which would be an expensive operation).
|
||||
* - this pipe uses the Internationalization API. Therefore it is only reliable in Chrome and Opera
|
||||
* browsers.
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
* ### Examples
|
||||
*
|
||||
* Assuming `dateObj` is (year: 2010, month: 9, day: 3, hour: 12 PM, minute: 05, second: 08)
|
||||
* in the _local_ time and locale is 'en-US':
|
||||
*
|
||||
* {@example common/pipes/ts/date_pipe.ts region='DeprecatedDatePipe'}
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
@Pipe({name: 'date', pure: true})
|
||||
export class DeprecatedDatePipe implements PipeTransform {
|
||||
/** @internal */
|
||||
static _ALIASES: {[key: string]: string} = {
|
||||
'medium': 'yMMMdjms',
|
||||
'short': 'yMdjm',
|
||||
'fullDate': 'yMMMMEEEEd',
|
||||
'longDate': 'yMMMMd',
|
||||
'mediumDate': 'yMMMd',
|
||||
'shortDate': 'yMd',
|
||||
'mediumTime': 'jms',
|
||||
'shortTime': 'jm'
|
||||
};
|
||||
|
||||
constructor(@Inject(LOCALE_ID) private _locale: string) {}
|
||||
|
||||
transform(value: any, pattern: string = 'mediumDate'): string|null {
|
||||
if (value == null || value === '' || value !== value) return null;
|
||||
|
||||
let date: Date;
|
||||
|
||||
if (typeof value === 'string') {
|
||||
value = value.trim();
|
||||
}
|
||||
|
||||
if (isDate(value)) {
|
||||
date = value;
|
||||
} else if (!isNaN(value - parseFloat(value))) {
|
||||
date = new Date(parseFloat(value));
|
||||
} else if (typeof value === 'string' && /^(\d{4}-\d{1,2}-\d{1,2})$/.test(value)) {
|
||||
/**
|
||||
* For ISO Strings without time the day, month and year must be extracted from the ISO String
|
||||
* before Date creation to avoid time offset and errors in the new Date.
|
||||
* If we only replace '-' with ',' in the ISO String ("2015,01,01"), and try to create a new
|
||||
* date, some browsers (e.g. IE 9) will throw an invalid Date error
|
||||
* If we leave the '-' ("2015-01-01") and try to create a new Date("2015-01-01") the
|
||||
* timeoffset
|
||||
* is applied
|
||||
* Note: ISO months are 0 for January, 1 for February, ...
|
||||
*/
|
||||
const [y, m, d] = value.split('-').map((val: string) => parseInt(val, 10));
|
||||
date = new Date(y, m - 1, d);
|
||||
} else {
|
||||
date = new Date(value);
|
||||
}
|
||||
|
||||
if (!isDate(date)) {
|
||||
let match: RegExpMatchArray|null;
|
||||
if ((typeof value === 'string') && (match = value.match(ISO8601_DATE_REGEX))) {
|
||||
date = isoStringToDate(match);
|
||||
} else {
|
||||
throw invalidPipeArgumentError(DeprecatedDatePipe, value);
|
||||
}
|
||||
}
|
||||
|
||||
return DateFormatter.format(
|
||||
date, this._locale, DeprecatedDatePipe._ALIASES[pattern] || pattern);
|
||||
}
|
||||
}
|
||||
|
||||
function isDate(value: any): value is Date {
|
||||
return value instanceof Date && !isNaN(value.valueOf());
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Provider} from '@angular/core';
|
||||
import {DeprecatedDatePipe} from './date_pipe';
|
||||
import {DeprecatedCurrencyPipe, DeprecatedDecimalPipe, DeprecatedPercentPipe} from './number_pipe';
|
||||
|
||||
export {
|
||||
DeprecatedCurrencyPipe,
|
||||
DeprecatedDatePipe,
|
||||
DeprecatedDecimalPipe,
|
||||
DeprecatedPercentPipe,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A collection of deprecated i18n pipes that require intl api
|
||||
*
|
||||
* @deprecated from v5
|
||||
*/
|
||||
export const COMMON_DEPRECATED_I18N_PIPES: Provider[] =
|
||||
[DeprecatedDecimalPipe, DeprecatedPercentPipe, DeprecatedCurrencyPipe, DeprecatedDatePipe];
|
|
@ -1,221 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {NumberFormatStyle} from '../../i18n/locale_data_api';
|
||||
|
||||
export class NumberFormatter {
|
||||
static format(num: number, locale: string, style: NumberFormatStyle, opts: {
|
||||
minimumIntegerDigits?: number,
|
||||
minimumFractionDigits?: number,
|
||||
maximumFractionDigits?: number,
|
||||
currency?: string|null,
|
||||
currencyAsSymbol?: boolean
|
||||
} = {}): string {
|
||||
const {minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, currency,
|
||||
currencyAsSymbol = false} = opts;
|
||||
const options: Intl.NumberFormatOptions = {
|
||||
minimumIntegerDigits,
|
||||
minimumFractionDigits,
|
||||
maximumFractionDigits,
|
||||
style: NumberFormatStyle[style].toLowerCase()
|
||||
};
|
||||
|
||||
if (style == NumberFormatStyle.Currency) {
|
||||
options.currency = typeof currency == 'string' ? currency : undefined;
|
||||
options.currencyDisplay = currencyAsSymbol ? 'symbol' : 'code';
|
||||
}
|
||||
return new Intl.NumberFormat(locale, options).format(num);
|
||||
}
|
||||
}
|
||||
|
||||
type DateFormatterFn = (date: Date, locale: string) => string;
|
||||
|
||||
const DATE_FORMATS_SPLIT =
|
||||
/((?:[^yMLdHhmsazZEwGjJ']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|J+|j+|m+|s+|a|z|Z|G+|w+))(.*)/;
|
||||
|
||||
const PATTERN_ALIASES: {[format: string]: DateFormatterFn} = {
|
||||
// Keys are quoted so they do not get renamed during closure compilation.
|
||||
'yMMMdjms': datePartGetterFactory(combine([
|
||||
digitCondition('year', 1),
|
||||
nameCondition('month', 3),
|
||||
digitCondition('day', 1),
|
||||
digitCondition('hour', 1),
|
||||
digitCondition('minute', 1),
|
||||
digitCondition('second', 1),
|
||||
])),
|
||||
'yMdjm': datePartGetterFactory(combine([
|
||||
digitCondition('year', 1), digitCondition('month', 1), digitCondition('day', 1),
|
||||
digitCondition('hour', 1), digitCondition('minute', 1)
|
||||
])),
|
||||
'yMMMMEEEEd': datePartGetterFactory(combine([
|
||||
digitCondition('year', 1), nameCondition('month', 4), nameCondition('weekday', 4),
|
||||
digitCondition('day', 1)
|
||||
])),
|
||||
'yMMMMd': datePartGetterFactory(
|
||||
combine([digitCondition('year', 1), nameCondition('month', 4), digitCondition('day', 1)])),
|
||||
'yMMMd': datePartGetterFactory(
|
||||
combine([digitCondition('year', 1), nameCondition('month', 3), digitCondition('day', 1)])),
|
||||
'yMd': datePartGetterFactory(
|
||||
combine([digitCondition('year', 1), digitCondition('month', 1), digitCondition('day', 1)])),
|
||||
'jms': datePartGetterFactory(combine(
|
||||
[digitCondition('hour', 1), digitCondition('second', 1), digitCondition('minute', 1)])),
|
||||
'jm': datePartGetterFactory(combine([digitCondition('hour', 1), digitCondition('minute', 1)]))
|
||||
};
|
||||
|
||||
const DATE_FORMATS: {[format: string]: DateFormatterFn} = {
|
||||
// Keys are quoted so they do not get renamed.
|
||||
'yyyy': datePartGetterFactory(digitCondition('year', 4)),
|
||||
'yy': datePartGetterFactory(digitCondition('year', 2)),
|
||||
'y': datePartGetterFactory(digitCondition('year', 1)),
|
||||
'MMMM': datePartGetterFactory(nameCondition('month', 4)),
|
||||
'MMM': datePartGetterFactory(nameCondition('month', 3)),
|
||||
'MM': datePartGetterFactory(digitCondition('month', 2)),
|
||||
'M': datePartGetterFactory(digitCondition('month', 1)),
|
||||
'LLLL': datePartGetterFactory(nameCondition('month', 4)),
|
||||
'L': datePartGetterFactory(nameCondition('month', 1)),
|
||||
'dd': datePartGetterFactory(digitCondition('day', 2)),
|
||||
'd': datePartGetterFactory(digitCondition('day', 1)),
|
||||
'HH': digitModifier(
|
||||
hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 2), false)))),
|
||||
'H': hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), false))),
|
||||
'hh': digitModifier(
|
||||
hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 2), true)))),
|
||||
'h': hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), true))),
|
||||
'jj': datePartGetterFactory(digitCondition('hour', 2)),
|
||||
'j': datePartGetterFactory(digitCondition('hour', 1)),
|
||||
'mm': digitModifier(datePartGetterFactory(digitCondition('minute', 2))),
|
||||
'm': datePartGetterFactory(digitCondition('minute', 1)),
|
||||
'ss': digitModifier(datePartGetterFactory(digitCondition('second', 2))),
|
||||
's': datePartGetterFactory(digitCondition('second', 1)),
|
||||
// while ISO 8601 requires fractions to be prefixed with `.` or `,`
|
||||
// we can be just safely rely on using `sss` since we currently don't support single or two digit
|
||||
// fractions
|
||||
'sss': datePartGetterFactory(digitCondition('second', 3)),
|
||||
'EEEE': datePartGetterFactory(nameCondition('weekday', 4)),
|
||||
'EEE': datePartGetterFactory(nameCondition('weekday', 3)),
|
||||
'EE': datePartGetterFactory(nameCondition('weekday', 2)),
|
||||
'E': datePartGetterFactory(nameCondition('weekday', 1)),
|
||||
'a': hourClockExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), true))),
|
||||
'Z': timeZoneGetter('short'),
|
||||
'z': timeZoneGetter('long'),
|
||||
'ww': datePartGetterFactory({}), // Week of year, padded (00-53). Week 01 is the week with the
|
||||
// first Thursday of the year. not support ?
|
||||
'w':
|
||||
datePartGetterFactory({}), // Week of year (0-53). Week 1 is the week with the first Thursday
|
||||
// of the year not support ?
|
||||
'G': datePartGetterFactory(nameCondition('era', 1)),
|
||||
'GG': datePartGetterFactory(nameCondition('era', 2)),
|
||||
'GGG': datePartGetterFactory(nameCondition('era', 3)),
|
||||
'GGGG': datePartGetterFactory(nameCondition('era', 4))
|
||||
};
|
||||
|
||||
|
||||
function digitModifier(inner: DateFormatterFn): DateFormatterFn {
|
||||
return function(date: Date, locale: string): string {
|
||||
const result = inner(date, locale);
|
||||
return result.length == 1 ? '0' + result : result;
|
||||
};
|
||||
}
|
||||
|
||||
function hourClockExtractor(inner: DateFormatterFn): DateFormatterFn {
|
||||
return function(date: Date, locale: string): string { return inner(date, locale).split(' ')[1]; };
|
||||
}
|
||||
|
||||
function hourExtractor(inner: DateFormatterFn): DateFormatterFn {
|
||||
return function(date: Date, locale: string): string { return inner(date, locale).split(' ')[0]; };
|
||||
}
|
||||
|
||||
function intlDateFormat(date: Date, locale: string, options: Intl.DateTimeFormatOptions): string {
|
||||
return new Intl.DateTimeFormat(locale, options).format(date).replace(/[\u200e\u200f]/g, '');
|
||||
}
|
||||
|
||||
function timeZoneGetter(timezone: string): DateFormatterFn {
|
||||
// To workaround `Intl` API restriction for single timezone let format with 24 hours
|
||||
const options = {hour: '2-digit', hour12: false, timeZoneName: timezone};
|
||||
return function(date: Date, locale: string): string {
|
||||
const result = intlDateFormat(date, locale, options);
|
||||
// Then extract first 3 letters that related to hours
|
||||
return result ? result.substring(3) : '';
|
||||
};
|
||||
}
|
||||
|
||||
function hour12Modify(
|
||||
options: Intl.DateTimeFormatOptions, value: boolean): Intl.DateTimeFormatOptions {
|
||||
options.hour12 = value;
|
||||
return options;
|
||||
}
|
||||
|
||||
function digitCondition(prop: string, len: number): Intl.DateTimeFormatOptions {
|
||||
const result: {[k: string]: string} = {};
|
||||
result[prop] = len === 2 ? '2-digit' : 'numeric';
|
||||
return result;
|
||||
}
|
||||
|
||||
function nameCondition(prop: string, len: number): Intl.DateTimeFormatOptions {
|
||||
const result: {[k: string]: string} = {};
|
||||
if (len < 4) {
|
||||
result[prop] = len > 1 ? 'short' : 'narrow';
|
||||
} else {
|
||||
result[prop] = 'long';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function combine(options: Intl.DateTimeFormatOptions[]): Intl.DateTimeFormatOptions {
|
||||
return options.reduce((merged, opt) => ({...merged, ...opt}), {});
|
||||
}
|
||||
|
||||
function datePartGetterFactory(ret: Intl.DateTimeFormatOptions): DateFormatterFn {
|
||||
return (date: Date, locale: string): string => intlDateFormat(date, locale, ret);
|
||||
}
|
||||
|
||||
const DATE_FORMATTER_CACHE = new Map<string, string[]>();
|
||||
|
||||
function dateFormatter(format: string, date: Date, locale: string): string {
|
||||
const fn = PATTERN_ALIASES[format];
|
||||
|
||||
if (fn) return fn(date, locale);
|
||||
|
||||
const cacheKey = format;
|
||||
let parts = DATE_FORMATTER_CACHE.get(cacheKey);
|
||||
|
||||
if (!parts) {
|
||||
parts = [];
|
||||
let match: RegExpExecArray|null;
|
||||
DATE_FORMATS_SPLIT.exec(format);
|
||||
|
||||
let _format: string|null = format;
|
||||
while (_format) {
|
||||
match = DATE_FORMATS_SPLIT.exec(_format);
|
||||
if (match) {
|
||||
parts = parts.concat(match.slice(1));
|
||||
_format = parts.pop() !;
|
||||
} else {
|
||||
parts.push(_format);
|
||||
_format = null;
|
||||
}
|
||||
}
|
||||
|
||||
DATE_FORMATTER_CACHE.set(cacheKey, parts);
|
||||
}
|
||||
|
||||
return parts.reduce((text, part) => {
|
||||
const fn = DATE_FORMATS[part];
|
||||
return text + (fn ? fn(date, locale) : partToTime(part));
|
||||
}, '');
|
||||
}
|
||||
|
||||
function partToTime(part: string): string {
|
||||
return part === '\'\'' ? '\'' : part.replace(/(^'|'$)/g, '').replace(/''/g, '\'');
|
||||
}
|
||||
|
||||
export class DateFormatter {
|
||||
static format(date: Date, locale: string, pattern: string): string {
|
||||
return dateFormatter(pattern, date, locale);
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Inject, LOCALE_ID, Pipe, PipeTransform, Type} from '@angular/core';
|
||||
import {NUMBER_FORMAT_REGEXP, parseIntAutoRadix} from '../../i18n/format_number';
|
||||
import {NumberFormatStyle} from '../../i18n/locale_data_api';
|
||||
import {invalidPipeArgumentError} from '../invalid_pipe_argument_error';
|
||||
import {NumberFormatter} from './intl';
|
||||
|
||||
function formatNumber(
|
||||
pipe: Type<any>, locale: string, value: number | string, style: NumberFormatStyle,
|
||||
digits?: string | null, currency: string | null = null,
|
||||
currencyAsSymbol: boolean = false): string|null {
|
||||
if (value == null) return null;
|
||||
|
||||
// Convert strings to numbers
|
||||
value = typeof value === 'string' && !isNaN(+value - parseFloat(value)) ? +value : value;
|
||||
if (typeof value !== 'number') {
|
||||
throw invalidPipeArgumentError(pipe, value);
|
||||
}
|
||||
|
||||
let minInt: number|undefined;
|
||||
let minFraction: number|undefined;
|
||||
let maxFraction: number|undefined;
|
||||
if (style !== NumberFormatStyle.Currency) {
|
||||
// rely on Intl default for currency
|
||||
minInt = 1;
|
||||
minFraction = 0;
|
||||
maxFraction = 3;
|
||||
}
|
||||
|
||||
if (digits) {
|
||||
const parts = digits.match(NUMBER_FORMAT_REGEXP);
|
||||
if (parts === null) {
|
||||
throw new Error(`${digits} is not a valid digit info for number pipes`);
|
||||
}
|
||||
if (parts[1] != null) { // min integer digits
|
||||
minInt = parseIntAutoRadix(parts[1]);
|
||||
}
|
||||
if (parts[3] != null) { // min fraction digits
|
||||
minFraction = parseIntAutoRadix(parts[3]);
|
||||
}
|
||||
if (parts[5] != null) { // max fraction digits
|
||||
maxFraction = parseIntAutoRadix(parts[5]);
|
||||
}
|
||||
}
|
||||
|
||||
return NumberFormatter.format(value, locale, style, {
|
||||
minimumIntegerDigits: minInt,
|
||||
minimumFractionDigits: minFraction,
|
||||
maximumFractionDigits: maxFraction,
|
||||
currency: currency,
|
||||
currencyAsSymbol: currencyAsSymbol,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a number as text. Group sizing and separator and other locale-specific
|
||||
* configurations are based on the active locale.
|
||||
*
|
||||
* where `expression` is a number:
|
||||
* - `digitInfo` is a `string` which has a following format: <br>
|
||||
* <code>{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}</code>
|
||||
* - `minIntegerDigits` is the minimum number of integer digits to use. Defaults to `1`.
|
||||
* - `minFractionDigits` is the minimum number of digits after fraction. Defaults to `0`.
|
||||
* - `maxFractionDigits` is the maximum number of digits after fraction. Defaults to `3`.
|
||||
*
|
||||
* For more information on the acceptable range for each of these numbers and other
|
||||
* details see your native internationalization library.
|
||||
*
|
||||
* WARNING: this pipe uses the Internationalization API which is not yet available in all browsers
|
||||
* and may require a polyfill. See [Browser Support](guide/browser-support) for details.
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* {@example common/pipes/ts/number_pipe.ts region='DeprecatedNumberPipe'}
|
||||
*
|
||||
* @ngModule CommonModule
|
||||
* @publicApi
|
||||
*/
|
||||
@Pipe({name: 'number'})
|
||||
export class DeprecatedDecimalPipe implements PipeTransform {
|
||||
constructor(@Inject(LOCALE_ID) private _locale: string) {}
|
||||
|
||||
transform(value: any, digits?: string): string|null {
|
||||
return formatNumber(
|
||||
DeprecatedDecimalPipe, this._locale, value, NumberFormatStyle.Decimal, digits);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngModule CommonModule
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* Formats a number as percentage according to locale rules.
|
||||
*
|
||||
* - `digitInfo` See {@link DecimalPipe} for detailed description.
|
||||
*
|
||||
* WARNING: this pipe uses the Internationalization API which is not yet available in all browsers
|
||||
* and may require a polyfill. See [Browser Support](guide/browser-support) for details.
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* {@example common/pipes/ts/percent_pipe.ts region='DeprecatedPercentPipe'}
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
@Pipe({name: 'percent'})
|
||||
export class DeprecatedPercentPipe implements PipeTransform {
|
||||
constructor(@Inject(LOCALE_ID) private _locale: string) {}
|
||||
|
||||
transform(value: any, digits?: string): string|null {
|
||||
return formatNumber(
|
||||
DeprecatedPercentPipe, this._locale, value, NumberFormatStyle.Percent, digits);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngModule CommonModule
|
||||
* @description
|
||||
*
|
||||
* Formats a number as currency using locale rules.
|
||||
*
|
||||
* Use `currency` to format a number as currency.
|
||||
*
|
||||
* - `currencyCode` is the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency code, such
|
||||
* as `USD` for the US dollar and `EUR` for the euro.
|
||||
* - `symbolDisplay` is a boolean indicating whether to use the currency symbol or code.
|
||||
* - `true`: use symbol (e.g. `$`).
|
||||
* - `false`(default): use code (e.g. `USD`).
|
||||
* - `digitInfo` See {@link DecimalPipe} for detailed description.
|
||||
*
|
||||
* WARNING: this pipe uses the Internationalization API which is not yet available in all browsers
|
||||
* and may require a polyfill. See [Browser Support](guide/browser-support) for details.
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* {@example common/pipes/ts/currency_pipe.ts region='DeprecatedCurrencyPipe'}
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
@Pipe({name: 'currency'})
|
||||
export class DeprecatedCurrencyPipe implements PipeTransform {
|
||||
constructor(@Inject(LOCALE_ID) private _locale: string) {}
|
||||
|
||||
transform(
|
||||
value: any, currencyCode: string = 'USD', symbolDisplay: boolean = false,
|
||||
digits?: string): string|null {
|
||||
return formatNumber(
|
||||
DeprecatedCurrencyPipe, this._locale, value, NumberFormatStyle.Currency, digits,
|
||||
currencyCode, symbolDisplay);
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
|
||||
import {DeprecatedI18NPipesModule, Plural} from '@angular/common';
|
||||
import {DEPRECATED_PLURAL_FN, getPluralCase} from '@angular/common/src/i18n/localization';
|
||||
import {TestBed, inject} from '@angular/core/testing';
|
||||
|
||||
describe('DeprecatedI18NPipesModule', () => {
|
||||
beforeEach(() => { TestBed.configureTestingModule({imports: [DeprecatedI18NPipesModule]}); });
|
||||
|
||||
it('should define the token DEPRECATED_PLURAL_FN',
|
||||
inject(
|
||||
[DEPRECATED_PLURAL_FN],
|
||||
(injectedGetPluralCase?: (locale: string, value: number | string) => Plural) => {
|
||||
expect(injectedGetPluralCase).toEqual(getPluralCase);
|
||||
}));
|
||||
});
|
|
@ -12,8 +12,7 @@ import localeZgh from '@angular/common/locales/zgh';
|
|||
import localeFr from '@angular/common/locales/fr';
|
||||
import {LOCALE_ID} from '@angular/core';
|
||||
import {TestBed, inject} from '@angular/core/testing';
|
||||
import {NgLocaleLocalization, NgLocalization, getPluralCategory, DEPRECATED_PLURAL_FN, getPluralCase} from '@angular/common/src/i18n/localization';
|
||||
import {Plural} from '@angular/common';
|
||||
import {NgLocaleLocalization, NgLocalization, getPluralCategory} from '@angular/common/src/i18n/localization';
|
||||
import {registerLocaleData} from '../../src/i18n/locale_data';
|
||||
|
||||
{
|
||||
|
@ -46,19 +45,6 @@ import {registerLocaleData} from '../../src/i18n/locale_data';
|
|||
roTests();
|
||||
});
|
||||
|
||||
describe('ro with v4 plurals', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{provide: LOCALE_ID, useValue: 'ro'},
|
||||
{provide: DEPRECATED_PLURAL_FN, useValue: getPluralCase}
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
roTests();
|
||||
});
|
||||
|
||||
function srTests() {
|
||||
it('should return plural cases for the provided locale',
|
||||
inject([NgLocalization], (l10n: NgLocalization) => {
|
||||
|
@ -82,110 +68,90 @@ import {registerLocaleData} from '../../src/i18n/locale_data';
|
|||
|
||||
srTests();
|
||||
});
|
||||
|
||||
describe('sr with v4 plurals', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{provide: LOCALE_ID, useValue: 'sr'},
|
||||
{provide: DEPRECATED_PLURAL_FN, useValue: getPluralCase}
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
srTests();
|
||||
});
|
||||
});
|
||||
|
||||
describe('NgLocaleLocalization', () => {
|
||||
function ngLocaleLocalizationTests(
|
||||
getPluralCase: ((locale: string, value: number | string) => Plural) | null) {
|
||||
it('should return the correct values for the "en" locale', () => {
|
||||
const l10n = new NgLocaleLocalization('en-US', getPluralCase);
|
||||
it('should return the correct values for the "en" locale', () => {
|
||||
const l10n = new NgLocaleLocalization('en-US');
|
||||
|
||||
expect(l10n.getPluralCategory(0)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(2)).toEqual('other');
|
||||
});
|
||||
expect(l10n.getPluralCategory(0)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(2)).toEqual('other');
|
||||
});
|
||||
|
||||
it('should return the correct values for the "ro" locale', () => {
|
||||
const l10n = new NgLocaleLocalization('ro', getPluralCase);
|
||||
it('should return the correct values for the "ro" locale', () => {
|
||||
const l10n = new NgLocaleLocalization('ro');
|
||||
|
||||
expect(l10n.getPluralCategory(0)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(2)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(12)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(23)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(1212)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(1223)).toEqual('other');
|
||||
});
|
||||
expect(l10n.getPluralCategory(0)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(2)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(12)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(23)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(1212)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(1223)).toEqual('other');
|
||||
});
|
||||
|
||||
it('should return the correct values for the "sr" locale', () => {
|
||||
const l10n = new NgLocaleLocalization('sr', getPluralCase);
|
||||
it('should return the correct values for the "sr" locale', () => {
|
||||
const l10n = new NgLocaleLocalization('sr');
|
||||
|
||||
expect(l10n.getPluralCategory(1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(31)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(0.1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(1.1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(2.1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(31)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(0.1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(1.1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(2.1)).toEqual('one');
|
||||
|
||||
expect(l10n.getPluralCategory(3)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(33)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(0.2)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(0.3)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(0.4)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(2.2)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(3)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(33)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(0.2)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(0.3)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(0.4)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(2.2)).toEqual('few');
|
||||
|
||||
expect(l10n.getPluralCategory(2.11)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(2.12)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(2.13)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(2.14)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(2.15)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(2.11)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(2.12)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(2.13)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(2.14)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(2.15)).toEqual('other');
|
||||
|
||||
expect(l10n.getPluralCategory(0)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(5)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(10)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(35)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(37)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(40)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(0.0)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(0.5)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(0.6)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(0)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(5)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(10)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(35)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(37)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(40)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(0.0)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(0.5)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(0.6)).toEqual('other');
|
||||
|
||||
expect(l10n.getPluralCategory(2)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(2.1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(2.2)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(2.3)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(2.4)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(2.5)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(2)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(2.1)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(2.2)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(2.3)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(2.4)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(2.5)).toEqual('other');
|
||||
|
||||
expect(l10n.getPluralCategory(20)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(21)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(22)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(23)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(24)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(25)).toEqual('other');
|
||||
});
|
||||
expect(l10n.getPluralCategory(20)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(21)).toEqual('one');
|
||||
expect(l10n.getPluralCategory(22)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(23)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(24)).toEqual('few');
|
||||
expect(l10n.getPluralCategory(25)).toEqual('other');
|
||||
});
|
||||
|
||||
it('should return the default value for a locale with no rule', () => {
|
||||
const l10n = new NgLocaleLocalization('zgh', getPluralCase);
|
||||
it('should return the default value for a locale with no rule', () => {
|
||||
const l10n = new NgLocaleLocalization('zgh');
|
||||
|
||||
expect(l10n.getPluralCategory(0)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(1)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(3)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(5)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(10)).toEqual('other');
|
||||
});
|
||||
}
|
||||
|
||||
ngLocaleLocalizationTests(null);
|
||||
ngLocaleLocalizationTests(getPluralCase);
|
||||
expect(l10n.getPluralCategory(0)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(1)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(3)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(5)).toEqual('other');
|
||||
expect(l10n.getPluralCategory(10)).toEqual('other');
|
||||
});
|
||||
});
|
||||
|
||||
function pluralCategoryTests(
|
||||
getPluralCase: ((locale: string, value: number | string) => Plural) | null) {
|
||||
describe('getPluralCategory', () => {
|
||||
it('should return plural category', () => {
|
||||
const l10n = new NgLocaleLocalization('fr', getPluralCase);
|
||||
const l10n = new NgLocaleLocalization('fr');
|
||||
|
||||
expect(getPluralCategory(0, ['one', 'other'], l10n)).toEqual('one');
|
||||
expect(getPluralCategory(1, ['one', 'other'], l10n)).toEqual('one');
|
||||
|
@ -193,7 +159,7 @@ import {registerLocaleData} from '../../src/i18n/locale_data';
|
|||
});
|
||||
|
||||
it('should return discrete cases', () => {
|
||||
const l10n = new NgLocaleLocalization('fr', getPluralCase);
|
||||
const l10n = new NgLocaleLocalization('fr');
|
||||
|
||||
expect(getPluralCategory(0, ['one', 'other', '=0'], l10n)).toEqual('=0');
|
||||
expect(getPluralCategory(1, ['one', 'other'], l10n)).toEqual('one');
|
||||
|
@ -202,7 +168,7 @@ import {registerLocaleData} from '../../src/i18n/locale_data';
|
|||
});
|
||||
|
||||
it('should fallback to other when the case is not present', () => {
|
||||
const l10n = new NgLocaleLocalization('ro', getPluralCase);
|
||||
const l10n = new NgLocaleLocalization('ro');
|
||||
expect(getPluralCategory(1, ['one', 'other'], l10n)).toEqual('one');
|
||||
// 2 -> 'few'
|
||||
expect(getPluralCategory(2, ['one', 'other'], l10n)).toEqual('other');
|
||||
|
@ -211,17 +177,12 @@ import {registerLocaleData} from '../../src/i18n/locale_data';
|
|||
describe('errors', () => {
|
||||
it('should report an error when the "other" category is not present', () => {
|
||||
expect(() => {
|
||||
const l10n = new NgLocaleLocalization('ro', getPluralCase);
|
||||
const l10n = new NgLocaleLocalization('ro');
|
||||
// 2 -> 'few'
|
||||
getPluralCategory(2, ['one'], l10n);
|
||||
}).toThrowError('No plural message found for value "2"');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('getPluralCategory', () => {
|
||||
pluralCategoryTests(null);
|
||||
pluralCategoryTests(getPluralCase);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,211 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {DeprecatedDatePipe} from '@angular/common';
|
||||
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
|
||||
import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_reflector';
|
||||
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
|
||||
|
||||
{
|
||||
describe('DeprecatedDatePipe', () => {
|
||||
let date: Date;
|
||||
const isoStringWithoutTime = '2015-01-01';
|
||||
let pipe: DeprecatedDatePipe;
|
||||
|
||||
// Check the transformation of a date into a pattern
|
||||
function expectDateFormatAs(date: Date | string, pattern: any, output: string): void {
|
||||
// disabled on chrome mobile because of the following bug affecting the intl API
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=796583
|
||||
// the android 7 emulator of saucelabs uses chrome mobile 63
|
||||
if (!browserDetection.isAndroid && !browserDetection.isWebkit) {
|
||||
expect(pipe.transform(date, pattern)).toEqual(output);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: reactivate the disabled expectations once emulators are fixed in SauceLabs
|
||||
// In some old versions of Chrome in Android emulators, time formatting returns dates in the
|
||||
// timezone of the VM host,
|
||||
// instead of the device timezone. Same symptoms as
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=406382
|
||||
// This happens locally and in SauceLabs, so some checks are disabled to avoid failures.
|
||||
// Tracking issue: https://github.com/angular/angular/issues/11187
|
||||
|
||||
beforeEach(() => {
|
||||
date = new Date(2015, 5, 15, 9, 3, 1);
|
||||
pipe = new DeprecatedDatePipe('en-US');
|
||||
});
|
||||
|
||||
it('should be marked as pure', () => {
|
||||
expect(new PipeResolver(new JitReflector()).resolve(DeprecatedDatePipe) !.pure).toEqual(true);
|
||||
});
|
||||
|
||||
describe('supports', () => {
|
||||
it('should support date', () => { expect(() => pipe.transform(date)).not.toThrow(); });
|
||||
|
||||
it('should support int', () => { expect(() => pipe.transform(123456789)).not.toThrow(); });
|
||||
|
||||
it('should support numeric strings',
|
||||
() => { expect(() => pipe.transform('123456789')).not.toThrow(); });
|
||||
|
||||
it('should support decimal strings',
|
||||
() => { expect(() => pipe.transform('123456789.11')).not.toThrow(); });
|
||||
|
||||
it('should support ISO string',
|
||||
() => expect(() => pipe.transform('2015-06-15T21:43:11Z')).not.toThrow());
|
||||
|
||||
it('should return null for empty string', () => expect(pipe.transform('')).toEqual(null));
|
||||
|
||||
it('should return null for NaN', () => expect(pipe.transform(Number.NaN)).toEqual(null));
|
||||
|
||||
it('should support ISO string without time',
|
||||
() => { expect(() => pipe.transform(isoStringWithoutTime)).not.toThrow(); });
|
||||
|
||||
it('should not support other objects',
|
||||
() => expect(() => pipe.transform({})).toThrowError(/InvalidPipeArgument/));
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should format each component correctly', () => {
|
||||
const dateFixtures: any = {
|
||||
'y': '2015',
|
||||
'yy': '15',
|
||||
'M': '6',
|
||||
'MM': '06',
|
||||
'MMM': 'Jun',
|
||||
'MMMM': 'June',
|
||||
'd': '15',
|
||||
'dd': '15',
|
||||
'EEE': 'Mon',
|
||||
'EEEE': 'Monday'
|
||||
};
|
||||
|
||||
const isoStringWithoutTimeFixtures: any = {
|
||||
'y': '2015',
|
||||
'yy': '15',
|
||||
'M': '1',
|
||||
'MM': '01',
|
||||
'MMM': 'Jan',
|
||||
'MMMM': 'January',
|
||||
'd': '1',
|
||||
'dd': '01',
|
||||
'EEE': 'Thu',
|
||||
'EEEE': 'Thursday'
|
||||
};
|
||||
|
||||
if (!browserDetection.isOldChrome) {
|
||||
dateFixtures['h'] = '9';
|
||||
dateFixtures['hh'] = '09';
|
||||
dateFixtures['j'] = '9 AM';
|
||||
isoStringWithoutTimeFixtures['h'] = '12';
|
||||
isoStringWithoutTimeFixtures['hh'] = '12';
|
||||
isoStringWithoutTimeFixtures['j'] = '12 AM';
|
||||
}
|
||||
|
||||
// IE and Edge can't format a date to minutes and seconds without hours
|
||||
if (!browserDetection.isEdge && !browserDetection.isIE ||
|
||||
!browserDetection.supportsNativeIntlApi) {
|
||||
if (!browserDetection.isOldChrome) {
|
||||
dateFixtures['HH'] = '09';
|
||||
isoStringWithoutTimeFixtures['HH'] = '00';
|
||||
}
|
||||
dateFixtures['E'] = 'M';
|
||||
dateFixtures['L'] = 'J';
|
||||
dateFixtures['m'] = '3';
|
||||
dateFixtures['s'] = '1';
|
||||
dateFixtures['mm'] = '03';
|
||||
dateFixtures['ss'] = '01';
|
||||
isoStringWithoutTimeFixtures['m'] = '0';
|
||||
isoStringWithoutTimeFixtures['s'] = '0';
|
||||
isoStringWithoutTimeFixtures['mm'] = '00';
|
||||
isoStringWithoutTimeFixtures['ss'] = '00';
|
||||
}
|
||||
|
||||
Object.keys(dateFixtures).forEach((pattern: string) => {
|
||||
expectDateFormatAs(date, pattern, dateFixtures[pattern]);
|
||||
});
|
||||
|
||||
if (!browserDetection.isOldChrome) {
|
||||
Object.keys(isoStringWithoutTimeFixtures).forEach((pattern: string) => {
|
||||
expectDateFormatAs(
|
||||
isoStringWithoutTime, pattern, isoStringWithoutTimeFixtures[pattern]);
|
||||
});
|
||||
}
|
||||
|
||||
expect(pipe.transform(date, 'Z')).toBeDefined();
|
||||
});
|
||||
|
||||
it('should format common multi component patterns', () => {
|
||||
const dateFixtures: any = {
|
||||
'EEE, M/d/y': 'Mon, 6/15/2015',
|
||||
'EEE, M/d': 'Mon, 6/15',
|
||||
'MMM d': 'Jun 15',
|
||||
'dd/MM/yyyy': '15/06/2015',
|
||||
'MM/dd/yyyy': '06/15/2015',
|
||||
'yMEEEd': '20156Mon15',
|
||||
'MEEEd': '6Mon15',
|
||||
'MMMd': 'Jun15',
|
||||
'yMMMMEEEEd': 'Monday, June 15, 2015'
|
||||
};
|
||||
|
||||
// IE and Edge can't format a date to minutes and seconds without hours
|
||||
if (!browserDetection.isEdge && !browserDetection.isIE ||
|
||||
!browserDetection.supportsNativeIntlApi) {
|
||||
dateFixtures['ms'] = '31';
|
||||
}
|
||||
|
||||
if (!browserDetection.isOldChrome) {
|
||||
dateFixtures['jm'] = '9:03 AM';
|
||||
}
|
||||
|
||||
Object.keys(dateFixtures).forEach((pattern: string) => {
|
||||
expectDateFormatAs(date, pattern, dateFixtures[pattern]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should format with pattern aliases', () => {
|
||||
const dateFixtures: any = {
|
||||
'MM/dd/yyyy': '06/15/2015',
|
||||
'fullDate': 'Monday, June 15, 2015',
|
||||
'longDate': 'June 15, 2015',
|
||||
'mediumDate': 'Jun 15, 2015',
|
||||
'shortDate': '6/15/2015'
|
||||
};
|
||||
|
||||
if (!browserDetection.isOldChrome) {
|
||||
// IE and Edge do not add a coma after the year in these 2 cases
|
||||
if ((browserDetection.isEdge || browserDetection.isIE) &&
|
||||
browserDetection.supportsNativeIntlApi) {
|
||||
dateFixtures['medium'] = 'Jun 15, 2015 9:03:01 AM';
|
||||
dateFixtures['short'] = '6/15/2015 9:03 AM';
|
||||
} else {
|
||||
dateFixtures['medium'] = 'Jun 15, 2015, 9:03:01 AM';
|
||||
dateFixtures['short'] = '6/15/2015, 9:03 AM';
|
||||
}
|
||||
}
|
||||
|
||||
if (!browserDetection.isOldChrome) {
|
||||
dateFixtures['mediumTime'] = '9:03:01 AM';
|
||||
dateFixtures['shortTime'] = '9:03 AM';
|
||||
}
|
||||
|
||||
Object.keys(dateFixtures).forEach((pattern: string) => {
|
||||
expectDateFormatAs(date, pattern, dateFixtures[pattern]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should format invalid in IE ISO date',
|
||||
() => expect(pipe.transform('2017-01-11T09:25:14.014-0500')).toEqual('Jan 11, 2017'));
|
||||
|
||||
it('should format invalid in Safari ISO date',
|
||||
() => expect(pipe.transform('2017-01-20T19:00:00+0000')).toEqual('Jan 20, 2017'));
|
||||
|
||||
it('should remove bidi control characters',
|
||||
() => expect(pipe.transform(date, 'MM/dd/yyyy') !.length).toEqual(10));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {DeprecatedCurrencyPipe, DeprecatedDecimalPipe, DeprecatedPercentPipe} from '@angular/common';
|
||||
import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testing_internal';
|
||||
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
|
||||
|
||||
(function() {
|
||||
function isNumeric(value: any): boolean { return !isNaN(value - parseFloat(value)); }
|
||||
|
||||
// Between the symbol and the number, Edge adds a no breaking space and IE11 adds a standard space
|
||||
function normalize(s: string): string { return s.replace(/\u00A0| /g, ''); }
|
||||
|
||||
describe('Number pipes', () => {
|
||||
describe('DeprecatedDecimalPipe', () => {
|
||||
let pipe: DeprecatedDecimalPipe;
|
||||
|
||||
beforeEach(() => { pipe = new DeprecatedDecimalPipe('en-US'); });
|
||||
|
||||
describe('transform', () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
expect(pipe.transform(12345)).toEqual('12,345');
|
||||
expect(pipe.transform(123, '.2')).toEqual('123.00');
|
||||
expect(pipe.transform(1, '3.')).toEqual('001');
|
||||
expect(pipe.transform(1.1, '3.4-5')).toEqual('001.1000');
|
||||
expect(pipe.transform(1.123456, '3.4-5')).toEqual('001.12346');
|
||||
expect(pipe.transform(1.1234)).toEqual('1.123');
|
||||
});
|
||||
|
||||
it('should support strings', () => {
|
||||
expect(pipe.transform('12345')).toEqual('12,345');
|
||||
expect(pipe.transform('123', '.2')).toEqual('123.00');
|
||||
expect(pipe.transform('1', '3.')).toEqual('001');
|
||||
expect(pipe.transform('1.1', '3.4-5')).toEqual('001.1000');
|
||||
expect(pipe.transform('1.123456', '3.4-5')).toEqual('001.12346');
|
||||
expect(pipe.transform('1.1234')).toEqual('1.123');
|
||||
});
|
||||
|
||||
it('should not support other objects', () => {
|
||||
expect(() => pipe.transform(new Object())).toThrowError();
|
||||
expect(() => pipe.transform('123abc')).toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('DeprecatedPercentPipe', () => {
|
||||
let pipe: DeprecatedPercentPipe;
|
||||
|
||||
beforeEach(() => { pipe = new DeprecatedPercentPipe('en-US'); });
|
||||
|
||||
describe('transform', () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
expect(normalize(pipe.transform(1.23) !)).toEqual('123%');
|
||||
expect(normalize(pipe.transform(1.2, '.2') !)).toEqual('120.00%');
|
||||
});
|
||||
|
||||
it('should not support other objects',
|
||||
() => { expect(() => pipe.transform(new Object())).toThrowError(); });
|
||||
});
|
||||
});
|
||||
|
||||
describe('DeprecatedCurrencyPipe', () => {
|
||||
let pipe: DeprecatedCurrencyPipe;
|
||||
|
||||
beforeEach(() => { pipe = new DeprecatedCurrencyPipe('en-US'); });
|
||||
|
||||
describe('transform', () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
// In old Chrome, default formatiing for USD is different
|
||||
if (browserDetection.isOldChrome) {
|
||||
expect(normalize(pipe.transform(123) !)).toEqual('USD123');
|
||||
} else {
|
||||
expect(normalize(pipe.transform(123) !)).toEqual('USD123.00');
|
||||
}
|
||||
expect(normalize(pipe.transform(12, 'EUR', false, '.1') !)).toEqual('EUR12.0');
|
||||
expect(normalize(pipe.transform(5.1234, 'USD', false, '.0-3') !)).toEqual('USD5.123');
|
||||
});
|
||||
|
||||
it('should not support other objects',
|
||||
() => { expect(() => pipe.transform(new Object())).toThrowError(); });
|
||||
});
|
||||
});
|
||||
|
||||
describe('isNumeric', () => {
|
||||
it('should return true when passing correct numeric string',
|
||||
() => { expect(isNumeric('2')).toBe(true); });
|
||||
|
||||
it('should return true when passing correct double string',
|
||||
() => { expect(isNumeric('1.123')).toBe(true); });
|
||||
|
||||
it('should return true when passing correct negative string',
|
||||
() => { expect(isNumeric('-2')).toBe(true); });
|
||||
|
||||
it('should return true when passing correct scientific notation string',
|
||||
() => { expect(isNumeric('1e5')).toBe(true); });
|
||||
|
||||
it('should return false when passing incorrect numeric',
|
||||
() => { expect(isNumeric('a')).toBe(false); });
|
||||
|
||||
it('should return false when passing parseable but non numeric',
|
||||
() => { expect(isNumeric('2a')).toBe(false); });
|
||||
});
|
||||
});
|
||||
})();
|
|
@ -27,30 +27,6 @@ export declare class DecimalPipe implements PipeTransform {
|
|||
transform(value: any, digitsInfo?: string, locale?: string): string | null;
|
||||
}
|
||||
|
||||
export declare class DeprecatedCurrencyPipe implements PipeTransform {
|
||||
constructor(_locale: string);
|
||||
transform(value: any, currencyCode?: string, symbolDisplay?: boolean, digits?: string): string | null;
|
||||
}
|
||||
|
||||
export declare class DeprecatedDatePipe implements PipeTransform {
|
||||
constructor(_locale: string);
|
||||
transform(value: any, pattern?: string): string | null;
|
||||
}
|
||||
|
||||
export declare class DeprecatedDecimalPipe implements PipeTransform {
|
||||
constructor(_locale: string);
|
||||
transform(value: any, digits?: string): string | null;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
export declare class DeprecatedI18NPipesModule {
|
||||
}
|
||||
|
||||
export declare class DeprecatedPercentPipe implements PipeTransform {
|
||||
constructor(_locale: string);
|
||||
transform(value: any, digits?: string): string | null;
|
||||
}
|
||||
|
||||
export declare const DOCUMENT: InjectionToken<Document>;
|
||||
|
||||
export declare function formatCurrency(value: number, locale: string, currency: string, currencyCode?: string, digitsInfo?: string): string;
|
||||
|
@ -273,10 +249,8 @@ export declare class NgIfContext {
|
|||
}
|
||||
|
||||
export declare class NgLocaleLocalization extends NgLocalization {
|
||||
/** @deprecated */ protected deprecatedPluralFn?: ((locale: string, value: string | number) => Plural) | null | undefined;
|
||||
protected locale: string;
|
||||
constructor(locale: string,
|
||||
/** @deprecated */ deprecatedPluralFn?: ((locale: string, value: string | number) => Plural) | null | undefined);
|
||||
constructor(locale: string);
|
||||
getPluralCategory(value: any, locale?: string): string;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue