fix(ivy): update i18n/i18nStart and i18nAttributes instruction order (#28163)

Prior to this change element's i18n attributes like "i18n-title" were processed after "i18n" ones that placed "i18n" and "i18nAttributes" instructions in wrong order, thus "i18nAttributes" failed to target its host element at runtime. This change updates processing order and puts "i18nAttributes" instructions in front of "i18n" ones to resolve the problem.

PR Close #28163
This commit is contained in:
Andrew Kushnir 2019-01-15 12:10:41 -08:00
parent c61ea1d5bd
commit 9a81f0d9a8
3 changed files with 17 additions and 16 deletions

View File

@ -580,8 +580,8 @@ describe('i18n support in the view compiler', () => {
template: function MyComponent_Template(rf, ctx) { template: function MyComponent_Template(rf, ctx) {
if (rf & 1) { if (rf & 1) {
$r3$.ɵelementStart(0, "div"); $r3$.ɵelementStart(0, "div");
$r3$.ɵi18n(1, $MSG_EXTERNAL_4969674997806975147$$APP_SPEC_TS_0$); $r3$.ɵi18nAttributes(1, $_c0$);
$r3$.ɵi18nAttributes(2, $_c0$); $r3$.ɵi18n(2, $MSG_EXTERNAL_4969674997806975147$$APP_SPEC_TS_0$);
$r3$.ɵelementEnd(); $r3$.ɵelementEnd();
} }
} }

View File

@ -619,10 +619,6 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
this.creationInstruction(element.sourceSpan, R3.disableBindings); this.creationInstruction(element.sourceSpan, R3.disableBindings);
} }
if (isI18nRootElement) {
this.i18nStart(element.sourceSpan, element.i18n !, createSelfClosingI18nInstruction);
}
// process i18n element attributes // process i18n element attributes
if (i18nAttrs.length) { if (i18nAttrs.length) {
let hasBindings: boolean = false; let hasBindings: boolean = false;
@ -656,6 +652,12 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
} }
} }
// Note: it's important to keep i18n/i18nStart instructions after i18nAttributes ones,
// to make sure i18nAttributes instruction targets current element at runtime.
if (isI18nRootElement) {
this.i18nStart(element.sourceSpan, element.i18n !, createSelfClosingI18nInstruction);
}
// The style bindings code is placed into two distinct blocks within the template function AOT // The style bindings code is placed into two distinct blocks within the template function AOT
// code: creation and update. The creation code contains the `elementStyling` instructions // code: creation and update. The creation code contains the `elementStyling` instructions
// which will apply the collected binding values to the element. `elementStyling` is // which will apply the collected binding values to the element. `elementStyling` is

View File

@ -117,19 +117,18 @@ onlyInIvy('Ivy i18n logic').describe('i18n', function() {
} }
}); });
fixmeIvy('FW-904: i18n attributes placed on i18n root node don\'t work') it('should work correctly when placed on i18n root node', () => {
.it('should work correctly when placed on i18n root node', () => { const title = 'Hello {{ name }}';
const title = 'Hello {{ name }}'; const content = 'Hello';
const content = 'Hello'; const template = `
const template = `
<div i18n i18n-title="m|d" title="${title}">${content}</div> <div i18n i18n-title="m|d" title="${title}">${content}</div>
`; `;
const fixture = getFixtureWithOverrides({template}); const fixture = getFixtureWithOverrides({template});
const element = fixture.nativeElement.firstChild; const element = fixture.nativeElement.firstChild;
expect(element.title).toBe('Bonjour John'); expect(element.title).toBe('Bonjour John');
expect(element).toHaveText('Bonjour'); expect(element).toHaveText('Bonjour');
}); });
it('should add i18n attributes on self-closing tags', () => { it('should add i18n attributes on self-closing tags', () => {
const title = 'Hello {{ name }}'; const title = 'Hello {{ name }}';