feat(ivy): implement $localize() global function (#31609)

PR Close #31609
This commit is contained in:
Pete Bacon Darwin
2019-07-30 18:02:17 +01:00
committed by Misko Hevery
parent b34bdf5c42
commit b21397bde9
13 changed files with 723 additions and 0 deletions

View File

@ -0,0 +1,24 @@
load("//tools:defaults.bzl", "jasmine_node_test", "ts_library")
ts_library(
name = "test_lib",
testonly = True,
srcs = glob(
["*_spec.ts"],
),
deps = [
"//packages:types",
"//packages/localize",
],
)
jasmine_node_test(
name = "test",
bootstrap = [
"angular/tools/testing/init_node_no_angular_spec.js",
],
deps = [
":test_lib",
"//tools/testing:node_no_angular",
],
)

View File

@ -0,0 +1,100 @@
/**
* @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 '..'; // Ensure $localize is attached to the global scope
import {TranslateFn} from '../src/localize';
describe('$localize tag', () => {
describe('with no `translate()` defined (the default)', () => {
it('should render template literals as-is', () => {
expect($localize.translate).toBeUndefined();
expect($localize `abc`).toEqual('abc');
expect($localize `abc${1 + 2 + 3}`).toEqual('abc6');
expect($localize `abc${1 + 2 + 3}def`).toEqual('abc6def');
expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15');
const getName = () => 'World';
expect($localize `Hello, ${getName()}!`).toEqual('Hello, World!');
});
it('should strip placeholder names from message parts', () => {
expect($localize.translate).toBeUndefined();
expect($localize `abc${1 + 2 + 3}:ph1:def${4 + 5 + 6}:ph2:`).toEqual('abc6def15');
});
it('should ignore escaped placeholder name marker', () => {
expect($localize.translate).toBeUndefined();
expect($localize `abc${1 + 2 + 3}\:ph1:def${4 + 5 + 6}\:ph2:`).toEqual('abc6:ph1:def15:ph2:');
});
});
describe('with `translate()` defined as an identity', () => {
beforeEach(() => { $localize.translate = identityTranslate; });
afterEach(() => { $localize.translate = undefined; });
it('should render template literals as-is', () => {
expect($localize `abc`).toEqual('abc');
expect($localize `abc${1 + 2 + 3}`).toEqual('abc6');
expect($localize `abc${1 + 2 + 3}def`).toEqual('abc6def');
expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15');
const getName = () => 'World';
expect($localize `Hello, ${getName()}!`).toEqual('Hello, World!');
});
});
describe('with `translate()` defined to upper-case messageParts', () => {
beforeEach(() => { $localize.translate = upperCaseTranslate; });
afterEach(() => { $localize.translate = undefined; });
it('should render template literals with messages upper-cased', () => {
expect($localize `abc`).toEqual('ABC');
expect($localize `abc${1 + 2 + 3}`).toEqual('ABC6');
expect($localize `abc${1 + 2 + 3}def`).toEqual('ABC6DEF');
expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('ABC6DEF15');
const getName = () => 'World';
expect($localize `Hello, ${getName()}!`).toEqual('HELLO, World!');
});
});
describe('with `translate()` defined to reverse expressions', () => {
beforeEach(() => { $localize.translate = reverseTranslate; });
afterEach(() => { $localize.translate = undefined; });
it('should render template literals with expressions reversed', () => {
const getName = () => 'World';
expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`)
.toEqual('abcWorlddef15 - Hello, 6!');
});
});
});
function makeTemplateObject(cooked: string[], raw: string[]): TemplateStringsArray {
Object.defineProperty(cooked, 'raw', {value: raw});
return cooked as any;
}
const identityTranslate: TranslateFn = function(
messageParts: TemplateStringsArray, expressions: readonly any[]) {
return [messageParts, expressions];
};
const upperCaseTranslate: TranslateFn = function(
messageParts: TemplateStringsArray, expressions: readonly any[]) {
return [
makeTemplateObject(
Array.from(messageParts).map((part: string) => part.toUpperCase()),
messageParts.raw.map((part: string) => part.toUpperCase())),
expressions
];
};
const reverseTranslate: TranslateFn = function(
messageParts: TemplateStringsArray, expressions: readonly any[]) {
expressions = Array.from(expressions).reverse();
return [messageParts, expressions];
};