Skip to content

Commit

Permalink
feat(core): remove dependency to intl API
Browse files Browse the repository at this point in the history
BREAKING CHANGE: all i18n pipes have been updated to not require the intl API anymore. Some results might vary, see the document to update from v4 to v5 for more information.

Fixes angular#10809, angular#9524, angular#7008, angular#9324, angular#7590, angular#6724, angular#3429, angular#17576, angular#17478, angular#17319, angular#17200, angular#16838, angular#16624, angular#16625, angular#16591, angular#14131, angular#12632, angular#11376, angular#11187
  • Loading branch information
ocombe committed Jul 20, 2017
1 parent a18485c commit cf41ddf
Show file tree
Hide file tree
Showing 27 changed files with 2,368 additions and 680 deletions.
7 changes: 5 additions & 2 deletions packages/common/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
* Entry point for all public APIs of the common package.
*/
export * from './location/index';
export {NgLocaleLocalization, NgLocalization} from './localization';
export {NgLocaleLocalization, NgLocalization} from './i18n/localization';
export {AVAILABLE_LOCALES} from './i18n/available_locales';
export {CURRENCIES} from './i18n/currencies';
export {parseCookieValue as ɵparseCookieValue} from './cookie';
export {CommonModule} from './common_module';
export {CommonModule, DeprecatedCommonModule} from './common_module';
export {NgClass, NgFor, NgForOf, NgForOfContext, NgIf, NgIfContext, NgPlural, NgPluralCase, NgStyle, 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} 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';
39 changes: 34 additions & 5 deletions packages/common/src/common_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@

import {NgModule} from '@angular/core';

import {COMMON_DEPRECATED_DIRECTIVES, COMMON_DIRECTIVES} from './directives/index';
import {NgLocaleLocalization, NgLocalization} from './localization';
import {COMMON_PIPES} from './pipes/index';
import {COMMON_DIRECTIVES} from './directives/index';
import {NgLocaleLocalization, NgLocalization} from './i18n/localization';
import {COMMON_DEPRECATED_I18N_PIPES} from './pipes/deprecated/index';
import {COMMON_I18N_PIPES, COMMON_PIPES} from './pipes/index';

@NgModule({
declarations: [COMMON_DIRECTIVES, COMMON_PIPES],
exports: [COMMON_DIRECTIVES, COMMON_PIPES]
})
export class CommonBaseModule {
}

// Note: This does not contain the location providers,
// as they need some platform specific implementations to work.
Expand All @@ -21,11 +28,33 @@ import {COMMON_PIPES} from './pipes/index';
* @stable
*/
@NgModule({
declarations: [COMMON_DIRECTIVES, COMMON_PIPES],
exports: [COMMON_DIRECTIVES, COMMON_PIPES],
imports: [CommonBaseModule],
declarations: [COMMON_I18N_PIPES],
exports: [COMMON_I18N_PIPES, CommonBaseModule],
providers: [
{provide: NgLocalization, useClass: NgLocaleLocalization},
],
})
export class CommonModule {
}

// Note: This does not contain the location providers,
// as they need some platform specific implementations to work.
/**
* The module that includes all the basic Angular directives like {@link NgIf}, {@link NgForOf}, ...
* It includes the deprecated i18n pipes that will be removed in Angular v6 in favor of the new
* i18n pipes that don't use the intl api.
*
* @stable
* @deprecated use CommonModule instead
*/
@NgModule({
imports: [CommonBaseModule],
declarations: [COMMON_DEPRECATED_I18N_PIPES],
exports: [COMMON_DEPRECATED_I18N_PIPES, CommonBaseModule],
providers: [
{provide: NgLocalization, useClass: NgLocaleLocalization},
],
})
export class DeprecatedCommonModule {
}
2 changes: 1 addition & 1 deletion packages/common/src/directives/ng_plural.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {Attribute, Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core';

import {NgLocalization, getPluralCategory} from '../localization';
import {NgLocalization, getPluralCategory} from '../i18n/localization';

import {SwitchView} from './ng_switch';

Expand Down
130 changes: 130 additions & 0 deletions packages/common/src/i18n/localization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/**
* @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, Injectable, LOCALE_DATA, LOCALE_ID, NgLocale, Optional, Plural} from '@angular/core';
import {AVAILABLE_LOCALES} from './available_locales';
import {NgLocaleEn} from './data/locale_en';


/**
* @experimental
*/
export abstract class NgLocalization {
abstract getPluralCategory(value: any, locale?: string): string;
}


/**
* Returns the plural category for a given value.
* - "=value" when the case exists,
* - the plural category otherwise
*
* @internal
*/
export function getPluralCategory(
value: number, cases: string[], ngLocalization: NgLocalization, locale?: string): string {
let key = `=${value}`;

if (cases.indexOf(key) > -1) {
return key;
}

key = ngLocalization.getPluralCategory(value, locale);

if (cases.indexOf(key) > -1) {
return key;
}

if (cases.indexOf('other') > -1) {
return 'other';
}

throw new Error(`No plural message found for value "${value}"`);
}

/**
* Returns the plural case based on the locale
*
* @experimental
*/
@Injectable()
export class NgLocaleLocalization extends NgLocalization {
constructor(
@Inject(LOCALE_ID) protected locale: string,
@Optional() @Inject(LOCALE_DATA) protected localeData: NgLocale[]) {
super();
}

getPluralCategory(value: any, locale?: string): string {
const localeDatum = findNgLocale(locale || this.locale, this.localeData);
const plural = localeDatum.getPluralCase(value);

switch (plural) {
case Plural.Zero:
return 'zero';
case Plural.One:
return 'one';
case Plural.Two:
return 'two';
case Plural.Few:
return 'few';
case Plural.Many:
return 'many';
default:
return 'other';
}
}
}

/**
* Returns the closest existing locale or null
* ie: "en-US" will return "en", and "fr_ca" will return "fr-CA"
*/
function getNormalizedLocale(locale: string): string {
let normalizedLocale = locale.replace('_', '-');
const match =
AVAILABLE_LOCALES.find((l: string) => l.toLocaleLowerCase() === locale.toLocaleLowerCase());

if (match) {
normalizedLocale = match;
} else {
const parentLocale = normalizedLocale.split('-')[0].toLocaleLowerCase();
if (AVAILABLE_LOCALES.find((l: string) => l.toLocaleLowerCase() === parentLocale)) {
normalizedLocale = parentLocale;
} else {
throw new Error(
`"${locale}" is not a valid LOCALE_ID value. See https://github.com/unicode-cldr/cldr-core/blob/master/availableLocales.json for a list of valid locales`);
}
}

return normalizedLocale;
}

/**
* Finds the matching NgLocale for a locale
*
* @internal
* @experimental i18n support is experimental.
*/
export function findNgLocale(locale: string, localeData: NgLocale[] | null): NgLocale {
const currentLocale = getNormalizedLocale(locale);

if (localeData) {
const match =
localeData.find((providedLocale: NgLocale) => providedLocale.localeId === currentLocale);
if (match) {
return match;
}
}

if (currentLocale === 'en') {
return NgLocaleEn;
} else {
throw new Error(`Missing NgLocale data for the locale "${locale}"`);
}
}
Loading

0 comments on commit cf41ddf

Please sign in to comment.