fix(ivy): i18n - do not render message ids unnecessarily (#32867)

In an attempt to be compatible with previous translation files
the Angular compiler was generating instructions that always
included the message id. This was because it was not possible
to accurately re-generate the id from the calls to `$localize()` alone.

In line with https://hackmd.io/EQF4_-atSXK4XWg8eAha2g this
commit changes the compiler so that it only renders ids if they are
"custom" ones provided by the template author.

NOTE:

When translating messages generated by the Angular compiler
from i18n tags in templates, the `$localize.translate()` function
will compute message ids, if no custom id is provided, using a
common digest function that only relies upon the information
available in the `$localize()` calls.

This computed message id will not be the same as the message
ids stored in legacy translation files. Such files will need to be
migrated to use the new common digest function.

This only affects developers who have been trialling `$localize`, have
been calling `loadTranslations()`, and are not exclusively using custom
ids in their templates.

PR Close #32867
This commit is contained in:
Pete Bacon Darwin 2019-10-02 18:17:56 +01:00 committed by atscott
parent d24ade91b8
commit 9188751adc
11 changed files with 439 additions and 261 deletions

View File

@ -219,7 +219,7 @@ describe('i18n support in the template compiler', () => {
$I18N_7$ = $MSG_EXTERNAL_6435899732746131543$$APP_SPEC_TS_8$;
}
else {
$I18N_7$ = $localize \`:meaningC|@@6435899732746131543:Title C\`;
$I18N_7$ = $localize \`:meaningC|:Title C\`;
}
const $_c9$ = ["title", $I18N_7$];
var $I18N_11$;
@ -232,7 +232,7 @@ describe('i18n support in the template compiler', () => {
$I18N_11$ = $MSG_EXTERNAL_5200291527729162531$$APP_SPEC_TS_12$;
}
else {
$I18N_11$ = $localize \`:meaningD|descD@@5200291527729162531:Title D\`;
$I18N_11$ = $localize \`:meaningD|descD:Title D\`;
}
const $_c13$ = ["title", $I18N_11$];
var $I18N_15$;
@ -365,7 +365,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_8809028065680254561$$APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:m|d@@8809028065680254561:introduction\`;
$I18N_1$ = $localize \`:m|d:introduction\`;
}
const $_c1$ = ["title", $I18N_1$];
@ -402,7 +402,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_5526535577705876535$$APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:@@5526535577705876535:static text\`;
$I18N_1$ = $localize \`static text\`;
}
var $I18N_2$;
if (ngI18nClosureMode) {
@ -416,7 +416,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_8977039798304050198$$APP_SPEC_TS_2$;
}
else {
$I18N_2$ = $localize \`:m|d@@8977039798304050198:intro $` +
$I18N_2$ = $localize \`:m|d:intro $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
var $I18N_3$;
@ -431,7 +431,7 @@ describe('i18n support in the template compiler', () => {
$I18N_3$ = $MSG_EXTERNAL_7432761130955693041$$APP_SPEC_TS_3$;
}
else {
$I18N_3$ = $localize \`:m1|d1@@7432761130955693041:$` +
$I18N_3$ = $localize \`:m1|d1:$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
const $_c1$ = [
@ -452,7 +452,7 @@ describe('i18n support in the template compiler', () => {
$I18N_6$ = $MSG_EXTERNAL_7566208596013750546$$APP_SPEC_TS_6$;
}
else {
$I18N_6$ = $localize \`:m2|d2@@7566208596013750546:$` +
$I18N_6$ = $localize \`:m2|d2:$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` +
String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: and again $` +
String.raw `{"\uFFFD2\uFFFD"}:INTERPOLATION_2:\`;
@ -465,7 +465,7 @@ describe('i18n support in the template compiler', () => {
$I18N_7$ = $MSG_EXTERNAL_6639222533406278123$$APP_SPEC_TS_7$;
}
else {
$I18N_7$ = $localize \`:@@6639222533406278123:$` +
$I18N_7$ = $localize \`$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
const $_c3$ = [
@ -516,7 +516,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_8977039798304050198$;
}
else {
$I18N_1$ = $localize \`:m|d@@8977039798304050198:intro $` +
$I18N_1$ = $localize \`:m|d:intro $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
const $_c3$ = ["title", $I18N_1$];
@ -559,7 +559,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_8538466649243975456$$APP_SPEC_TS__1$;
}
else {
$I18N_1$ = $localize \`:m|d@@8538466649243975456:different scope $` +
$I18N_1$ = $localize \`:m|d:different scope $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
const $_c2$ = ["title", $I18N_1$];
@ -609,7 +609,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_3462388422673575127$$APP_SPEC_TS_2$;
}
else {
$I18N_1$ = $localize \`:@@3462388422673575127:$` +
$I18N_1$ = $localize \`$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: title\`;
}
const $_c3$ = ["title", $I18N_1$];
@ -658,7 +658,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_5526535577705876535$$APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:@@5526535577705876535:static text\`;
$I18N_1$ = $localize \`static text\`;
}
var $I18N_2$;
if (ngI18nClosureMode) {
@ -672,7 +672,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_8977039798304050198$$APP_SPEC_TS_2$;
}
else {
$I18N_2$ = $localize \`:m|d@@8977039798304050198:intro $` +
$I18N_2$ = $localize \`:m|d:intro $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
var $I18N_3$;
@ -687,7 +687,7 @@ describe('i18n support in the template compiler', () => {
$I18N_3$ = $MSG_EXTERNAL_7432761130955693041$$APP_SPEC_TS_3$;
}
else {
$I18N_3$ = $localize \`:m1|d1@@7432761130955693041:$` +
$I18N_3$ = $localize \`:m1|d1:$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
const $_c1$ = [
@ -708,7 +708,7 @@ describe('i18n support in the template compiler', () => {
$I18N_6$ = $MSG_EXTERNAL_7566208596013750546$$APP_SPEC_TS_6$;
}
else {
$I18N_6$ = $localize \`:m2|d2@@7566208596013750546:$` +
$I18N_6$ = $localize \`:m2|d2:$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` +
String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: and again $` +
String.raw `{"\uFFFD2\uFFFD"}:INTERPOLATION_2:\`;
@ -721,7 +721,7 @@ describe('i18n support in the template compiler', () => {
$I18N_7$ = $MSG_EXTERNAL_6639222533406278123$$APP_SPEC_TS_7$;
}
else {
$I18N_7$ = $localize \`:@@6639222533406278123:$` +
$I18N_7$ = $localize \`$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
const $_c3$ = [
@ -775,7 +775,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_8538466649243975456$$APP_SPEC_TS__3$;
}
else {
$I18N_2$ = $localize \`:m|d@@8538466649243975456:different scope $` +
$I18N_2$ = $localize \`:m|d:different scope $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
const $_c4$ = ["title", $I18N_2$];
@ -827,7 +827,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_7727043314656808423$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:m|d@@7727043314656808423:Element title\`;
$I18N_0$ = $localize \`:m|d:Element title\`;
}
const $_c1$ = ["title", $I18N_0$];
var $I18N_2$;
@ -836,7 +836,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_4969674997806975147$$APP_SPEC_TS_2$;
}
else {
$I18N_2$ = $localize \`:@@4969674997806975147:Some content\`;
$I18N_2$ = $localize \`Some content\`;
}
template: function MyComponent_Template(rf, ctx) {
@ -926,7 +926,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_APP_SPEC_TS_1$;
}
else {
$I18N_0$ = $localize \`:@@3784161717320915177:Some text\`;
$I18N_0$ = $localize \`Some text\`;
}
`;
verify(input, output);
@ -944,7 +944,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_4924931801512133405$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@4924931801512133405:Some text 'with single quotes', "with double quotes" and without quotes.\`;
$I18N_0$ = $localize \`Some text 'with single quotes', "with double quotes" and without quotes.\`;
}
`;
@ -967,7 +967,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_4890179241114413722$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@4890179241114413722:My i18n block #1\`;
$I18N_0$ = $localize \`My i18n block #1\`;
}
var $I18N_1$;
if (ngI18nClosureMode) {
@ -975,7 +975,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_2413150872298537152$$APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:@@2413150872298537152:My i18n block #2\`;
$I18N_1$ = $localize \`My i18n block #2\`;
}
var $I18N_2$;
if (ngI18nClosureMode) {
@ -983,7 +983,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_5023003143537152794$$APP_SPEC_TS_2$;
}
else {
$I18N_2$ = $localize \`:@@5023003143537152794:My i18n block #3\`;
$I18N_2$ = $localize \`My i18n block #3\`;
}
template: function MyComponent_Template(rf, ctx) {
@ -1028,7 +1028,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_7597881511811528589$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@7597881511811528589: Named interpolation: $` +
$I18N_0$ = $localize \` Named interpolation: $` +
String.raw `{"\uFFFD0\uFFFD"}:PH_A: Named interpolation with spaces: $` +
String.raw `{"\uFFFD1\uFFFD"}:PH_B: \`;
}
@ -1065,7 +1065,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_6749967533321674787$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@6749967533321674787:$` +
$I18N_0$ = $localize \`$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
@ -1104,7 +1104,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_APP_SPEC_TS_1$$APP_SPEC_TS_1$;
}
else {
$I18N_0$ = $localize \`:@@1194644703943451474: $` +
$I18N_0$ = $localize \` $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` +
String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: $` +
String.raw `{"\uFFFD2\uFFFD"}:INTERPOLATION_2: \`;
@ -1144,7 +1144,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_572579892698764378$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@572579892698764378:My i18n block #$` +
$I18N_0$ = $localize \`My i18n block #$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
var $I18N_1$;
@ -1155,7 +1155,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_609623417156596326$$APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:@@609623417156596326:My i18n block #$` +
$I18N_1$ = $localize \`My i18n block #$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
var $I18N_2$;
@ -1166,7 +1166,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_3998119318957372120$$APP_SPEC_TS_2$;
}
else {
$I18N_2$ = $localize \`:@@3998119318957372120:My i18n block #$` +
$I18N_2$ = $localize \`My i18n block #$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
@ -1228,7 +1228,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_7905233330103651696$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@7905233330103651696: My i18n block #$` +
$I18N_0$ = $localize \` My i18n block #$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` +
String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_SPAN:Plain text in nested element$` +
String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_SPAN:\`;
@ -1246,7 +1246,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_5788821996131681377$$APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:@@5788821996131681377: My i18n block #$` +
$I18N_1$ = $localize \` My i18n block #$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` +
String.raw `{"[\uFFFD#6\uFFFD|\uFFFD#7\uFFFD]"}:START_TAG_DIV:$` +
String.raw `{"[\uFFFD#6\uFFFD|\uFFFD#7\uFFFD]"}:START_TAG_DIV:$` + String.raw
@ -1317,7 +1317,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_4782264005467235841$$APP_SPEC_TS_3$;
}
else {
$I18N_2$ = $localize \`:@@4782264005467235841:Span title $` +
$I18N_2$ = $localize \`Span title $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` +
String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1:\`;
}
@ -1332,7 +1332,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_4446430594603971069$$APP_SPEC_TS_5$;
}
else {
$I18N_0$ = $localize \`:@@4446430594603971069: My i18n block #1 with value: $` +
$I18N_0$ = $localize \` My i18n block #1 with value: $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + String.raw
`{"\uFFFD#2\uFFFD"}:START_TAG_SPAN: Plain text in nested element (block #1) $` +
String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_SPAN:\`;
@ -1345,7 +1345,7 @@ describe('i18n support in the template compiler', () => {
$I18N_7$ = $MSG_EXTERNAL_2719594642740200058$$APP_SPEC_TS_8$;
}
else {
$I18N_7$ = $localize \`:@@2719594642740200058:Span title $` +
$I18N_7$ = $localize \`Span title $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
const $_c9$ = ["title", $I18N_7$];
@ -1359,7 +1359,7 @@ describe('i18n support in the template compiler', () => {
$I18N_6$ = $MSG_EXTERNAL_2778714953278357902$$APP_SPEC_TS_10$;
}
else {
$I18N_6$ = $localize \`:@@2778714953278357902: My i18n block #2 with value $` +
$I18N_6$ = $localize \` My i18n block #2 with value $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + String.raw
`{"\uFFFD#7\uFFFD"}:START_TAG_SPAN: Plain text in nested element (block #2) $` +
String.raw `{"\uFFFD/#7\uFFFD"}:CLOSE_TAG_SPAN:\`;
@ -1429,7 +1429,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_7679414751795588050$$APP_SPEC_TS__1$;
}
else {
$I18N_1$ = $localize \`:@@7679414751795588050: Some other content $` +
$I18N_1$ = $localize \` Some other content $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` +
String.raw `{"\uFFFD#3\uFFFD"}:START_TAG_DIV: More nested levels with bindings $` +
String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: $` +
@ -1498,7 +1498,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_2367729185105559721$$APP_SPEC_TS__2$;
}
else {
$I18N_2$ = $localize \`:@@2367729185105559721:App logo #$` +
$I18N_2$ = $localize \`App logo #$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
const $_c4$ = ["title", $I18N_2$];
@ -1613,7 +1613,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_1221890473527419724$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@1221890473527419724: Some content $` +
$I18N_0$ = $localize \` Some content $` +
String.raw
`{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_DIV_2: Some other content $` +
String.raw `{"\uFFFD0:1\uFFFD"}:INTERPOLATION: $` + String.raw
@ -1696,7 +1696,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_119975189388320493$$APP_SPEC_TS__1$;
}
else {
$I18N_1$ = $localize \`:@@119975189388320493:Some other content $` +
$I18N_1$ = $localize \`Some other content $` +
String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_SPAN:$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:$` +
String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_SPAN:\`;
@ -1745,7 +1745,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_APP_SPEC_TS_2$;
}
else {
$I18N_1$ = $localize \`:@@3902961887793684628:Hello\`;
$I18N_1$ = $localize \`Hello\`;
}
template: function MyComponent_Template(rf, ctx) {
@ -1775,7 +1775,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_4890179241114413722$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@4890179241114413722:My i18n block #1\`;
$I18N_0$ = $localize \`My i18n block #1\`;
}
template: function MyComponent_Template(rf, ctx) {
@ -1802,7 +1802,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@8806993169187953163:{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}\`;
$I18N_0$ = $localize \`{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}\`;
}
$I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -1839,7 +1839,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_2413150872298537152$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@2413150872298537152:My i18n block #2\`;
$I18N_0$ = $localize \`My i18n block #2\`;
}
var $I18N_1$;
if (ngI18nClosureMode) {
@ -1847,7 +1847,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_4890179241114413722$$APP_SPEC_TS__1$;
}
else {
$I18N_1$ = $localize \`:@@4890179241114413722:My i18n block #1\`;
$I18N_1$ = $localize \`My i18n block #1\`;
}
function MyComponent_ng_template_0_Template(rf, ctx) {
if (rf & 1) {
@ -1882,7 +1882,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_5295701706185791735$$APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:@@5295701706185791735:Text #1\`;
$I18N_1$ = $localize \`Text #1\`;
}
const $_c2$ = [${AttributeMarker.Styles}, "padding", "10px"];
var $I18N_3$;
@ -1891,7 +1891,7 @@ describe('i18n support in the template compiler', () => {
$I18N_3$ = $MSG_EXTERNAL_4722270221386399294$$APP_SPEC_TS_3$;
}
else {
$I18N_3$ = $localize \`:@@4722270221386399294:Text #2\`;
$I18N_3$ = $localize \`Text #2\`;
}
consts: 4,
@ -1927,7 +1927,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_355394464191978948$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@355394464191978948:Some content: $` +
$I18N_0$ = $localize \`Some content: $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
@ -1964,7 +1964,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_355394464191978948$$APP_SPEC_TS__0$;
}
else {
$I18N_0$ = $localize \`:@@355394464191978948:Some content: $` +
$I18N_0$ = $localize \`Some content: $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
}
function MyComponent_ng_template_0_Template(rf, ctx) {
@ -2012,7 +2012,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_702706566400598764$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@702706566400598764:$` +
$I18N_0$ = $localize \`$` +
String.raw `{"\uFFFD*2:1\uFFFD"}:START_TAG_NG_TEMPLATE:Template content: $` +
String.raw `{"\uFFFD0:1\uFFFD"}:INTERPOLATION:$` +
String.raw `{"\uFFFD/*2:1\uFFFD"}:CLOSE_TAG_NG_TEMPLATE:$` +
@ -2067,7 +2067,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@8806993169187953163:{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}\`;
$I18N_0$ = $localize \`{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}\`;
}
$I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -2078,7 +2078,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS__1$;
}
else {
$I18N_1$ = $localize \`:@@7842238767399919809:{VAR_SELECT, select, male {male} female {female} other {other}}\`;
$I18N_1$ = $localize \`{VAR_SELECT, select, male {male} female {female} other {other}}\`;
}
$I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -2163,7 +2163,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_2051477021417799640$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@2051477021417799640:$` +
$I18N_0$ = $localize \`$` +
String.raw
`{"[\uFFFD*2:1\uFFFD|\uFFFD*2:2\uFFFD|\uFFFD*1:3\uFFFD]"}:START_TAG_NG_TEMPLATE: Template A: $` +
String.raw `{"\uFFFD0:1\uFFFD"}:INTERPOLATION: $` + String.raw
@ -2221,7 +2221,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@7842238767399919809:{VAR_SELECT, select, male {male} female {female} other {other}}\`;
$I18N_0$ = $localize \`{VAR_SELECT, select, male {male} female {female} other {other}}\`;
}
$I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -2232,7 +2232,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS__1$;
}
else {
$I18N_1$ = $localize \`:@@8806993169187953163:{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}\`;
$I18N_1$ = $localize \`{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}\`;
}
$I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -2287,7 +2287,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_4891196282781544695$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@4891196282781544695:$` +
$I18N_0$ = $localize \`$` +
String.raw `{"\uFFFD#2\uFFFD\uFFFD/#2\uFFFD"}:TAG_IMG: is my logo #1 \`;
}
var $I18N_2$;
@ -2298,7 +2298,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_461986953980355147$$APP_SPEC_TS__2$;
}
else {
$I18N_2$ = $localize \`:@@461986953980355147:$` +
$I18N_2$ = $localize \`$` +
String.raw `{"\uFFFD#1\uFFFD\uFFFD/#1\uFFFD"}:TAG_IMG: is my logo #2 \`;
}
function MyComponent_ng_template_3_Template(rf, ctx) {
@ -2344,7 +2344,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_8537814667662432133$$APP_SPEC_TS__0$;
}
else {
$I18N_0$ = $localize \`:@@8537814667662432133: Root content $` +
$I18N_0$ = $localize \` Root content $` +
String.raw
`{"\uFFFD*1:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_NG_CONTAINER: Nested content $` +
String.raw `{"\uFFFD/#1:1\uFFFD\uFFFD/*1:1\uFFFD"}:CLOSE_TAG_NG_CONTAINER:\`;
@ -2371,7 +2371,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_6563391987554512024$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@6563391987554512024:Test\`;
$I18N_0$ = $localize \`Test\`;
}
var $I18N_1$;
if (ngI18nClosureMode) {
@ -2379,7 +2379,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_6563391987554512024$$APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:@@6563391987554512024:Test\`;
$I18N_1$ = $localize \`Test\`;
}
`;
@ -2401,7 +2401,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_APP_SPEC_TS_1$;
}
else {
$I18N_0$ = $localize \`:@@161173306924314453: Hello $` +
$I18N_0$ = $localize \` Hello $` +
String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_NG_CONTAINER:there$` +
String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_NG_CONTAINER:\`;
}
@ -2437,7 +2437,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_APP_SPEC_TS_1$;
}
else {
$I18N_0$ = $localize \`:@@1968828034476446869: Hello $` +
$I18N_0$ = $localize \` Hello $` +
String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_NG_CONTAINER:there $` +
String.raw `{"\uFFFD#3\uFFFD"}:START_TAG_STRONG:!$` +
String.raw `{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_STRONG:$` +
@ -2477,7 +2477,7 @@ describe('i18n support in the template compiler', () => {
const $MSG_EXTERNAL_3308216566145348998$$APP_SPEC_TS___2$ = goog.getMsg("Content A");
$I18N_1$ = $MSG_EXTERNAL_3308216566145348998$$APP_SPEC_TS___2$;
} else {
$I18N_1$ = $localize \`:@@3308216566145348998:Content A\`;
$I18N_1$ = $localize \`Content A\`;
}
function MyComponent_0_ng_template_0_Template(rf, ctx) {
if (rf & 1) {
@ -2494,7 +2494,7 @@ describe('i18n support in the template compiler', () => {
const $MSG_EXTERNAL_8349021389088127654$$APP_SPEC_TS__4$ = goog.getMsg("Content B");
$I18N_3$ = $MSG_EXTERNAL_8349021389088127654$$APP_SPEC_TS__4$;
} else {
$I18N_3$ = $localize \`:@@8349021389088127654:Content B\`;
$I18N_3$ = $localize \`Content B\`;
}
function MyComponent_ng_container_1_Template(rf, ctx) {
if (rf & 1) {
@ -2541,7 +2541,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_963542717423364282$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@963542717423364282:\n Some text\n $` +
$I18N_0$ = $localize \`\n Some text\n $` +
String.raw `{"\uFFFD#3\uFFFD"}:START_TAG_SPAN:Text inside span$` +
String.raw `{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_SPAN:\n \`;
}
@ -2576,7 +2576,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@7842238767399919809:{VAR_SELECT, select, male {male} female {female} other {other}}\`;
$I18N_0$ = $localize \`{VAR_SELECT, select, male {male} female {female} other {other}}\`;
}
$I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -2612,7 +2612,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_4166854826696768832$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@4166854826696768832:{VAR_SELECT, select, single {'single quotes'} double {"double quotes"} other {other}}\`;
$I18N_0$ = $localize \`{VAR_SELECT, select, single {'single quotes'} double {"double quotes"} other {other}}\`;
}
$I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -2634,7 +2634,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@8806993169187953163:{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}\`;
$I18N_0$ = $localize \`{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}\`;
}
$I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -2674,7 +2674,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@7842238767399919809:{VAR_SELECT, select, male {male} female {female} other {other}}\`;
$I18N_0$ = $localize \`{VAR_SELECT, select, male {male} female {female} other {other}}\`;
}
$I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -2688,7 +2688,7 @@ describe('i18n support in the template compiler', () => {
$I18N_3$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS__3$;
}
else {
$I18N_3$ = $localize \`:@@8806993169187953163:{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}\`;
$I18N_3$ = $localize \`{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}\`;
}
$I18N_3$ = $r3$.ɵɵi18nPostprocess($I18N_3$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -2714,7 +2714,7 @@ describe('i18n support in the template compiler', () => {
$I18N_5$ = $MSG_EXTERNAL_1922743304863699161$$APP_SPEC_TS__5$;
}
else {
$I18N_5$ = $localize \`:@@1922743304863699161:{VAR_SELECT, select, 0 {no emails} 1 {one email} other {{INTERPOLATION} emails}}\`;
$I18N_5$ = $localize \`{VAR_SELECT, select, 0 {no emails} 1 {one email} other {{INTERPOLATION} emails}}\`;
}
$I18N_5$ = $r3$.ɵɵi18nPostprocess($I18N_5$, {
"VAR_SELECT": "\uFFFD0\uFFFD",
@ -2771,7 +2771,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_2949673783721159566$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@2949673783721159566:{VAR_SELECT, select, 10 {ten} 20 {twenty} other {{INTERPOLATION}}}\`;
$I18N_0$ = $localize \`{VAR_SELECT, select, 10 {ten} 20 {twenty} other {{INTERPOLATION}}}\`;
}
$I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD",
@ -2810,7 +2810,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_2417296354340576868$$APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:@@2417296354340576868:{VAR_SELECT, select, male {male - {START_BOLD_TEXT}male{CLOSE_BOLD_TEXT}} female {female {START_BOLD_TEXT}female{CLOSE_BOLD_TEXT}} other {{START_TAG_DIV}{START_ITALIC_TEXT}other{CLOSE_ITALIC_TEXT}{CLOSE_TAG_DIV}}}\`;
$I18N_1$ = $localize \`{VAR_SELECT, select, male {male - {START_BOLD_TEXT}male{CLOSE_BOLD_TEXT}} female {female {START_BOLD_TEXT}female{CLOSE_BOLD_TEXT}} other {{START_TAG_DIV}{START_ITALIC_TEXT}other{CLOSE_ITALIC_TEXT}{CLOSE_TAG_DIV}}}\`;
}
$I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD",
@ -2836,7 +2836,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_5791551881115084301$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@5791551881115084301: $` +
$I18N_0$ = $localize \` $` +
String.raw `{$I18N_1$}:ICU: $` +
String.raw `{"\uFFFD#2\uFFFD"}:START_BOLD_TEXT:Other content$` +
String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_BOLD_TEXT:$` +
@ -2881,7 +2881,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_6879461626778511059$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@6879461626778511059:{VAR_SELECT, select, male {male of age: {INTERPOLATION}} female {female} other {other}}\`;
$I18N_0$ = $localize \`{VAR_SELECT, select, male {male of age: {INTERPOLATION}} female {female} other {other}}\`;
}
$I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD",
@ -2921,7 +2921,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:@@7842238767399919809:{VAR_SELECT, select, male {male} female {female} other {other}}\`;
$I18N_1$ = $localize \`{VAR_SELECT, select, male {male} female {female} other {other}}\`;
}
$I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -2932,7 +2932,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_7068143081688428291$$APP_SPEC_TS_2$;
}
else {
$I18N_2$ = $localize \`:@@7068143081688428291:{VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}\`;
$I18N_2$ = $localize \`{VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}\`;
}
$I18N_2$ = $r3$.ɵɵi18nPostprocess($I18N_2$, {
"VAR_SELECT": "\uFFFD1\uFFFD"
@ -2946,7 +2946,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_2967249209167308918$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@2967249209167308918: $` +
$I18N_0$ = $localize \` $` +
String.raw `{$I18N_1$}:ICU: $` + String.raw `{$I18N_2$}:ICU_1: \`;
}
@ -2988,7 +2988,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:@@7842238767399919809:{VAR_SELECT, select, male {male} female {female} other {other}}\`;
$I18N_1$ = $localize \`{VAR_SELECT, select, male {male} female {female} other {other}}\`;
}
$I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -2999,7 +2999,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_APP_SPEC_TS_2$;
}
else {
$I18N_2$ = $localize \`:@@7842238767399919809:{VAR_SELECT, select, male {male} female {female} other {other}}\`;
$I18N_2$ = $localize \`{VAR_SELECT, select, male {male} female {female} other {other}}\`;
}
$I18N_2$ = $r3$.ɵɵi18nPostprocess($I18N_2$, {
"VAR_SELECT": "\uFFFD1\uFFFD"
@ -3011,7 +3011,7 @@ describe('i18n support in the template compiler', () => {
$I18N_4$ = $MSG_APP_SPEC_TS__4$;
}
else {
$I18N_4$ = $localize \`:@@7842238767399919809:{VAR_SELECT, select, male {male} female {female} other {other}}\`;
$I18N_4$ = $localize \`{VAR_SELECT, select, male {male} female {female} other {other}}\`;
}
$I18N_4$ = $r3$.ɵɵi18nPostprocess($I18N_4$, {
"VAR_SELECT": "\uFFFD0:1\uFFFD"
@ -3027,7 +3027,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@7986645988117050801: $` +
$I18N_0$ = $localize \` $` +
String.raw `{"\uFFFDI18N_EXP_ICU\uFFFD"}:ICU: $` +
String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_DIV: $` +
String.raw `{"\uFFFDI18N_EXP_ICU\uFFFD"}:ICU: $` + String.raw
@ -3096,7 +3096,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_343563413083115114$$APP_SPEC_TS_0$;
}
else {
$I18N_1$ = $localize \`:@@343563413083115114:{VAR_SELECT_1, select, male {male of age: {VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}} female {female} other {other}}\`;
$I18N_1$ = $localize \`{VAR_SELECT_1, select, male {male of age: {VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}} female {female} other {other}}\`;
}
$I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD",
@ -3108,7 +3108,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_3052001905251380936$$APP_SPEC_TS_3$;
}
else {
$I18N_0$ = $localize \`:@@3052001905251380936: $` +
$I18N_0$ = $localize \` $` +
String.raw `{$I18N_1$}:ICU: \`;
}
consts: 2,
@ -3151,7 +3151,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_6870293071705078389$$APP_SPEC_TS_1$;
}
else {
$I18N_0$ = $localize \`:@@6870293071705078389:{VAR_PLURAL, plural, =0 {zero} =2 {{INTERPOLATION} {VAR_SELECT, select, cat {cats} dog {dogs} other {animals}} !} other {other - {INTERPOLATION}}}\`;
$I18N_0$ = $localize \`{VAR_PLURAL, plural, =0 {zero} =2 {{INTERPOLATION} {VAR_SELECT, select, cat {cats} dog {dogs} other {animals}} !} other {other - {INTERPOLATION}}}\`;
}
$I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD",
@ -3194,7 +3194,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:@@7842238767399919809:{VAR_SELECT, select, male {male} female {female} other {other}}\`;
$I18N_1$ = $localize \`{VAR_SELECT, select, male {male} female {female} other {other}}\`;
}
$I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD"
@ -3206,7 +3206,7 @@ describe('i18n support in the template compiler', () => {
$I18N_3$ = $MSG_EXTERNAL_7068143081688428291$$APP_SPEC_TS__3$;
}
else {
$I18N_3$ = $localize \`:@@7068143081688428291:{VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}\`;
$I18N_3$ = $localize \`{VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}\`;
}
$I18N_3$ = $r3$.ɵɵi18nPostprocess($I18N_3$, {
"VAR_SELECT": "\uFFFD0:1\uFFFD"
@ -3222,7 +3222,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_1194472282609532229$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@1194472282609532229: $` +
$I18N_0$ = $localize \` $` +
String.raw `{$I18N_1$}:ICU: $` +
String.raw `{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_SPAN: $` +
String.raw `{$I18N_3$}:ICU_1: $` +
@ -3280,7 +3280,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_7825031864601787094$$APP_SPEC_TS_1$;
}
else {
$I18N_1$ = $localize \`:@@7825031864601787094:{VAR_SELECT, select, male {male {INTERPOLATION}} female {female {INTERPOLATION_1}} other {other}}\`;
$I18N_1$ = $localize \`{VAR_SELECT, select, male {male {INTERPOLATION}} female {female {INTERPOLATION_1}} other {other}}\`;
}
$I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD",
@ -3294,7 +3294,7 @@ describe('i18n support in the template compiler', () => {
$I18N_4$ = $MSG_EXTERNAL_2310343208266678305$$APP_SPEC_TS__3$;
}
else {
$I18N_4$ = $localize \`:@@2310343208266678305:{VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other: {INTERPOLATION}}}\`;
$I18N_4$ = $localize \`{VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other: {INTERPOLATION}}}\`;
}
$I18N_4$ = $r3$.ɵɵi18nPostprocess($I18N_4$, {
"VAR_SELECT": "\uFFFD0:1\uFFFD",
@ -3311,7 +3311,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_7186042105600518133$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@7186042105600518133: $` +
$I18N_0$ = $localize \` $` +
String.raw `{I18N_1}:ICU: $` +
String.raw `{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_SPAN: $` +
String.raw `{I18N_4}:ICU_1: $` +
@ -3370,7 +3370,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_6318060397235942326$$APP_SPEC_TS_0$;
}
else {
$I18N_0$ = $localize \`:@@6318060397235942326:{VAR_SELECT, select, male {male {PH_A}} female {female {PH_B}} other {other {PH_WITH_SPACES}}}\`;
$I18N_0$ = $localize \`{VAR_SELECT, select, male {male {PH_A}} female {female {PH_B}} other {other {PH_WITH_SPACES}}}\`;
}
$I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD",

View File

@ -157,7 +157,7 @@ export function fingerprint(str: string): [number, number] {
return [hi, lo];
}
export function computeMsgId(msg: string, meaning: string): string {
export function computeMsgId(msg: string, meaning: string = ''): string {
let [hi, lo] = fingerprint(msg);
if (meaning) {

View File

@ -10,6 +10,7 @@ import {ParseSourceSpan} from '../parse_util';
export class Message {
sources: MessageSpan[];
id: string = this.customId;
/**
* @param nodes message AST
@ -22,7 +23,7 @@ export class Message {
constructor(
public nodes: Node[], public placeholders: {[phName: string]: string},
public placeholderToMessage: {[phName: string]: Message}, public meaning: string,
public description: string, public id: string) {
public description: string, public customId: string) {
if (nodes.length) {
this.sources = [{
filePath: nodes[0].sourceSpan.start.file.url,

View File

@ -18,6 +18,7 @@ import {I18N_ATTR, I18N_ATTR_PREFIX, hasI18nAttrs, icuFromI18nMessage} from './u
export type I18nMeta = {
id?: string,
customId?: string,
description?: string,
meaning?: string
};
@ -47,7 +48,7 @@ export class I18nMetaVisitor implements html.Visitor {
const parsed: I18nMeta =
typeof meta === 'string' ? parseI18nMeta(meta) : metaFromI18nMessage(meta as i18n.Message);
const message = this._createI18nMessage(
nodes, parsed.meaning || '', parsed.description || '', parsed.id || '', visitNodeFn);
nodes, parsed.meaning || '', parsed.description || '', parsed.customId || '', visitNodeFn);
if (!message.id) {
// generate (or restore) message id if not specified in template
message.id = typeof meta !== 'string' && (meta as i18n.Message).id || decimalDigest(message);
@ -140,6 +141,7 @@ export function processI18nMeta(
export function metaFromI18nMessage(message: i18n.Message, id: string | null = null): I18nMeta {
return {
id: typeof id === 'string' ? id : message.id || '',
customId: message.customId,
meaning: message.meaning || '',
description: message.description || ''
};
@ -160,7 +162,7 @@ const I18N_ID_SEPARATOR = '@@';
* @returns Object with id, meaning and description fields
*/
export function parseI18nMeta(meta?: string): I18nMeta {
let id: string|undefined;
let customId: string|undefined;
let meaning: string|undefined;
let description: string|undefined;
@ -168,14 +170,14 @@ export function parseI18nMeta(meta?: string): I18nMeta {
const idIndex = meta.indexOf(I18N_ID_SEPARATOR);
const descIndex = meta.indexOf(I18N_MEANING_SEPARATOR);
let meaningAndDesc: string;
[meaningAndDesc, id] =
[meaningAndDesc, customId] =
(idIndex > -1) ? [meta.slice(0, idIndex), meta.slice(idIndex + 2)] : [meta, ''];
[meaning, description] = (descIndex > -1) ?
[meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] :
['', meaningAndDesc];
}
return {id, meaning, description};
return {customId, meaning, description};
}
/**
@ -190,8 +192,8 @@ export function serializeI18nHead(meta: I18nMeta, messagePart: string): string {
if (meta.meaning) {
metaBlock = `${meta.meaning}|${metaBlock}`;
}
if (meta.id) {
metaBlock = `${metaBlock}@@${meta.id}`;
if (meta.customId) {
metaBlock = `${metaBlock}@@${meta.customId}`;
}
if (metaBlock === '') {
// There is no metaBlock, so we must ensure that any starting colon is escaped.

View File

@ -20,6 +20,7 @@ import {computeMsgId, digest, sha1} from '../../src/i18n/digest';
meaning: '',
description: '',
sources: [],
customId: 'i',
})).toEqual('i');
});
});

View File

@ -241,8 +241,8 @@ describe('Utils', () => {
expect(serializeI18nTemplatePart('abc', ':message')).toEqual(':abc::message');
});
function meta(id?: string, meaning?: string, description?: string): I18nMeta {
return {id, meaning, description};
function meta(customId?: string, meaning?: string, description?: string): I18nMeta {
return {customId, meaning, description};
}
});
});

View File

@ -13,10 +13,11 @@ import localeRo from '@angular/common/locales/ro';
import {Component, ContentChild, ContentChildren, Directive, HostBinding, Input, LOCALE_ID, QueryList, TemplateRef, Type, ViewChild, ViewContainerRef, Pipe, PipeTransform} from '@angular/core';
import {setDelayProjection} from '@angular/core/src/render3/instructions/projection';
import {TestBed} from '@angular/core/testing';
import {loadTranslations} from '@angular/localize';
import {loadTranslations, clearTranslations} from '@angular/localize';
import {By} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {onlyInIvy} from '@angular/private/testing';
import {computeMsgId} from '@angular/compiler';
onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
@ -24,16 +25,19 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
TestBed.configureTestingModule({declarations: [AppComp, DirectiveWithTplRef, UppercasePipe]});
});
afterEach(() => { setDelayProjection(false); });
afterEach(() => {
setDelayProjection(false);
clearTranslations();
});
it('should translate text', () => {
loadTranslations({'3667842621564887364': 'texte'});
loadTranslations({[computeMsgId('text')]: 'texte'});
const fixture = initWithTemplate(AppComp, `<div i18n>text</div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div>texte</div>`);
});
it('should support interpolations', () => {
loadTranslations({'4848371593517801531': 'Bonjour {$INTERPOLATION}!'});
loadTranslations({[computeMsgId('Hello {$INTERPOLATION}!')]: 'Bonjour {$INTERPOLATION}!'});
const fixture = initWithTemplate(AppComp, `<div i18n>Hello {{name}}!</div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div>Bonjour Angular!</div>`);
fixture.componentRef.instance.name = `John`;
@ -42,8 +46,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('should support named interpolations', () => {
loadTranslations(
{'5429622669757720522': ' Bonjour {$USER_NAME}! Emails: {$AMOUNT_OF_EMAILS_RECEIVED} '});
loadTranslations({
[computeMsgId(' Hello {$USER_NAME}! Emails: {$AMOUNT_OF_EMAILS_RECEIVED} ')]:
' Bonjour {$USER_NAME}! Emails: {$AMOUNT_OF_EMAILS_RECEIVED} '
});
const fixture = initWithTemplate(AppComp, `
<div i18n>
Hello {{ name // i18n(ph="user_name") }}!
@ -58,7 +64,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('should support interpolations with custom interpolation config', () => {
loadTranslations({'3771704108176831903': 'Bonjour {$INTERPOLATION}'});
loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
const interpolation = ['{%', '%}'] as[string, string];
TestBed.overrideComponent(AppComp, {set: {interpolation}});
const fixture = initWithTemplate(AppComp, `<div i18n>Hello {% name %}</div>`);
@ -68,7 +74,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support &ngsp; in translatable sections', () => {
// note: the `` unicode symbol represents the `&ngsp;` in translations
loadTranslations({'2564699219547368060': 'texte ||'});
loadTranslations({[computeMsgId('text ||')]: 'texte ||'});
const fixture = initWithTemplate(AppCompWithWhitespaces, `<div i18n>text |&ngsp;|</div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div>texte | |</div>`);
@ -76,7 +82,8 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support interpolations with complex expressions', () => {
loadTranslations({
'3552931695168961643': ' {$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} (fr) '
[computeMsgId(' {$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} ')]:
' {$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} (fr) '
});
const fixture = initWithTemplate(AppComp, `
<div i18n>
@ -99,7 +106,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support elements', () => {
loadTranslations({
'4352419997312772902':
[computeMsgId(
'Hello {$START_TAG_SPAN}world{$CLOSE_TAG_SPAN} and {$START_TAG_DIV}universe{$CLOSE_TAG_DIV}!',
'')]:
'Bonjour {$START_TAG_SPAN}monde{$CLOSE_TAG_SPAN} et {$START_TAG_DIV}univers{$CLOSE_TAG_DIV}!'
});
const fixture = initWithTemplate(
@ -109,7 +118,11 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('should support removing elements', () => {
loadTranslations({'4038508921050216955': 'Bonjour {$START_TAG_SPAN}monde{$CLOSE_TAG_SPAN}'});
loadTranslations({
[computeMsgId(
'Hello {$START_BOLD_TEXT}my{$CLOSE_BOLD_TEXT}{$START_TAG_SPAN}world{$CLOSE_TAG_SPAN}',
'')]: 'Bonjour {$START_TAG_SPAN}monde{$CLOSE_TAG_SPAN}'
});
const fixture =
initWithTemplate(AppComp, `<div i18n>Hello <b>my</b><span>world</span></div><div>!</div>`);
expect(fixture.nativeElement.innerHTML)
@ -118,7 +131,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support moving elements', () => {
loadTranslations({
'4352419997312772902':
[computeMsgId(
'Hello {$START_TAG_SPAN}world{$CLOSE_TAG_SPAN} and {$START_TAG_DIV}universe{$CLOSE_TAG_DIV}!',
'')]:
'Bonjour {$START_TAG_DIV}univers{$CLOSE_TAG_DIV} et {$START_TAG_SPAN}monde{$CLOSE_TAG_SPAN}!'
});
const fixture = initWithTemplate(
@ -129,7 +144,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support template directives', () => {
loadTranslations({
'3546490957396057142':
[computeMsgId(
'Content: {$START_TAG_DIV}before{$START_TAG_SPAN}middle{$CLOSE_TAG_SPAN}after{$CLOSE_TAG_DIV}!',
'')]:
'Contenu: {$START_TAG_DIV}avant{$START_TAG_SPAN}milieu{$CLOSE_TAG_SPAN}après{$CLOSE_TAG_DIV}!'
});
const fixture = initWithTemplate(
@ -149,9 +166,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support multiple i18n blocks', () => {
loadTranslations({
'2954523302699461941': 'traduction {$INTERPOLATION}',
'6316306955288477512': 'start {$INTERPOLATION_1} middle {$INTERPOLATION} end',
'4435073550869683142': '{$START_TAG_E}{$CLOSE_TAG_E}{$START_TAG_C}traduction{$CLOSE_TAG_C}'
[computeMsgId('trad {$INTERPOLATION}')]: 'traduction {$INTERPOLATION}',
[computeMsgId('start {$INTERPOLATION} middle {$INTERPOLATION_1} end')]:
'start {$INTERPOLATION_1} middle {$INTERPOLATION} end',
[computeMsgId(
'{$START_TAG_C}trad{$CLOSE_TAG_C}{$START_TAG_D}{$CLOSE_TAG_D}{$START_TAG_E}{$CLOSE_TAG_E}',
'')]: '{$START_TAG_E}{$CLOSE_TAG_E}{$START_TAG_C}traduction{$CLOSE_TAG_C}'
});
const fixture = initWithTemplate(AppComp, `
<div>
@ -170,9 +190,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support multiple sibling i18n blocks', () => {
loadTranslations({
'1789603390900945185': 'Section un',
'3131519605456222658': 'Section deux',
'1438862747497772785': 'Section trois',
[computeMsgId('Section 1')]: 'Section un',
[computeMsgId('Section 2')]: 'Section deux',
[computeMsgId('Section 3')]: 'Section trois',
});
const fixture = initWithTemplate(AppComp, `
<div>
@ -186,9 +206,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support multiple sibling i18n blocks inside of a template directive', () => {
loadTranslations({
'1789603390900945185': 'Section un',
'3131519605456222658': 'Section deux',
'1438862747497772785': 'Section trois',
[computeMsgId('Section 1')]: 'Section un',
[computeMsgId('Section 2')]: 'Section deux',
[computeMsgId('Section 3')]: 'Section trois',
});
const fixture = initWithTemplate(AppComp, `
<ul *ngFor="let item of [1,2,3]">
@ -204,7 +224,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('should properly escape quotes in content', () => {
loadTranslations({'7582605960852813916': '\'Guillemets simples\' et "Guillemets doubles"'});
loadTranslations({
[computeMsgId('\'Single quotes\' and "Double quotes"')]:
'\'Guillemets simples\' et "Guillemets doubles"'
});
const fixture =
initWithTemplate(AppComp, `<div i18n>'Single quotes' and "Double quotes"</div>`);
@ -213,7 +236,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('should correctly bind to context in nested template', () => {
loadTranslations({'4691107123853093118': 'Article {$INTERPOLATION}'});
loadTranslations({[computeMsgId('Item {$INTERPOLATION}')]: 'Article {$INTERPOLATION}'});
const fixture = initWithTemplate(AppComp, `
<div *ngFor='let id of items'>
<div i18n>Item {{ id }}</div>
@ -233,13 +256,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('should handle i18n attribute with directives', () => {
loadTranslations({'3771704108176831903': 'Bonjour {$INTERPOLATION}'});
loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
const fixture = initWithTemplate(AppComp, `<div *ngIf="visible" i18n>Hello {{ name }}</div>`);
expect(fixture.nativeElement.firstChild).toHaveText('Bonjour Angular');
});
it('should work correctly with event listeners', () => {
loadTranslations({'Hello {$INTERPOLATION}': 'Bonjour {$INTERPOLATION}'});
loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
@Component(
{selector: 'app-comp', template: `<div i18n (click)="onClick()">Hello {{ name }}</div>`})
@ -266,13 +289,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
describe('ng-container and ng-template support', () => {
it('should support ng-container', () => {
loadTranslations({'3667842621564887364': 'texte'});
loadTranslations({[computeMsgId('text')]: 'texte'});
const fixture = initWithTemplate(AppComp, `<ng-container i18n>text</ng-container>`);
expect(fixture.nativeElement.innerHTML).toEqual(`texte<!--ng-container-->`);
});
it('should handle single translation message within ng-template', () => {
loadTranslations({'3771704108176831903': 'Bonjour {$INTERPOLATION}'});
loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
const fixture =
initWithTemplate(AppComp, `<ng-template i18n tplRef>Hello {{ name }}</ng-template>`);
@ -283,7 +306,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
// Note: applying structural directives to <ng-template> is typically user error, but it
// is technically allowed, so we need to support it.
it('should handle structural directives on ng-template', () => {
loadTranslations({'3771704108176831903': 'Bonjour {$INTERPOLATION}'});
loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
const fixture = initWithTemplate(
AppComp, `<ng-template *ngIf="name" i18n tplRef>Hello {{ name }}</ng-template>`);
@ -293,7 +316,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should be able to act as child elements inside i18n block (plain text content)', () => {
loadTranslations({
'3250373733165819471':
[computeMsgId(
'{$START_TAG_NG_TEMPLATE} Hello {$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER} Bye {$CLOSE_TAG_NG_CONTAINER}',
'')]:
'{$START_TAG_NG_TEMPLATE} Bonjour {$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER} Au revoir {$CLOSE_TAG_NG_CONTAINER}'
});
const fixture = initWithTemplate(AppComp, `
@ -313,7 +338,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should be able to act as child elements inside i18n block (text + tags)', () => {
loadTranslations({
'7109932217076518742':
[computeMsgId(
'{$START_TAG_NG_TEMPLATE}{$START_TAG_SPAN}Hello{$CLOSE_TAG_SPAN}{$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER}{$START_TAG_SPAN}Hello{$CLOSE_TAG_SPAN}{$CLOSE_TAG_NG_CONTAINER}',
'')]:
'{$START_TAG_NG_TEMPLATE}{$START_TAG_SPAN}Bonjour{$CLOSE_TAG_SPAN}{$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER}{$START_TAG_SPAN}Bonjour{$CLOSE_TAG_SPAN}{$CLOSE_TAG_NG_CONTAINER}'
});
const fixture = initWithTemplate(AppComp, `
@ -336,7 +363,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should be able to act as child elements inside i18n block (text + pipes)', () => {
loadTranslations({
'2351903444091919458':
[computeMsgId(
'{$START_TAG_NG_TEMPLATE}Hello {$INTERPOLATION}{$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER}Bye {$INTERPOLATION}{$CLOSE_TAG_NG_CONTAINER}',
'')]:
'{$START_TAG_NG_TEMPLATE}Hej {$INTERPOLATION}{$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER}Vi ses {$INTERPOLATION}{$CLOSE_TAG_NG_CONTAINER}'
});
const fixture = initWithTemplate(AppComp, `
@ -352,7 +381,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should be able to handle deep nested levels with templates', () => {
loadTranslations({
'3582176345457676':
[computeMsgId(
'{$START_TAG_SPAN} Hello - 1 {$CLOSE_TAG_SPAN}{$START_TAG_SPAN_1} Hello - 2 {$START_TAG_SPAN_1} Hello - 3 {$START_TAG_SPAN_1} Hello - 4 {$CLOSE_TAG_SPAN}{$CLOSE_TAG_SPAN}{$CLOSE_TAG_SPAN}{$START_TAG_SPAN} Hello - 5 {$CLOSE_TAG_SPAN}',
'')]:
'{$START_TAG_SPAN} Bonjour - 1 {$CLOSE_TAG_SPAN}{$START_TAG_SPAN_1} Bonjour - 2 {$START_TAG_SPAN_1} Bonjour - 3 {$START_TAG_SPAN_1} Bonjour - 4 {$CLOSE_TAG_SPAN}{$CLOSE_TAG_SPAN}{$CLOSE_TAG_SPAN}{$START_TAG_SPAN} Bonjour - 5 {$CLOSE_TAG_SPAN}'
});
const fixture = initWithTemplate(AppComp, `
@ -383,8 +414,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('should handle self-closing tags as content', () => {
loadTranslations(
{'3294715134260231285': '{$START_TAG_SPAN}Mon logo{$TAG_IMG}{$CLOSE_TAG_SPAN}'});
loadTranslations({
[computeMsgId('{$START_TAG_SPAN}My logo{$TAG_IMG}{$CLOSE_TAG_SPAN}')]:
'{$START_TAG_SPAN}Mon logo{$TAG_IMG}{$CLOSE_TAG_SPAN}'
});
const content = `My logo<img src="logo.png" title="Logo">`;
const fixture = initWithTemplate(AppComp, `
<ng-container i18n>
@ -404,6 +437,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('should correctly find context for an element inside i18n section in <ng-template>', () => {
loadTranslations({
[computeMsgId('{$START_LINK}Not logged in{$CLOSE_LINK}')]:
'{$START_LINK}Not logged in{$CLOSE_LINK}'
});
@Directive({selector: '[myDir]'})
class Dir {
condition = true;
@ -438,8 +475,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
describe('should support ICU expressions', () => {
it('with no root node', () => {
loadTranslations(
{'8806993169187953163': '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'});
loadTranslations({
[computeMsgId('{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}')]:
'{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'
});
const fixture =
initWithTemplate(AppComp, `{count, select, 10 {ten} 20 {twenty} other {other}}`);
@ -448,8 +487,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('with no i18n tag', () => {
loadTranslations(
{'8806993169187953163': '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'});
loadTranslations({
[computeMsgId('{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}')]:
'{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'
});
const fixture = initWithTemplate(
AppComp, `<div>{count, select, 10 {ten} 20 {twenty} other {other}}</div>`);
@ -459,9 +500,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('multiple', () => {
loadTranslations({
'3639715378617754400':
[computeMsgId(
'{VAR_PLURAL, plural, =0 {no {START_BOLD_TEXT}emails{CLOSE_BOLD_TEXT}!} =1 {one {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} {START_TAG_SPAN}emails{CLOSE_TAG_SPAN}}}',
'')]:
'{VAR_PLURAL, plural, =0 {aucun {START_BOLD_TEXT}email{CLOSE_BOLD_TEXT}!} =1 {un {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} {START_TAG_SPAN}emails{CLOSE_TAG_SPAN}}}',
'484647350062685600': '{VAR_SELECT, select, other {({INTERPOLATION})}}'
[computeMsgId('{VAR_SELECT, select, other {({INTERPOLATION})}}')]:
'{VAR_SELECT, select, other {({INTERPOLATION})}}',
[computeMsgId('{$ICU} - {$ICU_1}')]: '{$ICU} - {$ICU_1}',
});
const fixture = initWithTemplate(AppComp, `<div i18n>{count, plural,
=0 {no <b>emails</b>!}
@ -487,8 +532,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('with custom interpolation config', () => {
loadTranslations(
{'8091236997374391053': '{VAR_SELECT, select, 10 {dix} other {{INTERPOLATION}}}'});
loadTranslations({
[computeMsgId('{VAR_SELECT, select, 10 {ten} other {{INTERPOLATION}}}')]:
'{VAR_SELECT, select, 10 {dix} other {{INTERPOLATION}}}'
});
const interpolation = ['{%', '%}'] as[string, string];
TestBed.overrideComponent(AppComp, {set: {interpolation}});
const fixture =
@ -499,9 +546,16 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('inside HTML elements', () => {
loadTranslations({
'3639715378617754400':
[computeMsgId(
'{VAR_PLURAL, plural, =0 {no {START_BOLD_TEXT}emails{CLOSE_BOLD_TEXT}!} =1 {one {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} {START_TAG_SPAN}emails{CLOSE_TAG_SPAN}}}',
'')]:
'{VAR_PLURAL, plural, =0 {aucun {START_BOLD_TEXT}email{CLOSE_BOLD_TEXT}!} =1 {un {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} {START_TAG_SPAN}emails{CLOSE_TAG_SPAN}}}',
'484647350062685600': '{VAR_SELECT, select, other {({INTERPOLATION})}}'
[computeMsgId('{VAR_SELECT, select, other {({INTERPOLATION})}}')]:
'{VAR_SELECT, select, other {({INTERPOLATION})}}',
[computeMsgId(
'{$START_TAG_SPAN_1}{$ICU}{$CLOSE_TAG_SPAN} - ' +
'{$START_TAG_SPAN_1}{$ICU_1}{$CLOSE_TAG_SPAN}')]:
'{$START_TAG_SPAN_1}{$ICU}{$CLOSE_TAG_SPAN} - {$START_TAG_SPAN_1}{$ICU_1}{$CLOSE_TAG_SPAN}',
});
const fixture = initWithTemplate(AppComp, `<div i18n><span>{count, plural,
=0 {no <b>emails</b>!}
@ -529,7 +583,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('inside template directives', () => {
loadTranslations({'484647350062685600': '{VAR_SELECT, select, other {({INTERPOLATION})}}'});
loadTranslations({
[computeMsgId('{$START_TAG_SPAN}{$ICU}{$CLOSE_TAG_SPAN}')]:
'{$START_TAG_SPAN}{$ICU}{$CLOSE_TAG_SPAN}',
[computeMsgId('{VAR_SELECT, select, other {({INTERPOLATION})}}')]:
'{VAR_SELECT, select, other {({INTERPOLATION})}}'
});
const fixture = initWithTemplate(AppComp, `<div i18n><span *ngIf="visible">{name, select,
other {({{name}})}
}</span></div>`);
@ -546,7 +605,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('inside ng-container', () => {
loadTranslations({'484647350062685600': '{VAR_SELECT, select, other {({INTERPOLATION})}}'});
loadTranslations({
[computeMsgId('{VAR_SELECT, select, other {({INTERPOLATION})}}')]:
'{VAR_SELECT, select, other {({INTERPOLATION})}}'
});
const fixture = initWithTemplate(AppComp, `<ng-container i18n>{name, select,
other {({{name}})}
}</ng-container>`);
@ -554,8 +616,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('inside <ng-template>', () => {
loadTranslations(
{'8806993169187953163': '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'});
loadTranslations({
[computeMsgId('{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}')]:
'{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'
});
const fixture = initWithTemplate(
AppComp, `
<ng-template i18n tplRef>` +
@ -569,7 +633,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('nested', () => {
loadTranslations({
'6934090145627876010':
[computeMsgId(
'{VAR_PLURAL, plural, =0 {zero} other {{INTERPOLATION} {VAR_SELECT, select, cat {cats} dog {dogs} other {animals}}!}}',
'')]:
'{VAR_PLURAL, plural, =0 {zero} other {{INTERPOLATION} {VAR_SELECT, select, cat {chats} dog {chiens} other {animaux}}!}}'
});
const fixture = initWithTemplate(AppComp, `<div i18n>{count, plural,
@ -589,11 +655,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('nested with interpolations in "other" blocks', () => {
// Note: for some reason long string causing clang to reformat the entire file.
const translation =
'{VAR_PLURAL, plural, =0 {zero} =2 {{INTERPOLATION} {VAR_SELECT, select, ' +
'cat {chats} dog {chiens} other {animaux}}!} other {other - {INTERPOLATION}}}';
loadTranslations({'3182623695425530660': translation});
loadTranslations({
[computeMsgId(
'{VAR_PLURAL, plural, =0 {zero} =2 {{INTERPOLATION} {VAR_SELECT, select, cat {cats} dog {dogs} other {animals}}!} other {other - {INTERPOLATION}}}',
'')]:
'{VAR_PLURAL, plural, =0 {zero} =2 {{INTERPOLATION} {VAR_SELECT, select, cat {chats} dog {chiens} other {animaux}}!} other {autre - {INTERPOLATION}}}'
});
const fixture = initWithTemplate(AppComp, `<div i18n>{count, plural,
=0 {zero}
@ -613,15 +680,19 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
fixture.componentRef.instance.count = 4;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual(`<div>other - 4<!--ICU 5--></div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div>autre - 4<!--ICU 5--></div>`);
});
it('should return the correct plural form for ICU expressions when using a specific locale',
() => {
registerLocaleData(localeRo);
TestBed.configureTestingModule({providers: [{provide: LOCALE_ID, useValue: 'ro'}]});
// We could also use `TestBed.overrideProvider(LOCALE_ID, {useValue: 'ro'});`
const fixture = initWithTemplate(AppComp, `
it('should return the correct plural form for ICU expressions when using a specific locale', () => {
loadTranslations({
[computeMsgId(
'{VAR_PLURAL, plural, =0 {no email} =one {one email} =few {a few emails} =other {lots of emails}}')]:
'{VAR_PLURAL, plural, =0 {no email} =one {one email} =few {a few emails} =other {lots of emails}}'
});
registerLocaleData(localeRo);
TestBed.configureTestingModule({providers: [{provide: LOCALE_ID, useValue: 'ro'}]});
// We could also use `TestBed.overrideProvider(LOCALE_ID, {useValue: 'ro'});`
const fixture = initWithTemplate(AppComp, `
{count, plural,
=0 {no email}
=one {one email}
@ -629,34 +700,38 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
=other {lots of emails}
}`);
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
// Change detection cycle, no model changes
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
// Change detection cycle, no model changes
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
fixture.componentInstance.count = 3;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 2-->');
fixture.componentInstance.count = 3;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 2-->');
fixture.componentInstance.count = 1;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('one email<!--ICU 2-->');
fixture.componentInstance.count = 1;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('one email<!--ICU 2-->');
fixture.componentInstance.count = 10;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 2-->');
fixture.componentInstance.count = 10;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 2-->');
fixture.componentInstance.count = 20;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 2-->');
fixture.componentInstance.count = 20;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 2-->');
fixture.componentInstance.count = 0;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
});
fixture.componentInstance.count = 0;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
});
it('projection', () => {
loadTranslations({
[computeMsgId('{VAR_PLURAL, plural, =1 {one} other {at least {INTERPOLATION} .}}')]:
'{VAR_PLURAL, plural, =1 {one} other {at least {INTERPOLATION} .}}'
});
@Component({selector: 'child', template: '<div><ng-content></ng-content></div>'})
class Child {
}
@ -675,7 +750,6 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
value = 3;
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
@ -684,6 +758,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('with empty values', () => {
loadTranslations({
[computeMsgId('{VAR_SELECT, select, 10 {} 20 {twenty} other {other}}')]:
'{VAR_SELECT, select, 10 {} 20 {twenty} other {other}}'
});
const fixture = initWithTemplate(AppComp, `{count, select, 10 {} 20 {twenty} other {other}}`);
const element = fixture.nativeElement;
@ -691,6 +769,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('inside a container when creating a view via vcr.createEmbeddedView', () => {
loadTranslations({
[computeMsgId('{VAR_PLURAL, plural, =1 {ONE} other {OTHER}}')]:
'{VAR_PLURAL, plural, =1 {ONE} other {OTHER}}'
});
@Directive({
selector: '[someDir]',
})
@ -757,6 +839,14 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('with nested ICU expression and inside a container when creating a view via vcr.createEmbeddedView',
() => {
loadTranslations({
[computeMsgId(
'{VAR_PLURAL, plural, =1 {ONE} other {{INTERPOLATION} ' +
'{VAR_SELECT, select, cat {cats} dog {dogs} other {animals}}!}}')]:
'{VAR_PLURAL, plural, =1 {ONE} other {{INTERPOLATION} ' +
'{VAR_SELECT, select, cat {cats} dog {dogs} other {animals}}!}}'
});
let dir: Dir|null = null;
@Directive({
selector: '[someDir]',
@ -823,6 +913,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('with nested containers', () => {
loadTranslations({
[computeMsgId('{VAR_SELECT, select, A {A } B {B } other {C }}')]:
'{VAR_SELECT, select, A {A } B {B } other {C }}',
[computeMsgId('{VAR_SELECT, select, A1 {A1 } B1 {B1 } other {C1 }}')]:
'{VAR_SELECT, select, A1 {A1 } B1 {B1 } other {C1 }}',
[computeMsgId(' {$ICU} ')]: ' {$ICU} ',
});
@Component({
selector: 'comp',
template: `
@ -857,6 +954,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('with named interpolations', () => {
loadTranslations({
[computeMsgId(
'{VAR_SELECT, select, A {A - {PH_A}} ' +
'B {B - {PH_B}} other {other - {PH_WITH_SPACES}}}')]:
'{VAR_SELECT, select, A {A (translated) - {PH_A}} ' +
'B {B (translated) - {PH_B}} other {other (translated) - {PH_WITH_SPACES}}}',
});
@Component({
selector: 'comp',
template: `
@ -881,16 +985,22 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
const fixture = TestBed.createComponent(Comp);
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.innerHTML).toContain('A - Type A');
expect(fixture.debugElement.nativeElement.innerHTML).toContain('A (translated) - Type A');
fixture.componentInstance.type = 'C'; // trigger "other" case
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.innerHTML).not.toContain('A - Type A');
expect(fixture.debugElement.nativeElement.innerHTML).toContain('other - Type C');
expect(fixture.debugElement.nativeElement.innerHTML).not.toContain('A (translated) - Type A');
expect(fixture.debugElement.nativeElement.innerHTML).toContain('other (translated) - Type C');
});
it('should work inside an ngTemplateOutlet inside an ngFor', () => {
loadTranslations({
[computeMsgId('{VAR_SELECT, select, A {A } B {B } other {other - {PH_WITH_SPACES}}}')]:
'{VAR_SELECT, select, A {A } B {B } other {other - {PH_WITH_SPACES}}}',
[computeMsgId('{$ICU} ')]: '{$ICU} '
});
@Component({
selector: 'app',
template: `
@ -925,13 +1035,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
describe('should support attributes', () => {
it('text', () => {
loadTranslations({'3667842621564887364': 'texte'});
loadTranslations({[computeMsgId('text')]: 'texte'});
const fixture = initWithTemplate(AppComp, `<div i18n i18n-title title='text'></div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div title="texte"></div>`);
});
it('interpolations', () => {
loadTranslations({'1721737630608625819': 'bonjour {$INTERPOLATION}'});
loadTranslations({[computeMsgId('hello {$INTERPOLATION}')]: 'bonjour {$INTERPOLATION}'});
const fixture =
initWithTemplate(AppComp, `<div i18n i18n-title title="hello {{name}}"></div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div title="bonjour Angular"></div>`);
@ -942,14 +1052,14 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('with pipes', () => {
loadTranslations({'5990850149002293021': 'bonjour {$INTERPOLATION}'});
loadTranslations({[computeMsgId('hello {$INTERPOLATION}')]: 'bonjour {$INTERPOLATION}'});
const fixture = initWithTemplate(
AppComp, `<div i18n i18n-title title="hello {{name | uppercase}}"></div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div title="bonjour ANGULAR"></div>`);
});
it('multiple attributes', () => {
loadTranslations({'1721737630608625819': 'bonjour {$INTERPOLATION}'});
loadTranslations({[computeMsgId('hello {$INTERPOLATION}')]: 'bonjour {$INTERPOLATION}'});
const fixture = initWithTemplate(
AppComp,
`<input i18n i18n-title title="hello {{name}}" i18n-placeholder placeholder="hello {{name}}">`);
@ -964,8 +1074,8 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('on removed elements', () => {
loadTranslations({
'3667842621564887364': 'texte',
'4851941758912026972': 'contenu',
[computeMsgId('text')]: 'texte',
[computeMsgId('{$START_TAG_SPAN}content{$CLOSE_TAG_SPAN}')]: 'contenu',
});
const fixture =
initWithTemplate(AppComp, `<div i18n><span i18n-title title="text">content</span></div>`);
@ -973,7 +1083,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('with custom interpolation config', () => {
loadTranslations({'6353989911216474113': 'Bonjour {$INTERPOLATION}'});
loadTranslations({[computeMsgId('Hello {$INTERPOLATION}', 'm')]: 'Bonjour {$INTERPOLATION}'});
const interpolation = ['{%', '%}'] as[string, string];
TestBed.overrideComponent(AppComp, {set: {interpolation}});
const fixture =
@ -984,7 +1094,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('in nested template', () => {
loadTranslations({'5108705942887033129': 'Article {$INTERPOLATION}'});
loadTranslations({[computeMsgId('Item {$INTERPOLATION}', 'm')]: 'Article {$INTERPOLATION}'});
const fixture = initWithTemplate(AppComp, `
<div *ngFor='let item of [1,2,3]'>
<div i18n-title='m|d' title='Item {{ item }}'></div>
@ -998,7 +1108,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('should add i18n attributes on self-closing tags', () => {
loadTranslations({'3771704108176831903': 'Bonjour {$INTERPOLATION}'});
loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
const fixture =
initWithTemplate(AppComp, `<img src="logo.png" i18n-title title="Hello {{ name }}">`);
@ -1007,6 +1117,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('should apply i18n attributes during second template pass', () => {
loadTranslations({[computeMsgId('Set')]: 'Set'});
@Directive({
selector: '[test]',
inputs: ['test'],
@ -1044,13 +1155,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('with complex expressions', () => {
loadTranslations({
'305276527729153743': '{$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} (fr)'
[computeMsgId('{$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2}')]:
'{$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} (fr)'
});
const fixture = initWithTemplate(AppComp, `
<div i18n-title title="{{ name | uppercase }} - {{ obj?.a?.b }} - {{ obj?.getA()?.b }}"></div>
`);
// the `obj` field is not yet defined, so 2nd and 3rd interpolations return empty
// strings
// the `obj` field is not yet defined, so 2nd and 3rd interpolations return empty strings
expect(fixture.nativeElement.firstChild.title).toEqual(`ANGULAR - - (fr)`);
fixture.componentRef.instance.obj = {
@ -1092,10 +1203,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
TestBed.configureTestingModule({declarations: [ClsDir, MyApp]});
loadTranslations({
// Note that this translation switches the order of the expressions!
'2244013204777604001': 'début {$INTERPOLATION_1} milieu {$INTERPOLATION} fin',
'7297507129788731971':
[computeMsgId('start {$INTERPOLATION} middle {$INTERPOLATION_1} end')]:
'début {$INTERPOLATION_1} milieu {$INTERPOLATION} fin',
[computeMsgId(
'{VAR_PLURAL, plural, =0 {no {START_BOLD_TEXT}emails{CLOSE_BOLD_TEXT}!} =1 {one {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} emails}}')]:
'{VAR_PLURAL, plural, =0 {aucun {START_BOLD_TEXT}email{CLOSE_BOLD_TEXT}!} =1 {un {START_ITALIC_TEXT}email{CLOSE_ITALIC_TEXT}} other {{INTERPOLATION} emails}}',
'7694415136422535717': ' traduction: {$ICU} '
[computeMsgId(' trad: {$ICU} ')]: ' traduction: {$ICU} '
});
const fixture = TestBed.createComponent(MyApp);
fixture.detectChanges();
@ -1138,8 +1251,8 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
TestBed.configureTestingModule({declarations: [AppComp, MyComp]});
loadTranslations({
'3299467052279745802': 'Bonjour {$INTERPOLATION}',
'694232821652669635': 'fonctionne',
[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}',
[computeMsgId('works')]: 'fonctionne',
});
const fixture = initWithTemplate(
AppComp,
@ -1155,8 +1268,19 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support adding/moving/removing nodes', () => {
loadTranslations({
'3934630822967503512':
'{$START_TAG_DIV2}{$CLOSE_TAG_DIV2}{$START_TAG_DIV8}{$CLOSE_TAG_DIV8}{$START_TAG_DIV4}{$CLOSE_TAG_DIV4}{$START_TAG_DIV5}{$CLOSE_TAG_DIV5}Bonjour monde{$START_TAG_DIV3}{$CLOSE_TAG_DIV3}{$START_TAG_DIV7}{$CLOSE_TAG_DIV7}'
[computeMsgId(
'{$START_TAG_DIV2}{$CLOSE_TAG_DIV2}' +
'{$START_TAG_DIV3}{$CLOSE_TAG_DIV3}' +
'{$START_TAG_DIV4}{$CLOSE_TAG_DIV4}' +
'{$START_TAG_DIV5}{$CLOSE_TAG_DIV5}' +
'{$START_TAG_DIV6}{$CLOSE_TAG_DIV6}' +
'{$START_TAG_DIV7}{$CLOSE_TAG_DIV7}' +
'{$START_TAG_DIV8}{$CLOSE_TAG_DIV8}')]: '{$START_TAG_DIV2}{$CLOSE_TAG_DIV2}' +
'{$START_TAG_DIV8}{$CLOSE_TAG_DIV8}' +
'{$START_TAG_DIV4}{$CLOSE_TAG_DIV4}' +
'{$START_TAG_DIV5}{$CLOSE_TAG_DIV5}Bonjour monde' +
'{$START_TAG_DIV3}{$CLOSE_TAG_DIV3}' +
'{$START_TAG_DIV7}{$CLOSE_TAG_DIV7}'
});
const fixture = initWithTemplate(AppComp, `
<div i18n>
@ -1195,8 +1319,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({
'7180841260895623479': 'Enfant de {$INTERPOLATION}',
'2325314462315226487':
[computeMsgId('Child of {$INTERPOLATION}')]: 'Enfant de {$INTERPOLATION}',
[computeMsgId(
'{$START_TAG_CHILD}I am projected from' +
' {$START_BOLD_TEXT}{$INTERPOLATION}{$START_TAG_REMOVE_ME_1}{$CLOSE_TAG_REMOVE_ME_1}{$CLOSE_BOLD_TEXT}' +
'{$START_TAG_REMOVE_ME_2}{$CLOSE_TAG_REMOVE_ME_2}' +
'{$CLOSE_TAG_CHILD}' +
'{$START_TAG_REMOVE_ME_3}{$CLOSE_TAG_REMOVE_ME_3}')]:
'{$START_TAG_CHILD}Je suis projeté depuis {$START_BOLD_TEXT}{$INTERPOLATION}{$CLOSE_BOLD_TEXT}{$CLOSE_TAG_CHILD}'
});
const fixture = TestBed.createComponent(Parent);
@ -1227,8 +1356,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({
'7180841260895623479': 'Enfant de {$INTERPOLATION}',
'7230149585615622873': 'Je suis projeté depuis {$INTERPOLATION}'
[computeMsgId('Child of {$INTERPOLATION}')]: 'Enfant de {$INTERPOLATION}',
[computeMsgId('I am projected from {$INTERPOLATION}')]:
'Je suis projeté depuis {$INTERPOLATION}'
});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
@ -1267,8 +1397,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}
TestBed.configureTestingModule({declarations: [Parent, Child, GrandChild]});
loadTranslations(
{'9156403697449779168': '{$START_BOLD_TEXT}Bonjour{$CLOSE_BOLD_TEXT} monde!'});
loadTranslations({
[computeMsgId('{$START_BOLD_TEXT}Hello{$CLOSE_BOLD_TEXT} World!')]:
'{$START_BOLD_TEXT}Bonjour{$CLOSE_BOLD_TEXT} monde!'
});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
@ -1291,7 +1423,8 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}
TestBed.configureTestingModule({declarations: [Parent, Child, GrandChild]});
loadTranslations({'9156403697449779168': 'Bonjour monde!'});
loadTranslations(
{[computeMsgId('{$START_BOLD_TEXT}Hello{$CLOSE_BOLD_TEXT} World!')]: 'Bonjour monde!'});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
@ -1316,7 +1449,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({'2827528023268681613': '{$START_TAG_SPAN}Contenu{$CLOSE_TAG_SPAN}'});
loadTranslations({
[computeMsgId('{$START_TAG_SPAN}{$CLOSE_TAG_SPAN}{$START_TAG_SPAN_1}{$CLOSE_TAG_SPAN}')]:
'{$START_TAG_SPAN}Contenu{$CLOSE_TAG_SPAN}'
});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
@ -1337,7 +1473,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({
'4431461951818971024':
[computeMsgId('Content projected from {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]:
'Contenu projeté depuis {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}'
});
@ -1366,7 +1502,8 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({
'4431461951818971024': '{$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT} a projeté le contenu'
[computeMsgId('Content projected from {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]:
'{$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT} a projeté le contenu'
});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
@ -1386,8 +1523,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({
'3861221266941684467': 'Contenu enfant {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}',
'6186458652454735259': 'et projection depuis {$INTERPOLATION}'
[computeMsgId('Child content {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]:
'Contenu enfant {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}',
[computeMsgId('and projection from {$INTERPOLATION}')]:
'et projection depuis {$INTERPOLATION}'
});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
@ -1396,6 +1535,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('should project bare ICU expressions', () => {
loadTranslations({
[computeMsgId('{VAR_PLURAL, plural, =1 {one} other {at least {INTERPOLATION} .}}')]:
'{VAR_PLURAL, plural, =1 {one} other {at least {INTERPOLATION} .}}'
});
@Component({selector: 'child', template: '<div><ng-content></ng-content></div>'})
class Child {
}
@ -1414,7 +1557,6 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
value = 3;
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
@ -1438,8 +1580,11 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({
'3861221266941684467': 'Contenu enfant {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}',
'4986299685320703675': 'et projection depuis {$ICU}'
[computeMsgId('{VAR_SELECT, select, angular {Angular} other {{INTERPOLATION}}}')]:
'{VAR_SELECT, select, angular {Angular} other {{INTERPOLATION}}}',
[computeMsgId('Child content {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]:
'Contenu enfant {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}',
[computeMsgId('and projection from {$ICU}')]: 'et projection depuis {$ICU}'
});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
@ -1466,8 +1611,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({
'3861221266941684467': 'Contenu enfant',
'6186458652454735259': 'et projection depuis {$INTERPOLATION}'
[computeMsgId('Child content {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]:
'Contenu enfant',
[computeMsgId('and projection from {$INTERPOLATION}')]:
'et projection depuis {$INTERPOLATION}'
});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
@ -1476,6 +1623,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should display/destroy projected i18n content', () => {
loadTranslations({
[computeMsgId('{VAR_SELECT, select, A {A} B {B} other {other}}')]:
'{VAR_SELECT, select, A {A} B {B} other {other}}'
});
@Component({
selector: 'app',
template: `
@ -1553,8 +1704,15 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}
TestBed.configureTestingModule({declarations: [TextDirective, DivQuery]});
loadTranslations(
{'3395826043214005257': '{$START_TAG_NG_TEMPLATE}Contenu{$CLOSE_TAG_NG_TEMPLATE}'});
loadTranslations({
[computeMsgId(
'{$START_TAG_NG_TEMPLATE}{$START_TAG_DIV_1}' +
'{$START_TAG_DIV}' +
'{$START_TAG_SPAN}Content{$CLOSE_TAG_SPAN}' +
'{$CLOSE_TAG_DIV}' +
'{$CLOSE_TAG_DIV}{$CLOSE_TAG_NG_TEMPLATE}')]:
'{$START_TAG_NG_TEMPLATE}Contenu{$CLOSE_TAG_NG_TEMPLATE}'
});
const fixture = initWithTemplate(AppComp, `
<div-query #q i18n>
<ng-template>
@ -1586,6 +1744,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
});
it('should not alloc expando slots when there is no new variable to create', () => {
loadTranslations({
[computeMsgId('{$START_TAG_DIV} Some content {$CLOSE_TAG_DIV}')]:
'{$START_TAG_DIV} Some content {$CLOSE_TAG_DIV}',
[computeMsgId(
'{$START_TAG_SPAN_1}{$ICU}{$CLOSE_TAG_SPAN} - {$START_TAG_SPAN_1}{$ICU_1}{$CLOSE_TAG_SPAN}')]:
'{$START_TAG_SPAN_1}{$ICU}{$CLOSE_TAG_SPAN} - {$START_TAG_SPAN_1}{$ICU_1}{$CLOSE_TAG_SPAN}',
});
@Component({
template: `
<div dialog i18n>

View File

@ -7,23 +7,18 @@
*/
import {CommonModule, DOCUMENT} from '@angular/common';
import {computeMsgId} from '@angular/compiler';
import {Compiler, Component, ComponentFactoryResolver, Directive, DoCheck, ElementRef, EmbeddedViewRef, ErrorHandler, NO_ERRORS_SCHEMA, NgModule, OnInit, Pipe, PipeTransform, QueryList, RendererFactory2, RendererType2, Sanitizer, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core';
import {Input} from '@angular/core/src/metadata';
import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode';
import {TestBed, TestComponentRenderer} from '@angular/core/testing';
import {loadTranslations} from '@angular/localize';
import {clearTranslations, loadTranslations} from '@angular/localize';
import {By, DomSanitizer} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {ivyEnabled, onlyInIvy} from '@angular/private/testing';
describe('ViewContainerRef', () => {
const TRANSLATIONS: any = {
'6587679027921703718': 'o',
'1059980791999999199': 'F{$START_TAG_DIV}{$CLOSE_TAG_DIV}o',
'8808498902423973223': '{$START_TAG_DIV}{$CLOSE_TAG_DIV}{$START_TAG_BEFORE}{$CLOSE_TAG_BEFORE}'
};
/**
* Gets the inner HTML of the given element with all HTML comments and Angular internal
* reflect attributes omitted. This makes HTML comparisons easier and less verbose.
@ -34,7 +29,6 @@ describe('ViewContainerRef', () => {
}
beforeEach(() => {
loadTranslations(TRANSLATIONS);
TestBed.configureTestingModule({
declarations: [
StructDir, ViewContainerRefComp, ViewContainerRefApp, DestroyCasesComp, ConstructorDir,
@ -43,6 +37,8 @@ describe('ViewContainerRef', () => {
});
});
afterEach(() => clearTranslations());
describe('create', () => {
it('should support view queries inside embedded views created in dir constructors', () => {
@ -349,6 +345,12 @@ describe('ViewContainerRef', () => {
onlyInIvy('Ivy i18n logic')
.it('when ViewContainerRef is on an element inside a ng-container with i18n', () => {
loadTranslations({
[computeMsgId('Bar')]: 'o',
[computeMsgId(
'{$START_TAG_BEFORE}{$CLOSE_TAG_BEFORE}{$START_TAG_DIV}{$START_TAG_INSIDE}{$CLOSE_TAG_INSIDE}{$CLOSE_TAG_DIV}{$START_TAG_AFTER}{$CLOSE_TAG_AFTER}')]:
'F{$START_TAG_DIV}{$CLOSE_TAG_DIV}o',
});
executeTest(`
<ng-template #foo>
<span i18n>Bar</span>
@ -368,11 +370,17 @@ describe('ViewContainerRef', () => {
});
onlyInIvy('Ivy i18n logic')
.it('when ViewContainerRef is on an element, and i18n is on the parent ViewContainerRef',
() => {
executeTest(`
.it('when ViewContainerRef is on an element, and i18n is on the parent ViewContainerRef', () => {
loadTranslations({
[computeMsgId(
'{$START_TAG_BEFORE}{$CLOSE_TAG_BEFORE}{$START_TAG_DIV}{$START_TAG_IN}{$CLOSE_TAG_IN}{$CLOSE_TAG_DIV}{$START_TAG_AFTER}{$CLOSE_TAG_AFTER}')]:
'{$START_TAG_DIV}{$CLOSE_TAG_DIV}{$START_TAG_BEFORE}oo{$CLOSE_TAG_BEFORE}',
[computeMsgId('{VAR_SELECT, select, other {|{INTERPOLATION}|}}')]:
'{VAR_SELECT, select, other {|{INTERPOLATION}|}}',
});
executeTest(`
<ng-template #foo>
<span>Foo</span>
<span>F</span>
</ng-template>
<ng-template structDir i18n>
@ -382,7 +390,7 @@ describe('ViewContainerRef', () => {
</div>
<after></after>
</ng-template>`);
});
});
});
describe('length', () => {

View File

@ -8,11 +8,12 @@
// Make the `$localize()` global function available to the compiled templates, and the direct calls
// below. This would normally be done inside the application `polyfills.ts` file.
import '@angular/localize/init';
import {computeMsgId} from '@angular/compiler';
import {loadTranslations} from '@angular/localize';
const translations = {
'6947830843539421219': 'Bonjour Monde!',
'6935800796474951272': 'Bonjour Titre!',
[computeMsgId('Hello World!')]: 'Bonjour Monde!',
[computeMsgId('Hello Title!')]: 'Bonjour Titre!',
};
loadTranslations(translations);

View File

@ -8,30 +8,25 @@
// Make the `$localize()` global function available to the compiled templates, and the direct calls
// below. This would normally be done inside the application `polyfills.ts` file.
import '@angular/localize/init';
import {computeMsgId} from '@angular/compiler';
import {loadTranslations} from '@angular/localize';
export const translations = {
// What needs to be done?
'5102526651904871634': `Qu'y a-t-il à faire ?`,
// {$START_HEADING_LEVEL1}todos{$CLOSE_HEADING_LEVEL1}{$TAG_INPUT}
'8643091609122689720':
[computeMsgId('What needs to be done?', '')]: `Qu'y a-t-il à faire ?`,
[computeMsgId('{$START_HEADING_LEVEL1}todos{$CLOSE_HEADING_LEVEL1}{$TAG_INPUT}', '')]:
'{$START_HEADING_LEVEL1}liste de tâches{$CLOSE_HEADING_LEVEL1}{$TAG_INPUT}',
// {VAR_PLURAL, plural, =1 {item left} other {items left}}
'271375439086996113': '{VAR_PLURAL, plural, =1 {tâche restante} other {tâches restantes}}',
// {$START_TAG_STRONG}{$INTERPOLATION}{$CLOSE_TAG_STRONG}{$ICU}
'4169337202119891309': '{$START_TAG_STRONG}{$INTERPOLATION}{$CLOSE_TAG_STRONG} {$ICU}',
// Clear Completed
'3329962774478249377': ' Effacer terminés ',
// Demonstrate Components
'5738403869589701812': ' Démontrer les components',
// Demonstrate Structural Directives
'4405796757024158842': 'Démontrer les directives structurelles',
// Demonstrate {$value}
'2762077329405284613': 'Démontrer {$value}',
// Demonstrate zoneless change detection
'3484387157632222646': 'Démontrer la détection des changements sans zonejs',
// Demonstrate internationalization
'442837859415373816': `Démontrer l'internationalisation`
[computeMsgId('{VAR_PLURAL, plural, =1 {item left} other {items left}}', '')]:
'{VAR_PLURAL, plural, =1 {tâche restante} other {tâches restantes}}',
[computeMsgId('{$START_TAG_STRONG}{$INTERPOLATION}{$CLOSE_TAG_STRONG}{$ICU}', '')]:
'{$START_TAG_STRONG}{$INTERPOLATION}{$CLOSE_TAG_STRONG} {$ICU}',
[computeMsgId('Clear Completed', '')]: ' Effacer terminés ',
[computeMsgId('Demonstrate Components', '')]: ' Démontrer les components',
[computeMsgId('Demonstrate Structural Directives', '')]: 'Démontrer les directives structurelles',
[computeMsgId('Demonstrate {$value}', '')]: 'Démontrer {$value}',
[computeMsgId('Demonstrate zoneless change detection', '')]:
'Démontrer la détection des changements sans zonejs',
[computeMsgId('Demonstrate internationalization', '')]: `Démontrer l'internationalisation`
};
loadTranslations(translations);

View File

@ -70,6 +70,10 @@ export interface ParsedMessage {
* A human readable rendering of the message
*/
messageString: string;
/**
* The meaning of the `message`, used to distinguish identical `messageString`s.
*/
meaning: string;
}
/**
@ -94,6 +98,7 @@ export function parseMessage(
messageId: metadata.id || computeMsgId(messageString, metadata.meaning || ''),
substitutions,
messageString,
meaning: metadata.meaning || '',
};
}