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$; $I18N_7$ = $MSG_EXTERNAL_6435899732746131543$$APP_SPEC_TS_8$;
} }
else { else {
$I18N_7$ = $localize \`:meaningC|@@6435899732746131543:Title C\`; $I18N_7$ = $localize \`:meaningC|:Title C\`;
} }
const $_c9$ = ["title", $I18N_7$]; const $_c9$ = ["title", $I18N_7$];
var $I18N_11$; var $I18N_11$;
@ -232,7 +232,7 @@ describe('i18n support in the template compiler', () => {
$I18N_11$ = $MSG_EXTERNAL_5200291527729162531$$APP_SPEC_TS_12$; $I18N_11$ = $MSG_EXTERNAL_5200291527729162531$$APP_SPEC_TS_12$;
} }
else { else {
$I18N_11$ = $localize \`:meaningD|descD@@5200291527729162531:Title D\`; $I18N_11$ = $localize \`:meaningD|descD:Title D\`;
} }
const $_c13$ = ["title", $I18N_11$]; const $_c13$ = ["title", $I18N_11$];
var $I18N_15$; var $I18N_15$;
@ -365,7 +365,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_8809028065680254561$$APP_SPEC_TS_1$; $I18N_1$ = $MSG_EXTERNAL_8809028065680254561$$APP_SPEC_TS_1$;
} }
else { else {
$I18N_1$ = $localize \`:m|d@@8809028065680254561:introduction\`; $I18N_1$ = $localize \`:m|d:introduction\`;
} }
const $_c1$ = ["title", $I18N_1$]; 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$; $I18N_1$ = $MSG_EXTERNAL_5526535577705876535$$APP_SPEC_TS_1$;
} }
else { else {
$I18N_1$ = $localize \`:@@5526535577705876535:static text\`; $I18N_1$ = $localize \`static text\`;
} }
var $I18N_2$; var $I18N_2$;
if (ngI18nClosureMode) { if (ngI18nClosureMode) {
@ -416,7 +416,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_8977039798304050198$$APP_SPEC_TS_2$; $I18N_2$ = $MSG_EXTERNAL_8977039798304050198$$APP_SPEC_TS_2$;
} }
else { else {
$I18N_2$ = $localize \`:m|d@@8977039798304050198:intro $` + $I18N_2$ = $localize \`:m|d:intro $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
var $I18N_3$; var $I18N_3$;
@ -431,7 +431,7 @@ describe('i18n support in the template compiler', () => {
$I18N_3$ = $MSG_EXTERNAL_7432761130955693041$$APP_SPEC_TS_3$; $I18N_3$ = $MSG_EXTERNAL_7432761130955693041$$APP_SPEC_TS_3$;
} }
else { else {
$I18N_3$ = $localize \`:m1|d1@@7432761130955693041:$` + $I18N_3$ = $localize \`:m1|d1:$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
const $_c1$ = [ const $_c1$ = [
@ -452,7 +452,7 @@ describe('i18n support in the template compiler', () => {
$I18N_6$ = $MSG_EXTERNAL_7566208596013750546$$APP_SPEC_TS_6$; $I18N_6$ = $MSG_EXTERNAL_7566208596013750546$$APP_SPEC_TS_6$;
} }
else { else {
$I18N_6$ = $localize \`:m2|d2@@7566208596013750546:$` + $I18N_6$ = $localize \`:m2|d2:$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` + String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` +
String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: and again $` + String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: and again $` +
String.raw `{"\uFFFD2\uFFFD"}:INTERPOLATION_2:\`; 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$; $I18N_7$ = $MSG_EXTERNAL_6639222533406278123$$APP_SPEC_TS_7$;
} }
else { else {
$I18N_7$ = $localize \`:@@6639222533406278123:$` + $I18N_7$ = $localize \`$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
const $_c3$ = [ const $_c3$ = [
@ -516,7 +516,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_8977039798304050198$; $I18N_1$ = $MSG_EXTERNAL_8977039798304050198$;
} }
else { else {
$I18N_1$ = $localize \`:m|d@@8977039798304050198:intro $` + $I18N_1$ = $localize \`:m|d:intro $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
const $_c3$ = ["title", $I18N_1$]; 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$; $I18N_1$ = $MSG_EXTERNAL_8538466649243975456$$APP_SPEC_TS__1$;
} }
else { else {
$I18N_1$ = $localize \`:m|d@@8538466649243975456:different scope $` + $I18N_1$ = $localize \`:m|d:different scope $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
const $_c2$ = ["title", $I18N_1$]; 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$; $I18N_1$ = $MSG_EXTERNAL_3462388422673575127$$APP_SPEC_TS_2$;
} }
else { else {
$I18N_1$ = $localize \`:@@3462388422673575127:$` + $I18N_1$ = $localize \`$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: title\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: title\`;
} }
const $_c3$ = ["title", $I18N_1$]; 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$; $I18N_1$ = $MSG_EXTERNAL_5526535577705876535$$APP_SPEC_TS_1$;
} }
else { else {
$I18N_1$ = $localize \`:@@5526535577705876535:static text\`; $I18N_1$ = $localize \`static text\`;
} }
var $I18N_2$; var $I18N_2$;
if (ngI18nClosureMode) { if (ngI18nClosureMode) {
@ -672,7 +672,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_8977039798304050198$$APP_SPEC_TS_2$; $I18N_2$ = $MSG_EXTERNAL_8977039798304050198$$APP_SPEC_TS_2$;
} }
else { else {
$I18N_2$ = $localize \`:m|d@@8977039798304050198:intro $` + $I18N_2$ = $localize \`:m|d:intro $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
var $I18N_3$; var $I18N_3$;
@ -687,7 +687,7 @@ describe('i18n support in the template compiler', () => {
$I18N_3$ = $MSG_EXTERNAL_7432761130955693041$$APP_SPEC_TS_3$; $I18N_3$ = $MSG_EXTERNAL_7432761130955693041$$APP_SPEC_TS_3$;
} }
else { else {
$I18N_3$ = $localize \`:m1|d1@@7432761130955693041:$` + $I18N_3$ = $localize \`:m1|d1:$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
const $_c1$ = [ const $_c1$ = [
@ -708,7 +708,7 @@ describe('i18n support in the template compiler', () => {
$I18N_6$ = $MSG_EXTERNAL_7566208596013750546$$APP_SPEC_TS_6$; $I18N_6$ = $MSG_EXTERNAL_7566208596013750546$$APP_SPEC_TS_6$;
} }
else { else {
$I18N_6$ = $localize \`:m2|d2@@7566208596013750546:$` + $I18N_6$ = $localize \`:m2|d2:$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` + String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` +
String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: and again $` + String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: and again $` +
String.raw `{"\uFFFD2\uFFFD"}:INTERPOLATION_2:\`; 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$; $I18N_7$ = $MSG_EXTERNAL_6639222533406278123$$APP_SPEC_TS_7$;
} }
else { else {
$I18N_7$ = $localize \`:@@6639222533406278123:$` + $I18N_7$ = $localize \`$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
const $_c3$ = [ const $_c3$ = [
@ -775,7 +775,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_8538466649243975456$$APP_SPEC_TS__3$; $I18N_2$ = $MSG_EXTERNAL_8538466649243975456$$APP_SPEC_TS__3$;
} }
else { else {
$I18N_2$ = $localize \`:m|d@@8538466649243975456:different scope $` + $I18N_2$ = $localize \`:m|d:different scope $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
const $_c4$ = ["title", $I18N_2$]; 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$; $I18N_0$ = $MSG_EXTERNAL_7727043314656808423$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:m|d@@7727043314656808423:Element title\`; $I18N_0$ = $localize \`:m|d:Element title\`;
} }
const $_c1$ = ["title", $I18N_0$]; const $_c1$ = ["title", $I18N_0$];
var $I18N_2$; var $I18N_2$;
@ -836,7 +836,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_4969674997806975147$$APP_SPEC_TS_2$; $I18N_2$ = $MSG_EXTERNAL_4969674997806975147$$APP_SPEC_TS_2$;
} }
else { else {
$I18N_2$ = $localize \`:@@4969674997806975147:Some content\`; $I18N_2$ = $localize \`Some content\`;
} }
template: function MyComponent_Template(rf, ctx) { template: function MyComponent_Template(rf, ctx) {
@ -926,7 +926,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_APP_SPEC_TS_1$; $I18N_0$ = $MSG_APP_SPEC_TS_1$;
} }
else { else {
$I18N_0$ = $localize \`:@@3784161717320915177:Some text\`; $I18N_0$ = $localize \`Some text\`;
} }
`; `;
verify(input, output); verify(input, output);
@ -944,7 +944,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_4924931801512133405$$APP_SPEC_TS_0$; $I18N_0$ = $MSG_EXTERNAL_4924931801512133405$$APP_SPEC_TS_0$;
} }
else { 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$; $I18N_0$ = $MSG_EXTERNAL_4890179241114413722$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@4890179241114413722:My i18n block #1\`; $I18N_0$ = $localize \`My i18n block #1\`;
} }
var $I18N_1$; var $I18N_1$;
if (ngI18nClosureMode) { if (ngI18nClosureMode) {
@ -975,7 +975,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_2413150872298537152$$APP_SPEC_TS_1$; $I18N_1$ = $MSG_EXTERNAL_2413150872298537152$$APP_SPEC_TS_1$;
} }
else { else {
$I18N_1$ = $localize \`:@@2413150872298537152:My i18n block #2\`; $I18N_1$ = $localize \`My i18n block #2\`;
} }
var $I18N_2$; var $I18N_2$;
if (ngI18nClosureMode) { if (ngI18nClosureMode) {
@ -983,7 +983,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_5023003143537152794$$APP_SPEC_TS_2$; $I18N_2$ = $MSG_EXTERNAL_5023003143537152794$$APP_SPEC_TS_2$;
} }
else { else {
$I18N_2$ = $localize \`:@@5023003143537152794:My i18n block #3\`; $I18N_2$ = $localize \`My i18n block #3\`;
} }
template: function MyComponent_Template(rf, ctx) { 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$; $I18N_0$ = $MSG_EXTERNAL_7597881511811528589$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@7597881511811528589: Named interpolation: $` + $I18N_0$ = $localize \` Named interpolation: $` +
String.raw `{"\uFFFD0\uFFFD"}:PH_A: Named interpolation with spaces: $` + String.raw `{"\uFFFD0\uFFFD"}:PH_A: Named interpolation with spaces: $` +
String.raw `{"\uFFFD1\uFFFD"}:PH_B: \`; 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$; $I18N_0$ = $MSG_EXTERNAL_6749967533321674787$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@6749967533321674787:$` + $I18N_0$ = $localize \`$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; 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$; $I18N_0$ = $MSG_APP_SPEC_TS_1$$APP_SPEC_TS_1$;
} }
else { else {
$I18N_0$ = $localize \`:@@1194644703943451474: $` + $I18N_0$ = $localize \` $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` +
String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: $` + String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: $` +
String.raw `{"\uFFFD2\uFFFD"}:INTERPOLATION_2: \`; 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$; $I18N_0$ = $MSG_EXTERNAL_572579892698764378$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@572579892698764378:My i18n block #$` + $I18N_0$ = $localize \`My i18n block #$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
var $I18N_1$; var $I18N_1$;
@ -1155,7 +1155,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_609623417156596326$$APP_SPEC_TS_1$; $I18N_1$ = $MSG_EXTERNAL_609623417156596326$$APP_SPEC_TS_1$;
} }
else { else {
$I18N_1$ = $localize \`:@@609623417156596326:My i18n block #$` + $I18N_1$ = $localize \`My i18n block #$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
var $I18N_2$; var $I18N_2$;
@ -1166,7 +1166,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_3998119318957372120$$APP_SPEC_TS_2$; $I18N_2$ = $MSG_EXTERNAL_3998119318957372120$$APP_SPEC_TS_2$;
} }
else { else {
$I18N_2$ = $localize \`:@@3998119318957372120:My i18n block #$` + $I18N_2$ = $localize \`My i18n block #$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; 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$; $I18N_0$ = $MSG_EXTERNAL_7905233330103651696$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@7905233330103651696: My i18n block #$` + $I18N_0$ = $localize \` My i18n block #$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` +
String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_SPAN:Plain text in nested element$` + String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_SPAN:Plain text in nested element$` +
String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_SPAN:\`; 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$; $I18N_1$ = $MSG_EXTERNAL_5788821996131681377$$APP_SPEC_TS_1$;
} }
else { else {
$I18N_1$ = $localize \`:@@5788821996131681377: My i18n block #$` + $I18N_1$ = $localize \` My i18n block #$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + 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 `{"[\uFFFD#6\uFFFD|\uFFFD#7\uFFFD]"}:START_TAG_DIV:$` + String.raw 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$; $I18N_2$ = $MSG_EXTERNAL_4782264005467235841$$APP_SPEC_TS_3$;
} }
else { else {
$I18N_2$ = $localize \`:@@4782264005467235841:Span title $` + $I18N_2$ = $localize \`Span title $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` + String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` +
String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1:\`; 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$; $I18N_0$ = $MSG_EXTERNAL_4446430594603971069$$APP_SPEC_TS_5$;
} }
else { 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 String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + String.raw
`{"\uFFFD#2\uFFFD"}:START_TAG_SPAN: Plain text in nested element (block #1) $` + `{"\uFFFD#2\uFFFD"}:START_TAG_SPAN: Plain text in nested element (block #1) $` +
String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_SPAN:\`; 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$; $I18N_7$ = $MSG_EXTERNAL_2719594642740200058$$APP_SPEC_TS_8$;
} }
else { else {
$I18N_7$ = $localize \`:@@2719594642740200058:Span title $` + $I18N_7$ = $localize \`Span title $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
const $_c9$ = ["title", $I18N_7$]; 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$; $I18N_6$ = $MSG_EXTERNAL_2778714953278357902$$APP_SPEC_TS_10$;
} }
else { 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 String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + String.raw
`{"\uFFFD#7\uFFFD"}:START_TAG_SPAN: Plain text in nested element (block #2) $` + `{"\uFFFD#7\uFFFD"}:START_TAG_SPAN: Plain text in nested element (block #2) $` +
String.raw `{"\uFFFD/#7\uFFFD"}:CLOSE_TAG_SPAN:\`; 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$; $I18N_1$ = $MSG_EXTERNAL_7679414751795588050$$APP_SPEC_TS__1$;
} }
else { else {
$I18N_1$ = $localize \`:@@7679414751795588050: Some other content $` + $I18N_1$ = $localize \` Some other content $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` +
String.raw `{"\uFFFD#3\uFFFD"}:START_TAG_DIV: More nested levels with bindings $` + String.raw `{"\uFFFD#3\uFFFD"}:START_TAG_DIV: More nested levels with bindings $` +
String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: $` + 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$; $I18N_2$ = $MSG_EXTERNAL_2367729185105559721$$APP_SPEC_TS__2$;
} }
else { else {
$I18N_2$ = $localize \`:@@2367729185105559721:App logo #$` + $I18N_2$ = $localize \`App logo #$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
const $_c4$ = ["title", $I18N_2$]; 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$; $I18N_0$ = $MSG_EXTERNAL_1221890473527419724$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@1221890473527419724: Some content $` + $I18N_0$ = $localize \` Some content $` +
String.raw String.raw
`{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_DIV_2: Some other content $` + `{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_DIV_2: Some other content $` +
String.raw `{"\uFFFD0:1\uFFFD"}:INTERPOLATION: $` + String.raw 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$; $I18N_1$ = $MSG_EXTERNAL_119975189388320493$$APP_SPEC_TS__1$;
} }
else { else {
$I18N_1$ = $localize \`:@@119975189388320493:Some other content $` + $I18N_1$ = $localize \`Some other content $` +
String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_SPAN:$` + String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_SPAN:$` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:$` + String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:$` +
String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_SPAN:\`; 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$; $I18N_1$ = $MSG_APP_SPEC_TS_2$;
} }
else { else {
$I18N_1$ = $localize \`:@@3902961887793684628:Hello\`; $I18N_1$ = $localize \`Hello\`;
} }
template: function MyComponent_Template(rf, ctx) { 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$; $I18N_0$ = $MSG_EXTERNAL_4890179241114413722$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@4890179241114413722:My i18n block #1\`; $I18N_0$ = $localize \`My i18n block #1\`;
} }
template: function MyComponent_Template(rf, ctx) { 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$; $I18N_0$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$;
} }
else { 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$, { $I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -1839,7 +1839,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_2413150872298537152$$APP_SPEC_TS_0$; $I18N_0$ = $MSG_EXTERNAL_2413150872298537152$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@2413150872298537152:My i18n block #2\`; $I18N_0$ = $localize \`My i18n block #2\`;
} }
var $I18N_1$; var $I18N_1$;
if (ngI18nClosureMode) { if (ngI18nClosureMode) {
@ -1847,7 +1847,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_4890179241114413722$$APP_SPEC_TS__1$; $I18N_1$ = $MSG_EXTERNAL_4890179241114413722$$APP_SPEC_TS__1$;
} }
else { else {
$I18N_1$ = $localize \`:@@4890179241114413722:My i18n block #1\`; $I18N_1$ = $localize \`My i18n block #1\`;
} }
function MyComponent_ng_template_0_Template(rf, ctx) { function MyComponent_ng_template_0_Template(rf, ctx) {
if (rf & 1) { if (rf & 1) {
@ -1882,7 +1882,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_5295701706185791735$$APP_SPEC_TS_1$; $I18N_1$ = $MSG_EXTERNAL_5295701706185791735$$APP_SPEC_TS_1$;
} }
else { else {
$I18N_1$ = $localize \`:@@5295701706185791735:Text #1\`; $I18N_1$ = $localize \`Text #1\`;
} }
const $_c2$ = [${AttributeMarker.Styles}, "padding", "10px"]; const $_c2$ = [${AttributeMarker.Styles}, "padding", "10px"];
var $I18N_3$; var $I18N_3$;
@ -1891,7 +1891,7 @@ describe('i18n support in the template compiler', () => {
$I18N_3$ = $MSG_EXTERNAL_4722270221386399294$$APP_SPEC_TS_3$; $I18N_3$ = $MSG_EXTERNAL_4722270221386399294$$APP_SPEC_TS_3$;
} }
else { else {
$I18N_3$ = $localize \`:@@4722270221386399294:Text #2\`; $I18N_3$ = $localize \`Text #2\`;
} }
consts: 4, consts: 4,
@ -1927,7 +1927,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_355394464191978948$$APP_SPEC_TS_0$; $I18N_0$ = $MSG_EXTERNAL_355394464191978948$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@355394464191978948:Some content: $` + $I18N_0$ = $localize \`Some content: $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; 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$; $I18N_0$ = $MSG_EXTERNAL_355394464191978948$$APP_SPEC_TS__0$;
} }
else { else {
$I18N_0$ = $localize \`:@@355394464191978948:Some content: $` + $I18N_0$ = $localize \`Some content: $` +
String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`;
} }
function MyComponent_ng_template_0_Template(rf, ctx) { 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$; $I18N_0$ = $MSG_EXTERNAL_702706566400598764$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@702706566400598764:$` + $I18N_0$ = $localize \`$` +
String.raw `{"\uFFFD*2:1\uFFFD"}:START_TAG_NG_TEMPLATE:Template content: $` + String.raw `{"\uFFFD*2:1\uFFFD"}:START_TAG_NG_TEMPLATE:Template content: $` +
String.raw `{"\uFFFD0:1\uFFFD"}:INTERPOLATION:$` + String.raw `{"\uFFFD0:1\uFFFD"}:INTERPOLATION:$` +
String.raw `{"\uFFFD/*2:1\uFFFD"}:CLOSE_TAG_NG_TEMPLATE:$` + 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$; $I18N_0$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$;
} }
else { 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$, { $I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -2078,7 +2078,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS__1$; $I18N_1$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS__1$;
} }
else { 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$, { $I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -2163,7 +2163,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_2051477021417799640$$APP_SPEC_TS_0$; $I18N_0$ = $MSG_EXTERNAL_2051477021417799640$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@2051477021417799640:$` + $I18N_0$ = $localize \`$` +
String.raw String.raw
`{"[\uFFFD*2:1\uFFFD|\uFFFD*2:2\uFFFD|\uFFFD*1:3\uFFFD]"}:START_TAG_NG_TEMPLATE: Template A: $` + `{"[\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 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$; $I18N_0$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_0$;
} }
else { 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$, { $I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -2232,7 +2232,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS__1$; $I18N_1$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS__1$;
} }
else { 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$, { $I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -2287,7 +2287,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_4891196282781544695$$APP_SPEC_TS_0$; $I18N_0$ = $MSG_EXTERNAL_4891196282781544695$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@4891196282781544695:$` + $I18N_0$ = $localize \`$` +
String.raw `{"\uFFFD#2\uFFFD\uFFFD/#2\uFFFD"}:TAG_IMG: is my logo #1 \`; String.raw `{"\uFFFD#2\uFFFD\uFFFD/#2\uFFFD"}:TAG_IMG: is my logo #1 \`;
} }
var $I18N_2$; var $I18N_2$;
@ -2298,7 +2298,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_461986953980355147$$APP_SPEC_TS__2$; $I18N_2$ = $MSG_EXTERNAL_461986953980355147$$APP_SPEC_TS__2$;
} }
else { else {
$I18N_2$ = $localize \`:@@461986953980355147:$` + $I18N_2$ = $localize \`$` +
String.raw `{"\uFFFD#1\uFFFD\uFFFD/#1\uFFFD"}:TAG_IMG: is my logo #2 \`; String.raw `{"\uFFFD#1\uFFFD\uFFFD/#1\uFFFD"}:TAG_IMG: is my logo #2 \`;
} }
function MyComponent_ng_template_3_Template(rf, ctx) { 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$; $I18N_0$ = $MSG_EXTERNAL_8537814667662432133$$APP_SPEC_TS__0$;
} }
else { else {
$I18N_0$ = $localize \`:@@8537814667662432133: Root content $` + $I18N_0$ = $localize \` Root content $` +
String.raw String.raw
`{"\uFFFD*1:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_NG_CONTAINER: Nested content $` + `{"\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:\`; 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$; $I18N_0$ = $MSG_EXTERNAL_6563391987554512024$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@6563391987554512024:Test\`; $I18N_0$ = $localize \`Test\`;
} }
var $I18N_1$; var $I18N_1$;
if (ngI18nClosureMode) { if (ngI18nClosureMode) {
@ -2379,7 +2379,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_6563391987554512024$$APP_SPEC_TS_1$; $I18N_1$ = $MSG_EXTERNAL_6563391987554512024$$APP_SPEC_TS_1$;
} }
else { 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$; $I18N_0$ = $MSG_APP_SPEC_TS_1$;
} }
else { 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"}:START_TAG_NG_CONTAINER:there$` +
String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_NG_CONTAINER:\`; 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$; $I18N_0$ = $MSG_APP_SPEC_TS_1$;
} }
else { else {
$I18N_0$ = $localize \`:@@1968828034476446869: Hello $` + $I18N_0$ = $localize \` Hello $` +
String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_NG_CONTAINER:there $` + String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_NG_CONTAINER:there $` +
String.raw `{"\uFFFD#3\uFFFD"}:START_TAG_STRONG:!$` + String.raw `{"\uFFFD#3\uFFFD"}:START_TAG_STRONG:!$` +
String.raw `{"\uFFFD/#3\uFFFD"}:CLOSE_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"); const $MSG_EXTERNAL_3308216566145348998$$APP_SPEC_TS___2$ = goog.getMsg("Content A");
$I18N_1$ = $MSG_EXTERNAL_3308216566145348998$$APP_SPEC_TS___2$; $I18N_1$ = $MSG_EXTERNAL_3308216566145348998$$APP_SPEC_TS___2$;
} else { } else {
$I18N_1$ = $localize \`:@@3308216566145348998:Content A\`; $I18N_1$ = $localize \`Content A\`;
} }
function MyComponent_0_ng_template_0_Template(rf, ctx) { function MyComponent_0_ng_template_0_Template(rf, ctx) {
if (rf & 1) { 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"); const $MSG_EXTERNAL_8349021389088127654$$APP_SPEC_TS__4$ = goog.getMsg("Content B");
$I18N_3$ = $MSG_EXTERNAL_8349021389088127654$$APP_SPEC_TS__4$; $I18N_3$ = $MSG_EXTERNAL_8349021389088127654$$APP_SPEC_TS__4$;
} else { } else {
$I18N_3$ = $localize \`:@@8349021389088127654:Content B\`; $I18N_3$ = $localize \`Content B\`;
} }
function MyComponent_ng_container_1_Template(rf, ctx) { function MyComponent_ng_container_1_Template(rf, ctx) {
if (rf & 1) { if (rf & 1) {
@ -2541,7 +2541,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_963542717423364282$$APP_SPEC_TS_0$; $I18N_0$ = $MSG_EXTERNAL_963542717423364282$$APP_SPEC_TS_0$;
} }
else { 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"}:START_TAG_SPAN:Text inside span$` +
String.raw `{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_SPAN:\n \`; 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$; $I18N_0$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_0$;
} }
else { 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$, { $I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -2612,7 +2612,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_4166854826696768832$$APP_SPEC_TS_0$; $I18N_0$ = $MSG_EXTERNAL_4166854826696768832$$APP_SPEC_TS_0$;
} }
else { 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$, { $I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -2634,7 +2634,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$; $I18N_0$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$;
} }
else { 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$, { $I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -2674,7 +2674,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_0$; $I18N_0$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_0$;
} }
else { 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$, { $I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -2688,7 +2688,7 @@ describe('i18n support in the template compiler', () => {
$I18N_3$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS__3$; $I18N_3$ = $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS__3$;
} }
else { 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$, { $I18N_3$ = $r3$.ɵɵi18nPostprocess($I18N_3$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -2714,7 +2714,7 @@ describe('i18n support in the template compiler', () => {
$I18N_5$ = $MSG_EXTERNAL_1922743304863699161$$APP_SPEC_TS__5$; $I18N_5$ = $MSG_EXTERNAL_1922743304863699161$$APP_SPEC_TS__5$;
} }
else { 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$, { $I18N_5$ = $r3$.ɵɵi18nPostprocess($I18N_5$, {
"VAR_SELECT": "\uFFFD0\uFFFD", "VAR_SELECT": "\uFFFD0\uFFFD",
@ -2771,7 +2771,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_2949673783721159566$$APP_SPEC_TS_0$; $I18N_0$ = $MSG_EXTERNAL_2949673783721159566$$APP_SPEC_TS_0$;
} }
else { 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$, { $I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD", "VAR_SELECT": "\uFFFD0\uFFFD",
@ -2810,7 +2810,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_2417296354340576868$$APP_SPEC_TS_1$; $I18N_1$ = $MSG_EXTERNAL_2417296354340576868$$APP_SPEC_TS_1$;
} }
else { 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$, { $I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD", "VAR_SELECT": "\uFFFD0\uFFFD",
@ -2836,7 +2836,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_5791551881115084301$$APP_SPEC_TS_0$; $I18N_0$ = $MSG_EXTERNAL_5791551881115084301$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@5791551881115084301: $` + $I18N_0$ = $localize \` $` +
String.raw `{$I18N_1$}:ICU: $` + String.raw `{$I18N_1$}:ICU: $` +
String.raw `{"\uFFFD#2\uFFFD"}:START_BOLD_TEXT:Other content$` + String.raw `{"\uFFFD#2\uFFFD"}:START_BOLD_TEXT:Other content$` +
String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_BOLD_TEXT:$` + 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$; $I18N_0$ = $MSG_EXTERNAL_6879461626778511059$$APP_SPEC_TS_0$;
} }
else { 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$, { $I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD", "VAR_SELECT": "\uFFFD0\uFFFD",
@ -2921,7 +2921,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_1$; $I18N_1$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_1$;
} }
else { 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$, { $I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -2932,7 +2932,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_EXTERNAL_7068143081688428291$$APP_SPEC_TS_2$; $I18N_2$ = $MSG_EXTERNAL_7068143081688428291$$APP_SPEC_TS_2$;
} }
else { 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$, { $I18N_2$ = $r3$.ɵɵi18nPostprocess($I18N_2$, {
"VAR_SELECT": "\uFFFD1\uFFFD" "VAR_SELECT": "\uFFFD1\uFFFD"
@ -2946,7 +2946,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_2967249209167308918$$APP_SPEC_TS_0$; $I18N_0$ = $MSG_EXTERNAL_2967249209167308918$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@2967249209167308918: $` + $I18N_0$ = $localize \` $` +
String.raw `{$I18N_1$}:ICU: $` + String.raw `{$I18N_2$}:ICU_1: \`; 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$; $I18N_1$ = $MSG_APP_SPEC_TS_1$;
} }
else { 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$, { $I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -2999,7 +2999,7 @@ describe('i18n support in the template compiler', () => {
$I18N_2$ = $MSG_APP_SPEC_TS_2$; $I18N_2$ = $MSG_APP_SPEC_TS_2$;
} }
else { 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$, { $I18N_2$ = $r3$.ɵɵi18nPostprocess($I18N_2$, {
"VAR_SELECT": "\uFFFD1\uFFFD" "VAR_SELECT": "\uFFFD1\uFFFD"
@ -3011,7 +3011,7 @@ describe('i18n support in the template compiler', () => {
$I18N_4$ = $MSG_APP_SPEC_TS__4$; $I18N_4$ = $MSG_APP_SPEC_TS__4$;
} }
else { 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$, { $I18N_4$ = $r3$.ɵɵi18nPostprocess($I18N_4$, {
"VAR_SELECT": "\uFFFD0:1\uFFFD" "VAR_SELECT": "\uFFFD0:1\uFFFD"
@ -3027,7 +3027,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_APP_SPEC_TS_0$; $I18N_0$ = $MSG_APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@7986645988117050801: $` + $I18N_0$ = $localize \` $` +
String.raw `{"\uFFFDI18N_EXP_ICU\uFFFD"}:ICU: $` + String.raw `{"\uFFFDI18N_EXP_ICU\uFFFD"}:ICU: $` +
String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_DIV: $` + String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_DIV: $` +
String.raw `{"\uFFFDI18N_EXP_ICU\uFFFD"}:ICU: $` + String.raw 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$; $I18N_1$ = $MSG_EXTERNAL_343563413083115114$$APP_SPEC_TS_0$;
} }
else { 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$, { $I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD", "VAR_SELECT": "\uFFFD0\uFFFD",
@ -3108,7 +3108,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_3052001905251380936$$APP_SPEC_TS_3$; $I18N_0$ = $MSG_EXTERNAL_3052001905251380936$$APP_SPEC_TS_3$;
} }
else { else {
$I18N_0$ = $localize \`:@@3052001905251380936: $` + $I18N_0$ = $localize \` $` +
String.raw `{$I18N_1$}:ICU: \`; String.raw `{$I18N_1$}:ICU: \`;
} }
consts: 2, consts: 2,
@ -3151,7 +3151,7 @@ describe('i18n support in the template compiler', () => {
$I18N_0$ = $MSG_EXTERNAL_6870293071705078389$$APP_SPEC_TS_1$; $I18N_0$ = $MSG_EXTERNAL_6870293071705078389$$APP_SPEC_TS_1$;
} }
else { 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$, { $I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD", "VAR_SELECT": "\uFFFD0\uFFFD",
@ -3194,7 +3194,7 @@ describe('i18n support in the template compiler', () => {
$I18N_1$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_1$; $I18N_1$ = $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_1$;
} }
else { 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$, { $I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD" "VAR_SELECT": "\uFFFD0\uFFFD"
@ -3206,7 +3206,7 @@ describe('i18n support in the template compiler', () => {
$I18N_3$ = $MSG_EXTERNAL_7068143081688428291$$APP_SPEC_TS__3$; $I18N_3$ = $MSG_EXTERNAL_7068143081688428291$$APP_SPEC_TS__3$;
} }
else { 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$, { $I18N_3$ = $r3$.ɵɵi18nPostprocess($I18N_3$, {
"VAR_SELECT": "\uFFFD0:1\uFFFD" "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$; $I18N_0$ = $MSG_EXTERNAL_1194472282609532229$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@1194472282609532229: $` + $I18N_0$ = $localize \` $` +
String.raw `{$I18N_1$}:ICU: $` + String.raw `{$I18N_1$}:ICU: $` +
String.raw `{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_SPAN: $` + String.raw `{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_SPAN: $` +
String.raw `{$I18N_3$}:ICU_1: $` + 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$; $I18N_1$ = $MSG_EXTERNAL_7825031864601787094$$APP_SPEC_TS_1$;
} }
else { 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$, { $I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$, {
"VAR_SELECT": "\uFFFD0\uFFFD", "VAR_SELECT": "\uFFFD0\uFFFD",
@ -3294,7 +3294,7 @@ describe('i18n support in the template compiler', () => {
$I18N_4$ = $MSG_EXTERNAL_2310343208266678305$$APP_SPEC_TS__3$; $I18N_4$ = $MSG_EXTERNAL_2310343208266678305$$APP_SPEC_TS__3$;
} }
else { 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$, { $I18N_4$ = $r3$.ɵɵi18nPostprocess($I18N_4$, {
"VAR_SELECT": "\uFFFD0:1\uFFFD", "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$; $I18N_0$ = $MSG_EXTERNAL_7186042105600518133$$APP_SPEC_TS_0$;
} }
else { else {
$I18N_0$ = $localize \`:@@7186042105600518133: $` + $I18N_0$ = $localize \` $` +
String.raw `{I18N_1}:ICU: $` + String.raw `{I18N_1}:ICU: $` +
String.raw `{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_SPAN: $` + String.raw `{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_SPAN: $` +
String.raw `{I18N_4}:ICU_1: $` + 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$; $I18N_0$ = $MSG_EXTERNAL_6318060397235942326$$APP_SPEC_TS_0$;
} }
else { 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$, { $I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, {
"VAR_SELECT": "\uFFFD0\uFFFD", "VAR_SELECT": "\uFFFD0\uFFFD",

View File

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

View File

@ -10,6 +10,7 @@ import {ParseSourceSpan} from '../parse_util';
export class Message { export class Message {
sources: MessageSpan[]; sources: MessageSpan[];
id: string = this.customId;
/** /**
* @param nodes message AST * @param nodes message AST
@ -22,7 +23,7 @@ export class Message {
constructor( constructor(
public nodes: Node[], public placeholders: {[phName: string]: string}, public nodes: Node[], public placeholders: {[phName: string]: string},
public placeholderToMessage: {[phName: string]: Message}, public meaning: string, public placeholderToMessage: {[phName: string]: Message}, public meaning: string,
public description: string, public id: string) { public description: string, public customId: string) {
if (nodes.length) { if (nodes.length) {
this.sources = [{ this.sources = [{
filePath: nodes[0].sourceSpan.start.file.url, 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 = { export type I18nMeta = {
id?: string, id?: string,
customId?: string,
description?: string, description?: string,
meaning?: string meaning?: string
}; };
@ -47,7 +48,7 @@ export class I18nMetaVisitor implements html.Visitor {
const parsed: I18nMeta = const parsed: I18nMeta =
typeof meta === 'string' ? parseI18nMeta(meta) : metaFromI18nMessage(meta as i18n.Message); typeof meta === 'string' ? parseI18nMeta(meta) : metaFromI18nMessage(meta as i18n.Message);
const message = this._createI18nMessage( const message = this._createI18nMessage(
nodes, parsed.meaning || '', parsed.description || '', parsed.id || '', visitNodeFn); nodes, parsed.meaning || '', parsed.description || '', parsed.customId || '', visitNodeFn);
if (!message.id) { if (!message.id) {
// generate (or restore) message id if not specified in template // generate (or restore) message id if not specified in template
message.id = typeof meta !== 'string' && (meta as i18n.Message).id || decimalDigest(message); 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 { export function metaFromI18nMessage(message: i18n.Message, id: string | null = null): I18nMeta {
return { return {
id: typeof id === 'string' ? id : message.id || '', id: typeof id === 'string' ? id : message.id || '',
customId: message.customId,
meaning: message.meaning || '', meaning: message.meaning || '',
description: message.description || '' description: message.description || ''
}; };
@ -160,7 +162,7 @@ const I18N_ID_SEPARATOR = '@@';
* @returns Object with id, meaning and description fields * @returns Object with id, meaning and description fields
*/ */
export function parseI18nMeta(meta?: string): I18nMeta { export function parseI18nMeta(meta?: string): I18nMeta {
let id: string|undefined; let customId: string|undefined;
let meaning: string|undefined; let meaning: string|undefined;
let description: string|undefined; let description: string|undefined;
@ -168,14 +170,14 @@ export function parseI18nMeta(meta?: string): I18nMeta {
const idIndex = meta.indexOf(I18N_ID_SEPARATOR); const idIndex = meta.indexOf(I18N_ID_SEPARATOR);
const descIndex = meta.indexOf(I18N_MEANING_SEPARATOR); const descIndex = meta.indexOf(I18N_MEANING_SEPARATOR);
let meaningAndDesc: string; let meaningAndDesc: string;
[meaningAndDesc, id] = [meaningAndDesc, customId] =
(idIndex > -1) ? [meta.slice(0, idIndex), meta.slice(idIndex + 2)] : [meta, '']; (idIndex > -1) ? [meta.slice(0, idIndex), meta.slice(idIndex + 2)] : [meta, ''];
[meaning, description] = (descIndex > -1) ? [meaning, description] = (descIndex > -1) ?
[meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] : [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] :
['', meaningAndDesc]; ['', meaningAndDesc];
} }
return {id, meaning, description}; return {customId, meaning, description};
} }
/** /**
@ -190,8 +192,8 @@ export function serializeI18nHead(meta: I18nMeta, messagePart: string): string {
if (meta.meaning) { if (meta.meaning) {
metaBlock = `${meta.meaning}|${metaBlock}`; metaBlock = `${meta.meaning}|${metaBlock}`;
} }
if (meta.id) { if (meta.customId) {
metaBlock = `${metaBlock}@@${meta.id}`; metaBlock = `${metaBlock}@@${meta.customId}`;
} }
if (metaBlock === '') { if (metaBlock === '') {
// There is no metaBlock, so we must ensure that any starting colon is escaped. // 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: '', meaning: '',
description: '', description: '',
sources: [], sources: [],
customId: 'i',
})).toEqual('i'); })).toEqual('i');
}); });
}); });

View File

@ -241,8 +241,8 @@ describe('Utils', () => {
expect(serializeI18nTemplatePart('abc', ':message')).toEqual(':abc::message'); expect(serializeI18nTemplatePart('abc', ':message')).toEqual(':abc::message');
}); });
function meta(id?: string, meaning?: string, description?: string): I18nMeta { function meta(customId?: string, meaning?: string, description?: string): I18nMeta {
return {id, meaning, description}; 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 {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 {setDelayProjection} from '@angular/core/src/render3/instructions/projection';
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {loadTranslations} from '@angular/localize'; import {loadTranslations, clearTranslations} from '@angular/localize';
import {By} from '@angular/platform-browser'; import {By} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers'; import {expect} from '@angular/platform-browser/testing/src/matchers';
import {onlyInIvy} from '@angular/private/testing'; import {onlyInIvy} from '@angular/private/testing';
import {computeMsgId} from '@angular/compiler';
onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
@ -24,16 +25,19 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
TestBed.configureTestingModule({declarations: [AppComp, DirectiveWithTplRef, UppercasePipe]}); TestBed.configureTestingModule({declarations: [AppComp, DirectiveWithTplRef, UppercasePipe]});
}); });
afterEach(() => { setDelayProjection(false); }); afterEach(() => {
setDelayProjection(false);
clearTranslations();
});
it('should translate text', () => { it('should translate text', () => {
loadTranslations({'3667842621564887364': 'texte'}); loadTranslations({[computeMsgId('text')]: 'texte'});
const fixture = initWithTemplate(AppComp, `<div i18n>text</div>`); const fixture = initWithTemplate(AppComp, `<div i18n>text</div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div>texte</div>`); expect(fixture.nativeElement.innerHTML).toEqual(`<div>texte</div>`);
}); });
it('should support interpolations', () => { it('should support interpolations', () => {
loadTranslations({'4848371593517801531': 'Bonjour {$INTERPOLATION}!'}); loadTranslations({[computeMsgId('Hello {$INTERPOLATION}!')]: 'Bonjour {$INTERPOLATION}!'});
const fixture = initWithTemplate(AppComp, `<div i18n>Hello {{name}}!</div>`); const fixture = initWithTemplate(AppComp, `<div i18n>Hello {{name}}!</div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div>Bonjour Angular!</div>`); expect(fixture.nativeElement.innerHTML).toEqual(`<div>Bonjour Angular!</div>`);
fixture.componentRef.instance.name = `John`; fixture.componentRef.instance.name = `John`;
@ -42,8 +46,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('should support named interpolations', () => { it('should support named interpolations', () => {
loadTranslations( loadTranslations({
{'5429622669757720522': ' Bonjour {$USER_NAME}! Emails: {$AMOUNT_OF_EMAILS_RECEIVED} '}); [computeMsgId(' Hello {$USER_NAME}! Emails: {$AMOUNT_OF_EMAILS_RECEIVED} ')]:
' Bonjour {$USER_NAME}! Emails: {$AMOUNT_OF_EMAILS_RECEIVED} '
});
const fixture = initWithTemplate(AppComp, ` const fixture = initWithTemplate(AppComp, `
<div i18n> <div i18n>
Hello {{ name // i18n(ph="user_name") }}! 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', () => { it('should support interpolations with custom interpolation config', () => {
loadTranslations({'3771704108176831903': 'Bonjour {$INTERPOLATION}'}); loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
const interpolation = ['{%', '%}'] as[string, string]; const interpolation = ['{%', '%}'] as[string, string];
TestBed.overrideComponent(AppComp, {set: {interpolation}}); TestBed.overrideComponent(AppComp, {set: {interpolation}});
const fixture = initWithTemplate(AppComp, `<div i18n>Hello {% name %}</div>`); 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', () => { it('should support &ngsp; in translatable sections', () => {
// note: the `` unicode symbol represents the `&ngsp;` in translations // 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>`); const fixture = initWithTemplate(AppCompWithWhitespaces, `<div i18n>text |&ngsp;|</div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div>texte | |</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', () => { it('should support interpolations with complex expressions', () => {
loadTranslations({ loadTranslations({
'3552931695168961643': ' {$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} (fr) ' [computeMsgId(' {$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} ')]:
' {$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} (fr) '
}); });
const fixture = initWithTemplate(AppComp, ` const fixture = initWithTemplate(AppComp, `
<div i18n> <div i18n>
@ -99,7 +106,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support elements', () => { it('should support elements', () => {
loadTranslations({ 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}!' 'Bonjour {$START_TAG_SPAN}monde{$CLOSE_TAG_SPAN} et {$START_TAG_DIV}univers{$CLOSE_TAG_DIV}!'
}); });
const fixture = initWithTemplate( const fixture = initWithTemplate(
@ -109,7 +118,11 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('should support removing elements', () => { 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 = const fixture =
initWithTemplate(AppComp, `<div i18n>Hello <b>my</b><span>world</span></div><div>!</div>`); initWithTemplate(AppComp, `<div i18n>Hello <b>my</b><span>world</span></div><div>!</div>`);
expect(fixture.nativeElement.innerHTML) expect(fixture.nativeElement.innerHTML)
@ -118,7 +131,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support moving elements', () => { it('should support moving elements', () => {
loadTranslations({ 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}!' 'Bonjour {$START_TAG_DIV}univers{$CLOSE_TAG_DIV} et {$START_TAG_SPAN}monde{$CLOSE_TAG_SPAN}!'
}); });
const fixture = initWithTemplate( const fixture = initWithTemplate(
@ -129,7 +144,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support template directives', () => { it('should support template directives', () => {
loadTranslations({ 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}!' 'Contenu: {$START_TAG_DIV}avant{$START_TAG_SPAN}milieu{$CLOSE_TAG_SPAN}après{$CLOSE_TAG_DIV}!'
}); });
const fixture = initWithTemplate( const fixture = initWithTemplate(
@ -149,9 +166,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support multiple i18n blocks', () => { it('should support multiple i18n blocks', () => {
loadTranslations({ loadTranslations({
'2954523302699461941': 'traduction {$INTERPOLATION}', [computeMsgId('trad {$INTERPOLATION}')]: 'traduction {$INTERPOLATION}',
'6316306955288477512': 'start {$INTERPOLATION_1} middle {$INTERPOLATION} end', [computeMsgId('start {$INTERPOLATION} middle {$INTERPOLATION_1} end')]:
'4435073550869683142': '{$START_TAG_E}{$CLOSE_TAG_E}{$START_TAG_C}traduction{$CLOSE_TAG_C}' '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, ` const fixture = initWithTemplate(AppComp, `
<div> <div>
@ -170,9 +190,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support multiple sibling i18n blocks', () => { it('should support multiple sibling i18n blocks', () => {
loadTranslations({ loadTranslations({
'1789603390900945185': 'Section un', [computeMsgId('Section 1')]: 'Section un',
'3131519605456222658': 'Section deux', [computeMsgId('Section 2')]: 'Section deux',
'1438862747497772785': 'Section trois', [computeMsgId('Section 3')]: 'Section trois',
}); });
const fixture = initWithTemplate(AppComp, ` const fixture = initWithTemplate(AppComp, `
<div> <div>
@ -186,9 +206,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support multiple sibling i18n blocks inside of a template directive', () => { it('should support multiple sibling i18n blocks inside of a template directive', () => {
loadTranslations({ loadTranslations({
'1789603390900945185': 'Section un', [computeMsgId('Section 1')]: 'Section un',
'3131519605456222658': 'Section deux', [computeMsgId('Section 2')]: 'Section deux',
'1438862747497772785': 'Section trois', [computeMsgId('Section 3')]: 'Section trois',
}); });
const fixture = initWithTemplate(AppComp, ` const fixture = initWithTemplate(AppComp, `
<ul *ngFor="let item of [1,2,3]"> <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', () => { 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 = const fixture =
initWithTemplate(AppComp, `<div i18n>'Single quotes' and "Double quotes"</div>`); 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', () => { it('should correctly bind to context in nested template', () => {
loadTranslations({'4691107123853093118': 'Article {$INTERPOLATION}'}); loadTranslations({[computeMsgId('Item {$INTERPOLATION}')]: 'Article {$INTERPOLATION}'});
const fixture = initWithTemplate(AppComp, ` const fixture = initWithTemplate(AppComp, `
<div *ngFor='let id of items'> <div *ngFor='let id of items'>
<div i18n>Item {{ id }}</div> <div i18n>Item {{ id }}</div>
@ -233,13 +256,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('should handle i18n attribute with directives', () => { 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>`); const fixture = initWithTemplate(AppComp, `<div *ngIf="visible" i18n>Hello {{ name }}</div>`);
expect(fixture.nativeElement.firstChild).toHaveText('Bonjour Angular'); expect(fixture.nativeElement.firstChild).toHaveText('Bonjour Angular');
}); });
it('should work correctly with event listeners', () => { it('should work correctly with event listeners', () => {
loadTranslations({'Hello {$INTERPOLATION}': 'Bonjour {$INTERPOLATION}'}); loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
@Component( @Component(
{selector: 'app-comp', template: `<div i18n (click)="onClick()">Hello {{ name }}</div>`}) {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', () => { describe('ng-container and ng-template support', () => {
it('should support ng-container', () => { it('should support ng-container', () => {
loadTranslations({'3667842621564887364': 'texte'}); loadTranslations({[computeMsgId('text')]: 'texte'});
const fixture = initWithTemplate(AppComp, `<ng-container i18n>text</ng-container>`); const fixture = initWithTemplate(AppComp, `<ng-container i18n>text</ng-container>`);
expect(fixture.nativeElement.innerHTML).toEqual(`texte<!--ng-container-->`); expect(fixture.nativeElement.innerHTML).toEqual(`texte<!--ng-container-->`);
}); });
it('should handle single translation message within ng-template', () => { it('should handle single translation message within ng-template', () => {
loadTranslations({'3771704108176831903': 'Bonjour {$INTERPOLATION}'}); loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
const fixture = const fixture =
initWithTemplate(AppComp, `<ng-template i18n tplRef>Hello {{ name }}</ng-template>`); 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 // Note: applying structural directives to <ng-template> is typically user error, but it
// is technically allowed, so we need to support it. // is technically allowed, so we need to support it.
it('should handle structural directives on ng-template', () => { it('should handle structural directives on ng-template', () => {
loadTranslations({'3771704108176831903': 'Bonjour {$INTERPOLATION}'}); loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
const fixture = initWithTemplate( const fixture = initWithTemplate(
AppComp, `<ng-template *ngIf="name" i18n tplRef>Hello {{ name }}</ng-template>`); 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)', () => { it('should be able to act as child elements inside i18n block (plain text content)', () => {
loadTranslations({ 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}' '{$START_TAG_NG_TEMPLATE} Bonjour {$CLOSE_TAG_NG_TEMPLATE}{$START_TAG_NG_CONTAINER} Au revoir {$CLOSE_TAG_NG_CONTAINER}'
}); });
const fixture = initWithTemplate(AppComp, ` 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)', () => { it('should be able to act as child elements inside i18n block (text + tags)', () => {
loadTranslations({ 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}' '{$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, ` 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)', () => { it('should be able to act as child elements inside i18n block (text + pipes)', () => {
loadTranslations({ 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}' '{$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, ` 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', () => { it('should be able to handle deep nested levels with templates', () => {
loadTranslations({ 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}' '{$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, ` const fixture = initWithTemplate(AppComp, `
@ -383,8 +414,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('should handle self-closing tags as content', () => { it('should handle self-closing tags as content', () => {
loadTranslations( loadTranslations({
{'3294715134260231285': '{$START_TAG_SPAN}Mon logo{$TAG_IMG}{$CLOSE_TAG_SPAN}'}); [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 content = `My logo<img src="logo.png" title="Logo">`;
const fixture = initWithTemplate(AppComp, ` const fixture = initWithTemplate(AppComp, `
<ng-container i18n> <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>', () => { 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]'}) @Directive({selector: '[myDir]'})
class Dir { class Dir {
condition = true; condition = true;
@ -438,8 +475,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
describe('should support ICU expressions', () => { describe('should support ICU expressions', () => {
it('with no root node', () => { it('with no root node', () => {
loadTranslations( loadTranslations({
{'8806993169187953163': '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'}); [computeMsgId('{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}')]:
'{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'
});
const fixture = const fixture =
initWithTemplate(AppComp, `{count, select, 10 {ten} 20 {twenty} other {other}}`); 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', () => { it('with no i18n tag', () => {
loadTranslations( loadTranslations({
{'8806993169187953163': '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'}); [computeMsgId('{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}')]:
'{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'
});
const fixture = initWithTemplate( const fixture = initWithTemplate(
AppComp, `<div>{count, select, 10 {ten} 20 {twenty} other {other}}</div>`); AppComp, `<div>{count, select, 10 {ten} 20 {twenty} other {other}}</div>`);
@ -459,9 +500,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('multiple', () => { it('multiple', () => {
loadTranslations({ 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}}}', '{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, const fixture = initWithTemplate(AppComp, `<div i18n>{count, plural,
=0 {no <b>emails</b>!} =0 {no <b>emails</b>!}
@ -487,8 +532,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('with custom interpolation config', () => { it('with custom interpolation config', () => {
loadTranslations( loadTranslations({
{'8091236997374391053': '{VAR_SELECT, select, 10 {dix} other {{INTERPOLATION}}}'}); [computeMsgId('{VAR_SELECT, select, 10 {ten} other {{INTERPOLATION}}}')]:
'{VAR_SELECT, select, 10 {dix} other {{INTERPOLATION}}}'
});
const interpolation = ['{%', '%}'] as[string, string]; const interpolation = ['{%', '%}'] as[string, string];
TestBed.overrideComponent(AppComp, {set: {interpolation}}); TestBed.overrideComponent(AppComp, {set: {interpolation}});
const fixture = const fixture =
@ -499,9 +546,16 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('inside HTML elements', () => { it('inside HTML elements', () => {
loadTranslations({ 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}}}', '{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, const fixture = initWithTemplate(AppComp, `<div i18n><span>{count, plural,
=0 {no <b>emails</b>!} =0 {no <b>emails</b>!}
@ -529,7 +583,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('inside template directives', () => { 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, const fixture = initWithTemplate(AppComp, `<div i18n><span *ngIf="visible">{name, select,
other {({{name}})} other {({{name}})}
}</span></div>`); }</span></div>`);
@ -546,7 +605,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('inside ng-container', () => { 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, const fixture = initWithTemplate(AppComp, `<ng-container i18n>{name, select,
other {({{name}})} other {({{name}})}
}</ng-container>`); }</ng-container>`);
@ -554,8 +616,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('inside <ng-template>', () => { it('inside <ng-template>', () => {
loadTranslations( loadTranslations({
{'8806993169187953163': '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'}); [computeMsgId('{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}')]:
'{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}'
});
const fixture = initWithTemplate( const fixture = initWithTemplate(
AppComp, ` AppComp, `
<ng-template i18n tplRef>` + <ng-template i18n tplRef>` +
@ -569,7 +633,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('nested', () => { it('nested', () => {
loadTranslations({ 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}}!}}' '{VAR_PLURAL, plural, =0 {zero} other {{INTERPOLATION} {VAR_SELECT, select, cat {chats} dog {chiens} other {animaux}}!}}'
}); });
const fixture = initWithTemplate(AppComp, `<div i18n>{count, plural, 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', () => { it('nested with interpolations in "other" blocks', () => {
// Note: for some reason long string causing clang to reformat the entire file. loadTranslations({
const translation = [computeMsgId(
'{VAR_PLURAL, plural, =0 {zero} =2 {{INTERPOLATION} {VAR_SELECT, select, ' + '{VAR_PLURAL, plural, =0 {zero} =2 {{INTERPOLATION} {VAR_SELECT, select, cat {cats} dog {dogs} other {animals}}!} other {other - {INTERPOLATION}}}',
'cat {chats} dog {chiens} other {animaux}}!} other {other - {INTERPOLATION}}}'; '')]:
loadTranslations({'3182623695425530660': translation}); '{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, const fixture = initWithTemplate(AppComp, `<div i18n>{count, plural,
=0 {zero} =0 {zero}
@ -613,15 +680,19 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
fixture.componentRef.instance.count = 4; fixture.componentRef.instance.count = 4;
fixture.detectChanges(); 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', it('should return the correct plural form for ICU expressions when using a specific locale', () => {
() => { loadTranslations({
registerLocaleData(localeRo); [computeMsgId(
TestBed.configureTestingModule({providers: [{provide: LOCALE_ID, useValue: 'ro'}]}); '{VAR_PLURAL, plural, =0 {no email} =one {one email} =few {a few emails} =other {lots of emails}}')]:
// We could also use `TestBed.overrideProvider(LOCALE_ID, {useValue: 'ro'});` '{VAR_PLURAL, plural, =0 {no email} =one {one email} =few {a few emails} =other {lots of emails}}'
const fixture = initWithTemplate(AppComp, ` });
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, {count, plural,
=0 {no email} =0 {no email}
=one {one email} =one {one email}
@ -629,34 +700,38 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
=other {lots of emails} =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 // Change detection cycle, no model changes
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->'); expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
fixture.componentInstance.count = 3; fixture.componentInstance.count = 3;
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 2-->'); expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 2-->');
fixture.componentInstance.count = 1; fixture.componentInstance.count = 1;
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('one email<!--ICU 2-->'); expect(fixture.nativeElement.innerHTML).toEqual('one email<!--ICU 2-->');
fixture.componentInstance.count = 10; fixture.componentInstance.count = 10;
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 2-->'); expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 2-->');
fixture.componentInstance.count = 20; fixture.componentInstance.count = 20;
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 2-->'); expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 2-->');
fixture.componentInstance.count = 0; fixture.componentInstance.count = 0;
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->'); expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
}); });
it('projection', () => { 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>'}) @Component({selector: 'child', template: '<div><ng-content></ng-content></div>'})
class Child { class Child {
} }
@ -675,7 +750,6 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
value = 3; value = 3;
} }
TestBed.configureTestingModule({declarations: [Parent, Child]}); TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({});
const fixture = TestBed.createComponent(Parent); const fixture = TestBed.createComponent(Parent);
fixture.detectChanges(); fixture.detectChanges();
@ -684,6 +758,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('with empty values', () => { 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 fixture = initWithTemplate(AppComp, `{count, select, 10 {} 20 {twenty} other {other}}`);
const element = fixture.nativeElement; 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', () => { 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({ @Directive({
selector: '[someDir]', 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', 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; let dir: Dir|null = null;
@Directive({ @Directive({
selector: '[someDir]', selector: '[someDir]',
@ -823,6 +913,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('with nested containers', () => { 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({ @Component({
selector: 'comp', selector: 'comp',
template: ` template: `
@ -857,6 +954,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('with named interpolations', () => { 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({ @Component({
selector: 'comp', selector: 'comp',
template: ` template: `
@ -881,16 +985,22 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
const fixture = TestBed.createComponent(Comp); const fixture = TestBed.createComponent(Comp);
fixture.detectChanges(); 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.componentInstance.type = 'C'; // trigger "other" case
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.debugElement.nativeElement.innerHTML).not.toContain('A - Type A'); expect(fixture.debugElement.nativeElement.innerHTML).not.toContain('A (translated) - Type A');
expect(fixture.debugElement.nativeElement.innerHTML).toContain('other - Type C'); expect(fixture.debugElement.nativeElement.innerHTML).toContain('other (translated) - Type C');
}); });
it('should work inside an ngTemplateOutlet inside an ngFor', () => { 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({ @Component({
selector: 'app', selector: 'app',
template: ` template: `
@ -925,13 +1035,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
describe('should support attributes', () => { describe('should support attributes', () => {
it('text', () => { it('text', () => {
loadTranslations({'3667842621564887364': 'texte'}); loadTranslations({[computeMsgId('text')]: 'texte'});
const fixture = initWithTemplate(AppComp, `<div i18n i18n-title title='text'></div>`); const fixture = initWithTemplate(AppComp, `<div i18n i18n-title title='text'></div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div title="texte"></div>`); expect(fixture.nativeElement.innerHTML).toEqual(`<div title="texte"></div>`);
}); });
it('interpolations', () => { it('interpolations', () => {
loadTranslations({'1721737630608625819': 'bonjour {$INTERPOLATION}'}); loadTranslations({[computeMsgId('hello {$INTERPOLATION}')]: 'bonjour {$INTERPOLATION}'});
const fixture = const fixture =
initWithTemplate(AppComp, `<div i18n i18n-title title="hello {{name}}"></div>`); initWithTemplate(AppComp, `<div i18n i18n-title title="hello {{name}}"></div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div title="bonjour Angular"></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', () => { it('with pipes', () => {
loadTranslations({'5990850149002293021': 'bonjour {$INTERPOLATION}'}); loadTranslations({[computeMsgId('hello {$INTERPOLATION}')]: 'bonjour {$INTERPOLATION}'});
const fixture = initWithTemplate( const fixture = initWithTemplate(
AppComp, `<div i18n i18n-title title="hello {{name | uppercase}}"></div>`); AppComp, `<div i18n i18n-title title="hello {{name | uppercase}}"></div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div title="bonjour ANGULAR"></div>`); expect(fixture.nativeElement.innerHTML).toEqual(`<div title="bonjour ANGULAR"></div>`);
}); });
it('multiple attributes', () => { it('multiple attributes', () => {
loadTranslations({'1721737630608625819': 'bonjour {$INTERPOLATION}'}); loadTranslations({[computeMsgId('hello {$INTERPOLATION}')]: 'bonjour {$INTERPOLATION}'});
const fixture = initWithTemplate( const fixture = initWithTemplate(
AppComp, AppComp,
`<input i18n i18n-title title="hello {{name}}" i18n-placeholder placeholder="hello {{name}}">`); `<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', () => { it('on removed elements', () => {
loadTranslations({ loadTranslations({
'3667842621564887364': 'texte', [computeMsgId('text')]: 'texte',
'4851941758912026972': 'contenu', [computeMsgId('{$START_TAG_SPAN}content{$CLOSE_TAG_SPAN}')]: 'contenu',
}); });
const fixture = const fixture =
initWithTemplate(AppComp, `<div i18n><span i18n-title title="text">content</span></div>`); 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', () => { it('with custom interpolation config', () => {
loadTranslations({'6353989911216474113': 'Bonjour {$INTERPOLATION}'}); loadTranslations({[computeMsgId('Hello {$INTERPOLATION}', 'm')]: 'Bonjour {$INTERPOLATION}'});
const interpolation = ['{%', '%}'] as[string, string]; const interpolation = ['{%', '%}'] as[string, string];
TestBed.overrideComponent(AppComp, {set: {interpolation}}); TestBed.overrideComponent(AppComp, {set: {interpolation}});
const fixture = const fixture =
@ -984,7 +1094,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('in nested template', () => { it('in nested template', () => {
loadTranslations({'5108705942887033129': 'Article {$INTERPOLATION}'}); loadTranslations({[computeMsgId('Item {$INTERPOLATION}', 'm')]: 'Article {$INTERPOLATION}'});
const fixture = initWithTemplate(AppComp, ` const fixture = initWithTemplate(AppComp, `
<div *ngFor='let item of [1,2,3]'> <div *ngFor='let item of [1,2,3]'>
<div i18n-title='m|d' title='Item {{ item }}'></div> <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', () => { it('should add i18n attributes on self-closing tags', () => {
loadTranslations({'3771704108176831903': 'Bonjour {$INTERPOLATION}'}); loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'});
const fixture = const fixture =
initWithTemplate(AppComp, `<img src="logo.png" i18n-title title="Hello {{ name }}">`); 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', () => { it('should apply i18n attributes during second template pass', () => {
loadTranslations({[computeMsgId('Set')]: 'Set'});
@Directive({ @Directive({
selector: '[test]', selector: '[test]',
inputs: ['test'], inputs: ['test'],
@ -1044,13 +1155,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('with complex expressions', () => { it('with complex expressions', () => {
loadTranslations({ loadTranslations({
'305276527729153743': '{$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} (fr)' [computeMsgId('{$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2}')]:
'{$INTERPOLATION} - {$INTERPOLATION_1} - {$INTERPOLATION_2} (fr)'
}); });
const fixture = initWithTemplate(AppComp, ` const fixture = initWithTemplate(AppComp, `
<div i18n-title title="{{ name | uppercase }} - {{ obj?.a?.b }} - {{ obj?.getA()?.b }}"></div> <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 // the `obj` field is not yet defined, so 2nd and 3rd interpolations return empty strings
// strings
expect(fixture.nativeElement.firstChild.title).toEqual(`ANGULAR - - (fr)`); expect(fixture.nativeElement.firstChild.title).toEqual(`ANGULAR - - (fr)`);
fixture.componentRef.instance.obj = { fixture.componentRef.instance.obj = {
@ -1092,10 +1203,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
TestBed.configureTestingModule({declarations: [ClsDir, MyApp]}); TestBed.configureTestingModule({declarations: [ClsDir, MyApp]});
loadTranslations({ loadTranslations({
// Note that this translation switches the order of the expressions! // Note that this translation switches the order of the expressions!
'2244013204777604001': 'début {$INTERPOLATION_1} milieu {$INTERPOLATION} fin', [computeMsgId('start {$INTERPOLATION} middle {$INTERPOLATION_1} end')]:
'7297507129788731971': '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}}', '{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); const fixture = TestBed.createComponent(MyApp);
fixture.detectChanges(); fixture.detectChanges();
@ -1138,8 +1251,8 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
TestBed.configureTestingModule({declarations: [AppComp, MyComp]}); TestBed.configureTestingModule({declarations: [AppComp, MyComp]});
loadTranslations({ loadTranslations({
'3299467052279745802': 'Bonjour {$INTERPOLATION}', [computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}',
'694232821652669635': 'fonctionne', [computeMsgId('works')]: 'fonctionne',
}); });
const fixture = initWithTemplate( const fixture = initWithTemplate(
AppComp, AppComp,
@ -1155,8 +1268,19 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should support adding/moving/removing nodes', () => { it('should support adding/moving/removing nodes', () => {
loadTranslations({ loadTranslations({
'3934630822967503512': [computeMsgId(
'{$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}' '{$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, ` const fixture = initWithTemplate(AppComp, `
<div i18n> <div i18n>
@ -1195,8 +1319,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
} }
TestBed.configureTestingModule({declarations: [Parent, Child]}); TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({ loadTranslations({
'7180841260895623479': 'Enfant de {$INTERPOLATION}', [computeMsgId('Child of {$INTERPOLATION}')]: 'Enfant de {$INTERPOLATION}',
'2325314462315226487': [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}' '{$START_TAG_CHILD}Je suis projeté depuis {$START_BOLD_TEXT}{$INTERPOLATION}{$CLOSE_BOLD_TEXT}{$CLOSE_TAG_CHILD}'
}); });
const fixture = TestBed.createComponent(Parent); const fixture = TestBed.createComponent(Parent);
@ -1227,8 +1356,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
} }
TestBed.configureTestingModule({declarations: [Parent, Child]}); TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({ loadTranslations({
'7180841260895623479': 'Enfant de {$INTERPOLATION}', [computeMsgId('Child of {$INTERPOLATION}')]: 'Enfant de {$INTERPOLATION}',
'7230149585615622873': 'Je suis projeté depuis {$INTERPOLATION}' [computeMsgId('I am projected from {$INTERPOLATION}')]:
'Je suis projeté depuis {$INTERPOLATION}'
}); });
const fixture = TestBed.createComponent(Parent); const fixture = TestBed.createComponent(Parent);
fixture.detectChanges(); fixture.detectChanges();
@ -1267,8 +1397,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
} }
TestBed.configureTestingModule({declarations: [Parent, Child, GrandChild]}); TestBed.configureTestingModule({declarations: [Parent, Child, GrandChild]});
loadTranslations( loadTranslations({
{'9156403697449779168': '{$START_BOLD_TEXT}Bonjour{$CLOSE_BOLD_TEXT} monde!'}); [computeMsgId('{$START_BOLD_TEXT}Hello{$CLOSE_BOLD_TEXT} World!')]:
'{$START_BOLD_TEXT}Bonjour{$CLOSE_BOLD_TEXT} monde!'
});
const fixture = TestBed.createComponent(Parent); const fixture = TestBed.createComponent(Parent);
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.nativeElement.innerHTML) expect(fixture.nativeElement.innerHTML)
@ -1291,7 +1423,8 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
} }
TestBed.configureTestingModule({declarations: [Parent, Child, GrandChild]}); 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); const fixture = TestBed.createComponent(Parent);
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.nativeElement.innerHTML) expect(fixture.nativeElement.innerHTML)
@ -1316,7 +1449,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
} }
TestBed.configureTestingModule({declarations: [Parent, Child]}); 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); const fixture = TestBed.createComponent(Parent);
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.nativeElement.innerHTML) expect(fixture.nativeElement.innerHTML)
@ -1337,7 +1473,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
} }
TestBed.configureTestingModule({declarations: [Parent, Child]}); TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({ 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}' '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]}); TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({ 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); const fixture = TestBed.createComponent(Parent);
fixture.detectChanges(); fixture.detectChanges();
@ -1386,8 +1523,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
} }
TestBed.configureTestingModule({declarations: [Parent, Child]}); TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({ loadTranslations({
'3861221266941684467': 'Contenu enfant {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}', [computeMsgId('Child content {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]:
'6186458652454735259': 'et projection depuis {$INTERPOLATION}' 'Contenu enfant {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}',
[computeMsgId('and projection from {$INTERPOLATION}')]:
'et projection depuis {$INTERPOLATION}'
}); });
const fixture = TestBed.createComponent(Parent); const fixture = TestBed.createComponent(Parent);
fixture.detectChanges(); fixture.detectChanges();
@ -1396,6 +1535,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}); });
it('should project bare ICU expressions', () => { 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>'}) @Component({selector: 'child', template: '<div><ng-content></ng-content></div>'})
class Child { class Child {
} }
@ -1414,7 +1557,6 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
value = 3; value = 3;
} }
TestBed.configureTestingModule({declarations: [Parent, Child]}); TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({});
const fixture = TestBed.createComponent(Parent); const fixture = TestBed.createComponent(Parent);
fixture.detectChanges(); fixture.detectChanges();
@ -1438,8 +1580,11 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
} }
TestBed.configureTestingModule({declarations: [Parent, Child]}); TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({ loadTranslations({
'3861221266941684467': 'Contenu enfant {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}', [computeMsgId('{VAR_SELECT, select, angular {Angular} other {{INTERPOLATION}}}')]:
'4986299685320703675': 'et projection depuis {$ICU}' '{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); const fixture = TestBed.createComponent(Parent);
fixture.detectChanges(); fixture.detectChanges();
@ -1466,8 +1611,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
} }
TestBed.configureTestingModule({declarations: [Parent, Child]}); TestBed.configureTestingModule({declarations: [Parent, Child]});
loadTranslations({ loadTranslations({
'3861221266941684467': 'Contenu enfant', [computeMsgId('Child content {$START_TAG_NG_CONTENT}{$CLOSE_TAG_NG_CONTENT}')]:
'6186458652454735259': 'et projection depuis {$INTERPOLATION}' 'Contenu enfant',
[computeMsgId('and projection from {$INTERPOLATION}')]:
'et projection depuis {$INTERPOLATION}'
}); });
const fixture = TestBed.createComponent(Parent); const fixture = TestBed.createComponent(Parent);
fixture.detectChanges(); fixture.detectChanges();
@ -1476,6 +1623,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
it('should display/destroy projected i18n content', () => { 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({ @Component({
selector: 'app', selector: 'app',
template: ` template: `
@ -1553,8 +1704,15 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
} }
TestBed.configureTestingModule({declarations: [TextDirective, DivQuery]}); TestBed.configureTestingModule({declarations: [TextDirective, DivQuery]});
loadTranslations( loadTranslations({
{'3395826043214005257': '{$START_TAG_NG_TEMPLATE}Contenu{$CLOSE_TAG_NG_TEMPLATE}'}); [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, ` const fixture = initWithTemplate(AppComp, `
<div-query #q i18n> <div-query #q i18n>
<ng-template> <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', () => { 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({ @Component({
template: ` template: `
<div dialog i18n> <div dialog i18n>

View File

@ -7,23 +7,18 @@
*/ */
import {CommonModule, DOCUMENT} from '@angular/common'; 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 {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 {Input} from '@angular/core/src/metadata';
import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode'; import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode';
import {TestBed, TestComponentRenderer} from '@angular/core/testing'; 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 {By, DomSanitizer} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers'; import {expect} from '@angular/platform-browser/testing/src/matchers';
import {ivyEnabled, onlyInIvy} from '@angular/private/testing'; import {ivyEnabled, onlyInIvy} from '@angular/private/testing';
describe('ViewContainerRef', () => { 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 * 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. * reflect attributes omitted. This makes HTML comparisons easier and less verbose.
@ -34,7 +29,6 @@ describe('ViewContainerRef', () => {
} }
beforeEach(() => { beforeEach(() => {
loadTranslations(TRANSLATIONS);
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ declarations: [
StructDir, ViewContainerRefComp, ViewContainerRefApp, DestroyCasesComp, ConstructorDir, StructDir, ViewContainerRefComp, ViewContainerRefApp, DestroyCasesComp, ConstructorDir,
@ -43,6 +37,8 @@ describe('ViewContainerRef', () => {
}); });
}); });
afterEach(() => clearTranslations());
describe('create', () => { describe('create', () => {
it('should support view queries inside embedded views created in dir constructors', () => { it('should support view queries inside embedded views created in dir constructors', () => {
@ -349,6 +345,12 @@ describe('ViewContainerRef', () => {
onlyInIvy('Ivy i18n logic') onlyInIvy('Ivy i18n logic')
.it('when ViewContainerRef is on an element inside a ng-container with i18n', () => { .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(` executeTest(`
<ng-template #foo> <ng-template #foo>
<span i18n>Bar</span> <span i18n>Bar</span>
@ -368,11 +370,17 @@ describe('ViewContainerRef', () => {
}); });
onlyInIvy('Ivy i18n logic') onlyInIvy('Ivy i18n logic')
.it('when ViewContainerRef is on an element, and i18n is on the parent ViewContainerRef', .it('when ViewContainerRef is on an element, and i18n is on the parent ViewContainerRef', () => {
() => { loadTranslations({
executeTest(` [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> <ng-template #foo>
<span>Foo</span> <span>F</span>
</ng-template> </ng-template>
<ng-template structDir i18n> <ng-template structDir i18n>
@ -382,7 +390,7 @@ describe('ViewContainerRef', () => {
</div> </div>
<after></after> <after></after>
</ng-template>`); </ng-template>`);
}); });
}); });
describe('length', () => { describe('length', () => {

View File

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

View File

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

View File

@ -70,6 +70,10 @@ export interface ParsedMessage {
* A human readable rendering of the message * A human readable rendering of the message
*/ */
messageString: string; 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 || ''), messageId: metadata.id || computeMsgId(messageString, metadata.meaning || ''),
substitutions, substitutions,
messageString, messageString,
meaning: metadata.meaning || '',
}; };
} }