Skip to content

Commit

Permalink
feat(ivy): allow the locale to be set via a global property
Browse files Browse the repository at this point in the history
The ivy compile time inlining tools work on the code after it has
been compiled and bundled (potentially minified and mangled).
It is only at this point in the processing that the current locale
can be specified.

The cleanest way for the tooling to provide this locale value is
by setting a well-known global property (e.g. `ɵNG_LOCALE_ID`)
which is then read at runtime by Angular and provided as the `LOCALE_ID`
token and also passed to the ivy machinery via `setLocaleId()`.

// FW-1639

See angular/angular-cli#15896
  • Loading branch information
petebacondarwin committed Oct 22, 2019
1 parent ec482da commit 4a66c14
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 7 deletions.
30 changes: 23 additions & 7 deletions packages/core/src/application_module.ts
Expand Up @@ -22,6 +22,7 @@ import {Compiler} from './linker/compiler';
import {NgModule} from './metadata';
import {SCHEDULER} from './render3/component_ref';
import {setLocaleId} from './render3/i18n';
import {global} from './util/global';
import {NgZone} from './zone';

export function _iterableDiffersFactory() {
Expand All @@ -35,19 +36,34 @@ export function _keyValueDiffersFactory() {
export function _localeFactory(locale?: string): string {
if (locale) {
if (ivyEnabled) {
// The developer has provided a value for the `LOCALE_ID` token, which overrides the one
// generated by this factory. So tell the ivy infrastructure about it.
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);

if (ngI18nClosureMode && typeof goog !== 'undefined') {
// Use `goog.LOCALE` as default value for `LOCALE_ID` token for Closure Compiler.

// Note: default `goog.LOCALE` value is `en`, while Angular used `en-US`.
// In order to preserve backwards compatibility, we use Angular default value over Closure
// Compiler's one.
if (goog.LOCALE !== 'en') {
if (ivyEnabled) {
setLocaleId(goog.LOCALE);
}
return goog.LOCALE;
}
return goog.LOCALE;
} else if (ivyEnabled) {
// The CLI tooling (e.g. translation inliner) may provide a locale by setting the ɵNG_LOCALE_ID
// global variable.
const localeId = global.ɵNG_LOCALE_ID || DEFAULT_LOCALE_ID;
setLocaleId(localeId);
return localeId;
}

// No Closure Compiler and no ivy - so just go with the default.
return DEFAULT_LOCALE_ID;
}

Expand Down
50 changes: 50 additions & 0 deletions packages/core/test/application_module_spec.ts
Expand Up @@ -7,11 +7,61 @@
*/

import {LOCALE_ID} from '@angular/core';
import {ivyEnabled} from '@angular/private/testing';

import {getLocaleId} from '../src/render3';
import {global} from '../src/util/global';
import {TestBed} from '../testing';
import {describe, expect, inject, it} from '../testing/src/testing_internal';

{
describe('Application module', () => {
it('should set the default locale to "en-US"',
inject([LOCALE_ID], (defaultLocale: string) => { expect(defaultLocale).toEqual('en-US'); }));

if (ivyEnabled) {
it('should set the ivy locale with the configured LOCALE_ID', () => {
TestBed.configureTestingModule({providers: [{provide: LOCALE_ID, useValue: 'fr'}]});
const before = getLocaleId();
const locale = TestBed.inject(LOCALE_ID);
const after = getLocaleId();
expect(before).toEqual('en-us');
expect(locale).toEqual('fr');
expect(after).toEqual('fr');
});

describe('global.ɵNG_LOCALE_ID', () => {
let hasGlobalLocale: boolean;
let globalLocale: string;
beforeEach(() => {
hasGlobalLocale = Object.getOwnPropertyNames(global).includes('ɵNG_LOCALE_ID');
if (hasGlobalLocale) {
globalLocale = global.ɵNG_LOCALE_ID;
}
global.ɵNG_LOCALE_ID = 'de';
});
afterEach(() => {
if (hasGlobalLocale) {
global.ɵNG_LOCALE_ID = globalLocale;
} else {
delete global.ɵNG_LOCALE_ID;
}
});

it('should set the locale to the global value', () => {
const locale = TestBed.inject(LOCALE_ID);
expect(locale).toEqual('de');
expect(getLocaleId()).toEqual('de');
});

it('should set the locale to the configured LOCALE_ID even if there is a global value',
() => {
TestBed.configureTestingModule({providers: [{provide: LOCALE_ID, useValue: 'fr'}]});
const locale = TestBed.inject(LOCALE_ID);
expect(locale).toEqual('fr');
expect(getLocaleId()).toEqual('fr');
});
});
}
});
}

0 comments on commit 4a66c14

Please sign in to comment.