fix(ivy): set LOCALE_ID when using the injector (#31566)

In `BrowserModule` the value of `LOCALE_ID` is defined in the `APPLICATION_MODULE_PROVIDERS` after `APP_INITIALIZER` has run.
This PR ensures that `LOCALE_ID` is also set for ivy at the same moment which allows the application to fetch the locale from a backend (for example).

Fixes #31465

FW-1436 #resolve

PR Close #31566
This commit is contained in:
Olivier Combe 2019-07-15 15:28:07 +02:00 committed by Andrew Kushnir
parent 40a0666651
commit 5296c04f61
11 changed files with 103 additions and 72 deletions

View File

@ -15,6 +15,7 @@ import localeHu from '@angular/common/locales/hu';
import localeSr from '@angular/common/locales/sr';
import localeTh from '@angular/common/locales/th';
import {isDate, toDate, formatDate} from '@angular/common/src/i18n/format_date';
import {ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID} from '@angular/core';
describe('Format date', () => {
describe('toDate', () => {
@ -46,13 +47,12 @@ describe('Format date', () => {
describe('formatDate', () => {
const isoStringWithoutTime = '2015-01-01';
const defaultLocale = 'en-US';
const defaultFormat = 'mediumDate';
let date: Date;
// Check the transformation of a date into a pattern
function expectDateFormatAs(date: Date | string, pattern: any, output: string): void {
expect(formatDate(date, pattern, defaultLocale)).toEqual(output, `pattern: "${pattern}"`);
expect(formatDate(date, pattern, DEFAULT_LOCALE_ID)).toEqual(output, `pattern: "${pattern}"`);
}
beforeAll(() => {
@ -209,7 +209,8 @@ describe('Format date', () => {
};
Object.keys(dateFixtures).forEach((pattern: string) => {
expect(formatDate(date, pattern, defaultLocale, '+0430')).toMatch(dateFixtures[pattern]);
expect(formatDate(date, pattern, DEFAULT_LOCALE_ID, '+0430'))
.toMatch(dateFixtures[pattern]);
});
});
@ -253,22 +254,22 @@ describe('Format date', () => {
};
Object.keys(dateFixtures).forEach((pattern: string) => {
expect(formatDate(date, pattern, defaultLocale)).toMatch(dateFixtures[pattern]);
expect(formatDate(date, pattern, DEFAULT_LOCALE_ID)).toMatch(dateFixtures[pattern]);
});
});
it('should format invalid in IE ISO date',
() => expect(formatDate('2017-01-11T12:00:00.014-0500', defaultFormat, defaultLocale))
() => expect(formatDate('2017-01-11T12:00:00.014-0500', defaultFormat, DEFAULT_LOCALE_ID))
.toEqual('Jan 11, 2017'));
it('should format invalid in Safari ISO date',
() => expect(formatDate('2017-01-20T12:00:00+0000', defaultFormat, defaultLocale))
() => expect(formatDate('2017-01-20T12:00:00+0000', defaultFormat, DEFAULT_LOCALE_ID))
.toEqual('Jan 20, 2017'));
// https://github.com/angular/angular/issues/9524
// https://github.com/angular/angular/issues/9524
it('should format correctly with iso strings that contain time',
() => expect(formatDate('2017-05-07T22:14:39', 'dd-MM-yyyy HH:mm', defaultLocale))
() => expect(formatDate('2017-05-07T22:14:39', 'dd-MM-yyyy HH:mm', DEFAULT_LOCALE_ID))
.toMatch(/07-05-2017 \d{2}:\d{2}/));
// https://github.com/angular/angular/issues/21491
@ -276,22 +277,22 @@ describe('Format date', () => {
// this test only works if the timezone is not in UTC
// which is the case for BrowserStack when we test Safari
if (new Date().getTimezoneOffset() !== 0) {
expect(formatDate('2018-01-11T13:00:00', 'HH', defaultLocale))
.not.toEqual(formatDate('2018-01-11T13:00:00Z', 'HH', defaultLocale));
expect(formatDate('2018-01-11T13:00:00', 'HH', DEFAULT_LOCALE_ID))
.not.toEqual(formatDate('2018-01-11T13:00:00Z', 'HH', DEFAULT_LOCALE_ID));
}
});
// https://github.com/angular/angular/issues/16624
// https://github.com/angular/angular/issues/17478
it('should show the correct time when the timezone is fixed', () => {
expect(formatDate('2017-06-13T10:14:39+0000', 'shortTime', defaultLocale, '+0000'))
expect(formatDate('2017-06-13T10:14:39+0000', 'shortTime', DEFAULT_LOCALE_ID, '+0000'))
.toEqual('10:14 AM');
expect(formatDate('2017-06-13T10:14:39+0000', 'h:mm a', defaultLocale, '+0000'))
expect(formatDate('2017-06-13T10:14:39+0000', 'h:mm a', DEFAULT_LOCALE_ID, '+0000'))
.toEqual('10:14 AM');
});
it('should remove bidi control characters',
() => expect(formatDate(date, 'MM/dd/yyyy', defaultLocale) !.length).toEqual(10));
() => expect(formatDate(date, 'MM/dd/yyyy', DEFAULT_LOCALE_ID) !.length).toEqual(10));
it(`should format the date correctly in various locales`, () => {
expect(formatDate(date, 'short', 'de')).toEqual('15.06.15, 09:03');

View File

@ -12,10 +12,9 @@ import localeFr from '@angular/common/locales/fr';
import localeAr from '@angular/common/locales/ar';
import {formatCurrency, formatNumber, formatPercent, registerLocaleData} from '@angular/common';
import {describe, expect, it} from '@angular/core/testing/src/testing_internal';
import {ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID} from '@angular/core';
describe('Format number', () => {
const defaultLocale = 'en-US';
beforeAll(() => {
registerLocaleData(localeEn);
registerLocaleData(localeEsUS);
@ -26,18 +25,18 @@ describe('Format number', () => {
describe('Number', () => {
describe('transform', () => {
it('should return correct value for numbers', () => {
expect(formatNumber(12345, defaultLocale)).toEqual('12,345');
expect(formatNumber(123, defaultLocale, '.2')).toEqual('123.00');
expect(formatNumber(1, defaultLocale, '3.')).toEqual('001');
expect(formatNumber(1.1, defaultLocale, '3.4-5')).toEqual('001.1000');
expect(formatNumber(1.123456, defaultLocale, '3.4-5')).toEqual('001.12346');
expect(formatNumber(1.1234, defaultLocale)).toEqual('1.123');
expect(formatNumber(1.123456, defaultLocale, '.2')).toEqual('1.123');
expect(formatNumber(1.123456, defaultLocale, '.4')).toEqual('1.1235');
expect(formatNumber(12345, DEFAULT_LOCALE_ID)).toEqual('12,345');
expect(formatNumber(123, DEFAULT_LOCALE_ID, '.2')).toEqual('123.00');
expect(formatNumber(1, DEFAULT_LOCALE_ID, '3.')).toEqual('001');
expect(formatNumber(1.1, DEFAULT_LOCALE_ID, '3.4-5')).toEqual('001.1000');
expect(formatNumber(1.123456, DEFAULT_LOCALE_ID, '3.4-5')).toEqual('001.12346');
expect(formatNumber(1.1234, DEFAULT_LOCALE_ID)).toEqual('1.123');
expect(formatNumber(1.123456, DEFAULT_LOCALE_ID, '.2')).toEqual('1.123');
expect(formatNumber(1.123456, DEFAULT_LOCALE_ID, '.4')).toEqual('1.1235');
});
it('should throw if minFractionDigits is explicitly higher than maxFractionDigits', () => {
expect(() => formatNumber(1.1, defaultLocale, '3.4-2'))
expect(() => formatNumber(1.1, DEFAULT_LOCALE_ID, '3.4-2'))
.toThrowError(/is higher than the maximum/);
});
});
@ -51,27 +50,27 @@ describe('Format number', () => {
describe('Percent', () => {
describe('transform', () => {
it('should return correct value for numbers', () => {
expect(formatPercent(1.23, defaultLocale)).toEqual('123%');
expect(formatPercent(1.2, defaultLocale, '.2')).toEqual('120.00%');
expect(formatPercent(1.2, defaultLocale, '4.2')).toEqual('0,120.00%');
expect(formatPercent(1.23, DEFAULT_LOCALE_ID)).toEqual('123%');
expect(formatPercent(1.2, DEFAULT_LOCALE_ID, '.2')).toEqual('120.00%');
expect(formatPercent(1.2, DEFAULT_LOCALE_ID, '4.2')).toEqual('0,120.00%');
expect(formatPercent(1.2, 'fr', '4.2')).toEqual('0 120,00 %');
expect(formatPercent(1.2, 'ar', '4.2')).toEqual('0,120.00%');
// see issue #20136
expect(formatPercent(0.12345674, defaultLocale, '0.0-10')).toEqual('12.345674%');
expect(formatPercent(0, defaultLocale, '0.0-10')).toEqual('0%');
expect(formatPercent(0.00, defaultLocale, '0.0-10')).toEqual('0%');
expect(formatPercent(1, defaultLocale, '0.0-10')).toEqual('100%');
expect(formatPercent(0.1, defaultLocale, '0.0-10')).toEqual('10%');
expect(formatPercent(0.12, defaultLocale, '0.0-10')).toEqual('12%');
expect(formatPercent(0.123, defaultLocale, '0.0-10')).toEqual('12.3%');
expect(formatPercent(12.3456, defaultLocale, '0.0-10')).toEqual('1,234.56%');
expect(formatPercent(12.345600, defaultLocale, '0.0-10')).toEqual('1,234.56%');
expect(formatPercent(12.345699999, defaultLocale, '0.0-6')).toEqual('1,234.57%');
expect(formatPercent(12.345699999, defaultLocale, '0.4-6')).toEqual('1,234.5700%');
expect(formatPercent(100, defaultLocale, '0.4-6')).toEqual('10,000.0000%');
expect(formatPercent(100, defaultLocale, '0.0-10')).toEqual('10,000%');
expect(formatPercent(1.5e2, defaultLocale)).toEqual('15,000%');
expect(formatPercent(1e100, defaultLocale)).toEqual('1E+102%');
expect(formatPercent(0.12345674, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('12.345674%');
expect(formatPercent(0, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('0%');
expect(formatPercent(0.00, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('0%');
expect(formatPercent(1, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('100%');
expect(formatPercent(0.1, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('10%');
expect(formatPercent(0.12, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('12%');
expect(formatPercent(0.123, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('12.3%');
expect(formatPercent(12.3456, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('1,234.56%');
expect(formatPercent(12.345600, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('1,234.56%');
expect(formatPercent(12.345699999, DEFAULT_LOCALE_ID, '0.0-6')).toEqual('1,234.57%');
expect(formatPercent(12.345699999, DEFAULT_LOCALE_ID, '0.4-6')).toEqual('1,234.5700%');
expect(formatPercent(100, DEFAULT_LOCALE_ID, '0.4-6')).toEqual('10,000.0000%');
expect(formatPercent(100, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('10,000%');
expect(formatPercent(1.5e2, DEFAULT_LOCALE_ID)).toEqual('15,000%');
expect(formatPercent(1e100, DEFAULT_LOCALE_ID)).toEqual('1E+102%');
});
});
});
@ -80,16 +79,16 @@ describe('Format number', () => {
const defaultCurrencyCode = 'USD';
describe('transform', () => {
it('should return correct value for numbers', () => {
expect(formatCurrency(123, defaultLocale, '$')).toEqual('$123.00');
expect(formatCurrency(12, defaultLocale, 'EUR', 'EUR', '.1')).toEqual('EUR12.0');
expect(
formatCurrency(5.1234, defaultLocale, defaultCurrencyCode, defaultCurrencyCode, '.0-3'))
expect(formatCurrency(123, DEFAULT_LOCALE_ID, '$')).toEqual('$123.00');
expect(formatCurrency(12, DEFAULT_LOCALE_ID, 'EUR', 'EUR', '.1')).toEqual('EUR12.0');
expect(formatCurrency(
5.1234, DEFAULT_LOCALE_ID, defaultCurrencyCode, defaultCurrencyCode, '.0-3'))
.toEqual('USD5.123');
expect(formatCurrency(5.1234, defaultLocale, defaultCurrencyCode)).toEqual('USD5.12');
expect(formatCurrency(5.1234, defaultLocale, '$')).toEqual('$5.12');
expect(formatCurrency(5.1234, defaultLocale, 'CA$')).toEqual('CA$5.12');
expect(formatCurrency(5.1234, defaultLocale, '$')).toEqual('$5.12');
expect(formatCurrency(5.1234, defaultLocale, '$', defaultCurrencyCode, '5.2-2'))
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, defaultCurrencyCode)).toEqual('USD5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, '$')).toEqual('$5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'CA$')).toEqual('CA$5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, '$')).toEqual('$5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, '$', defaultCurrencyCode, '5.2-2'))
.toEqual('$00,005.12');
expect(formatCurrency(5.1234, 'fr', '$', defaultCurrencyCode, '5.2-2'))
.toEqual('00 005,12 $');
@ -98,20 +97,21 @@ describe('Format number', () => {
it('should support any currency code name', () => {
// currency code is unknown, default formatting options will be used
expect(formatCurrency(5.1234, defaultLocale, 'unexisting_ISO_code'))
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'unexisting_ISO_code'))
.toEqual('unexisting_ISO_code5.12');
// currency code is USD, the pipe will format based on USD but will display "Custom name"
expect(formatCurrency(5.1234, defaultLocale, 'Custom name')).toEqual('Custom name5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'Custom name')).toEqual('Custom name5.12');
});
it('should round to the default number of digits if no digitsInfo', () => {
// IDR has a default number of digits of 0
expect(formatCurrency(5.1234, defaultLocale, 'IDR', 'IDR')).toEqual('IDR5');
expect(formatCurrency(5.1234, defaultLocale, 'IDR', 'IDR', '.2')).toEqual('IDR5.12');
expect(formatCurrency(5.1234, defaultLocale, 'Custom name', 'IDR')).toEqual('Custom name5');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'IDR', 'IDR')).toEqual('IDR5');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'IDR', 'IDR', '.2')).toEqual('IDR5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'Custom name', 'IDR'))
.toEqual('Custom name5');
// BHD has a default number of digits of 3
expect(formatCurrency(5.1234, defaultLocale, 'BHD', 'BHD')).toEqual('BHD5.123');
expect(formatCurrency(5.1234, defaultLocale, 'BHD', 'BHD', '.1-2')).toEqual('BHD5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'BHD', 'BHD')).toEqual('BHD5.123');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'BHD', 'BHD', '.1-2')).toEqual('BHD5.12');
});
});
});

View File

@ -14,11 +14,14 @@ import {Console} from './console';
import {Injector, StaticProvider} from './di';
import {Inject, Optional, SkipSelf} from './di/metadata';
import {ErrorHandler} from './error_handler';
import {DEFAULT_LOCALE_ID} from './i18n/localization';
import {LOCALE_ID} from './i18n/tokens';
import {ivyEnabled} from './ivy_switch';
import {ComponentFactoryResolver} from './linker';
import {Compiler} from './linker/compiler';
import {NgModule} from './metadata';
import {SCHEDULER} from './render3/component_ref';
import {setLocaleId} from './render3/i18n';
import {NgZone} from './zone';
export function _iterableDiffersFactory() {
@ -31,15 +34,21 @@ export function _keyValueDiffersFactory() {
export function _localeFactory(locale?: string): string {
if (locale) {
if (ivyEnabled) {
setLocaleId(locale);
}
return locale;
}
// Use `goog.LOCALE` as default value for `LOCALE_ID` token for Closure Compiler.
// Note: default `goog.LOCALE` value is `en`, when Angular used `en-US`. In order to preserve
// backwards compatibility, we use Angular default value over Closure Compiler's one.
if (ngI18nClosureMode && typeof goog !== 'undefined' && goog.LOCALE !== 'en') {
if (ivyEnabled) {
setLocaleId(goog.LOCALE);
}
return goog.LOCALE;
}
return 'en-US';
return DEFAULT_LOCALE_ID;
}
/**

View File

@ -8,15 +8,16 @@
import {Observable, Observer, Subscription, merge} from 'rxjs';
import {share} from 'rxjs/operators';
import {ApplicationInitStatus} from './application_init';
import {APP_BOOTSTRAP_LISTENER, PLATFORM_INITIALIZER} from './application_tokens';
import {getCompilerFacade} from './compiler/compiler_facade';
import {Console} from './console';
import {Injectable, InjectionToken, Injector, StaticProvider} from './di';
import {ErrorHandler} from './error_handler';
import {DEFAULT_LOCALE_ID} from './i18n/localization';
import {LOCALE_ID} from './i18n/tokens';
import {Type} from './interface/type';
import {ivyEnabled} from './ivy_switch';
import {COMPILER_OPTIONS, CompilerFactory, CompilerOptions} from './linker/compiler';
import {ComponentFactory, ComponentRef} from './linker/component_factory';
import {ComponentFactoryBoundToModule, ComponentFactoryResolver} from './linker/component_factory_resolver';
@ -26,7 +27,7 @@ import {isComponentResourceResolutionQueueEmpty, resolveComponentResources} from
import {WtfScopeFn, wtfCreateScope, wtfLeave} from './profile/profile';
import {assertNgModuleType} from './render3/assert';
import {ComponentFactory as R3ComponentFactory} from './render3/component_ref';
import {DEFAULT_LOCALE_ID, setLocaleId} from './render3/i18n';
import {setLocaleId} from './render3/i18n';
import {NgModuleFactory as R3NgModuleFactory} from './render3/ng_module_ref';
import {Testability, TestabilityRegistry} from './testability/testability';
import {isDevMode} from './util/is_dev_mode';
@ -264,8 +265,10 @@ export class PlatformRef {
throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?');
}
// If the `LOCALE_ID` provider is defined at bootstrap we set the value for runtime i18n (ivy)
const localeId = moduleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
setLocaleId(localeId);
if (ivyEnabled) {
const localeId = moduleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
setLocaleId(localeId || DEFAULT_LOCALE_ID);
}
moduleRef.onDestroy(() => remove(this._modules, moduleRef));
ngZone !.runOutsideAngular(
() => ngZone !.onError.subscribe(

View File

@ -16,6 +16,7 @@ export {Console as ɵConsole} from './console';
export {inject, setCurrentInjector as ɵsetCurrentInjector, ɵɵinject} from './di/injector_compatibility';
export {getInjectableDef as ɵgetInjectableDef, ɵɵInjectableDef, ɵɵInjectorDef} from './di/interface/defs';
export {APP_ROOT as ɵAPP_ROOT} from './di/scope';
export {DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID} from './i18n/localization';
export {ivyEnabled as ɵivyEnabled} from './ivy_switch';
export {ComponentFactory as ɵComponentFactory} from './linker/component_factory';
export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver';
@ -27,7 +28,6 @@ export {_sanitizeHtml as ɵ_sanitizeHtml} from './sanitization/html_sanitizer';
export {_sanitizeStyle as ɵ_sanitizeStyle} from './sanitization/style_sanitizer';
export {_sanitizeUrl as ɵ_sanitizeUrl} from './sanitization/url_sanitizer';
export {global as ɵglobal} from './util/global';
export {looseIdentical as ɵlooseIdentical,} from './util/comparison';
export {stringify as ɵstringify} from './util/stringify';
export {makeDecorator as ɵmakeDecorator} from './util/decorators';

View File

@ -173,7 +173,6 @@ export {
i18nConfigureLocalize as ɵi18nConfigureLocalize,
ɵɵi18nLocalize,
setLocaleId as ɵsetLocaleId,
DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID,
setClassMetadata as ɵsetClassMetadata,
ɵɵresolveWindow,
ɵɵresolveDocument,

View File

@ -29,3 +29,8 @@ export function getPluralCase(value: any, locale: string): string {
return 'other';
}
}
/**
* The locale id that the application is using by default (for translations and ICU expressions).
*/
export const DEFAULT_LOCALE_ID = 'en-US';

View File

@ -7,14 +7,12 @@
*/
import '../util/ng_i18n_closure_mode';
import {getPluralCase} from '../i18n/localization';
import {DEFAULT_LOCALE_ID, getPluralCase} from '../i18n/localization';
import {SRCSET_ATTRS, URI_ATTRS, VALID_ATTRS, VALID_ELEMENTS, getTemplateContent} from '../sanitization/html_sanitizer';
import {InertBodyHelper} from '../sanitization/inert_body';
import {_sanitizeUrl, sanitizeSrcset} from '../sanitization/url_sanitizer';
import {addAllToArray} from '../util/array_utils';
import {assertDataInRange, assertDefined, assertEqual, assertGreaterThan} from '../util/assert';
import {attachPatchData} from './context_discovery';
import {bind, setDelayProjection, ɵɵload} from './instructions/all';
import {attachI18nOpCodesDebug} from './instructions/lview_debug';
@ -1358,7 +1356,6 @@ export function ɵɵi18nLocalize(input: string, placeholders?: {[key: string]: s
* This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
* but is now defined as a global value.
*/
export const DEFAULT_LOCALE_ID = 'en-US';
let LOCALE_ID = DEFAULT_LOCALE_ID;
/**
@ -1369,7 +1366,10 @@ let LOCALE_ID = DEFAULT_LOCALE_ID;
* @param localeId
*/
export function setLocaleId(localeId: string) {
LOCALE_ID = localeId.toLowerCase().replace(/_/g, '-');
assertDefined(localeId, `Expected localeId to be defined`);
if (typeof localeId === 'string') {
LOCALE_ID = localeId.toLowerCase().replace(/_/g, '-');
}
}
/**

View File

@ -142,7 +142,6 @@ export {
} from './state';
export {
DEFAULT_LOCALE_ID,
ɵɵi18n,
ɵɵi18nAttributes,
ɵɵi18nExp,

View File

@ -7,7 +7,7 @@
*/
import {CommonModule} from '@angular/common';
import {Attribute, ChangeDetectorRef, Component, Directive, ElementRef, EventEmitter, Host, HostBinding, INJECTOR, Inject, Injectable, InjectionToken, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, forwardRef} from '@angular/core';
import {Attribute, ChangeDetectorRef, Component, Directive, ElementRef, EventEmitter, Host, HostBinding, INJECTOR, Inject, Injectable, InjectionToken, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, forwardRef, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID} from '@angular/core';
import {ViewRef} from '@angular/core/src/render3/view_ref';
import {TestBed} from '@angular/core/testing';
import {ivyEnabled, onlyInIvy} from '@angular/private/testing';
@ -1508,7 +1508,7 @@ describe('di', () => {
const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges();
// takes `LOCALE_ID` from module injector, since we skip Component level with @SkipSelf
expect(fixture.componentInstance.localeId).toBe('en-US');
expect(fixture.componentInstance.localeId).toBe(DEFAULT_LOCALE_ID);
});
it('should work when injecting dependency in Directives', () => {

View File

@ -343,6 +343,21 @@ class SomeComponent {
expect(getLocaleId()).toEqual('ro');
});
it('should wait for APP_INITIALIZER to set providers for `LOCALE_ID`', async() => {
let locale: string = '';
const promise = Promise.resolve().then(() => { locale = 'fr-FR'; });
const testModule = createModule({
providers: [
{provide: APP_INITIALIZER, useValue: () => promise, multi: true},
{provide: LOCALE_ID, useFactory: () => locale}
]
});
const app = await defaultPlatform.bootstrapModule(testModule);
expect(app.injector.get(LOCALE_ID)).toEqual('fr-FR');
});
});
describe('bootstrapModuleFactory', () => {