feat(ivy): allow the locale to be set via a global property (#33314)
In the post-$localize world the current locale value is defined by setting `$localize.locale` which is then read at runtime by Angular in the provider for the `LOCALE_ID` token and also passed to the ivy machinery via`setLocaleId()`. The $localize compile-time inlining tooling can replace occurrences of `$localize.locale` with a string literal, similar to how translations are inlined. // FW-1639 See https://github.com/angular/angular-cli/issues/15896 PR Close #33314
This commit is contained in:
parent
ed4244e932
commit
fde8363e0d
@ -24,6 +24,8 @@ import {SCHEDULER} from './render3/component_ref';
|
|||||||
import {setLocaleId} from './render3/i18n';
|
import {setLocaleId} from './render3/i18n';
|
||||||
import {NgZone} from './zone';
|
import {NgZone} from './zone';
|
||||||
|
|
||||||
|
declare const $localize: {locale?: string};
|
||||||
|
|
||||||
export function _iterableDiffersFactory() {
|
export function _iterableDiffersFactory() {
|
||||||
return defaultIterableDiffers;
|
return defaultIterableDiffers;
|
||||||
}
|
}
|
||||||
@ -33,22 +35,38 @@ export function _keyValueDiffersFactory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function _localeFactory(locale?: string): string {
|
export function _localeFactory(locale?: string): string {
|
||||||
if (locale) {
|
locale = locale || getGlobalLocale();
|
||||||
if (ivyEnabled) {
|
if (ivyEnabled) {
|
||||||
setLocaleId(locale);
|
setLocaleId(locale);
|
||||||
}
|
|
||||||
return locale;
|
|
||||||
}
|
}
|
||||||
// Use `goog.LOCALE` as default value for `LOCALE_ID` token for Closure Compiler.
|
return locale;
|
||||||
// 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.
|
|
||||||
|
/**
|
||||||
|
* Work out the locale from the potential global properties.
|
||||||
|
*
|
||||||
|
* * Closure Compiler: use `goog.LOCALE`.
|
||||||
|
* * Ivy enabled: use `$localize.locale`
|
||||||
|
*/
|
||||||
|
export function getGlobalLocale(): string {
|
||||||
if (ngI18nClosureMode && typeof goog !== 'undefined' && goog.LOCALE !== 'en') {
|
if (ngI18nClosureMode && typeof goog !== 'undefined' && goog.LOCALE !== 'en') {
|
||||||
if (ivyEnabled) {
|
// * The default `goog.LOCALE` value is `en`, while Angular used `en-US`.
|
||||||
setLocaleId(goog.LOCALE);
|
// * In order to preserve backwards compatibility, we use Angular default value over
|
||||||
}
|
// Closure Compiler's one.
|
||||||
return goog.LOCALE;
|
return goog.LOCALE;
|
||||||
|
} else {
|
||||||
|
// KEEP `typeof $localize !== 'undefined' && $localize.locale` IN SYNC WITH THE LOCALIZE
|
||||||
|
// COMPILE-TIME INLINER.
|
||||||
|
//
|
||||||
|
// * During compile time inlining of translations the expression will be replaced
|
||||||
|
// with a string literal that is the current locale. Other forms of this expression are not
|
||||||
|
// guaranteed to be replaced.
|
||||||
|
//
|
||||||
|
// * During runtime translation evaluation, the developer is required to set `$localize.locale`
|
||||||
|
// if required, or just to provide their own `LOCALE_ID` provider.
|
||||||
|
return (ivyEnabled && typeof $localize !== 'undefined' && $localize.locale) ||
|
||||||
|
DEFAULT_LOCALE_ID;
|
||||||
}
|
}
|
||||||
return DEFAULT_LOCALE_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,11 +7,74 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {LOCALE_ID} from '@angular/core';
|
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';
|
import {describe, expect, inject, it} from '../testing/src/testing_internal';
|
||||||
|
|
||||||
{
|
{
|
||||||
describe('Application module', () => {
|
describe('Application module', () => {
|
||||||
it('should set the default locale to "en-US"',
|
it('should set the default locale to "en-US"',
|
||||||
inject([LOCALE_ID], (defaultLocale: string) => { expect(defaultLocale).toEqual('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('$localize.locale', () => {
|
||||||
|
beforeEach(() => initLocale('de'));
|
||||||
|
afterEach(() => restoreLocale());
|
||||||
|
|
||||||
|
it('should set the ivy locale to `$localize.locale` value if it is defined', () => {
|
||||||
|
// Injecting `LOCALE_ID` should also initialize the ivy locale
|
||||||
|
const locale = TestBed.inject(LOCALE_ID);
|
||||||
|
expect(locale).toEqual('de');
|
||||||
|
expect(getLocaleId()).toEqual('de');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the ivy locale to an application provided LOCALE_ID even if `$localize.locale` is defined',
|
||||||
|
() => {
|
||||||
|
TestBed.configureTestingModule({providers: [{provide: LOCALE_ID, useValue: 'fr'}]});
|
||||||
|
const locale = TestBed.inject(LOCALE_ID);
|
||||||
|
expect(locale).toEqual('fr');
|
||||||
|
expect(getLocaleId()).toEqual('fr');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let hasGlobalLocalize: boolean;
|
||||||
|
let hasGlobalLocale: boolean;
|
||||||
|
let originalLocale: string;
|
||||||
|
|
||||||
|
function initLocale(locale: string) {
|
||||||
|
hasGlobalLocalize = Object.getOwnPropertyNames(global).includes('$localize');
|
||||||
|
if (!hasGlobalLocalize) {
|
||||||
|
global.$localize = {};
|
||||||
|
}
|
||||||
|
hasGlobalLocale = Object.getOwnPropertyNames(global.$localize).includes('locale');
|
||||||
|
originalLocale = global.$localize.locale;
|
||||||
|
global.$localize.locale = locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreLocale() {
|
||||||
|
if (hasGlobalLocale) {
|
||||||
|
global.$localize.locale = originalLocale;
|
||||||
|
} else {
|
||||||
|
delete global.$localize.locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasGlobalLocalize) {
|
||||||
|
delete global.$localize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,6 +20,22 @@ export interface LocalizeFn {
|
|||||||
* different translations.
|
* different translations.
|
||||||
*/
|
*/
|
||||||
translate?: TranslateFn;
|
translate?: TranslateFn;
|
||||||
|
/**
|
||||||
|
* The current locale of the translated messages.
|
||||||
|
*
|
||||||
|
* The compile-time translation inliner is able to replace the following code:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* $localize && $localize.locale
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* with a string literal of the current locale. E.g.
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* "fr"
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
locale?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TranslateFn {
|
export interface TranslateFn {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user