diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index 3df1f9b71d5e8..09c8a5f745a8f 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -683,10 +683,21 @@ function i18nEndFirstPass(lView: LView, tView: TView) { const visitedNodes = readCreateOpCodes(rootIndex, tI18n.create, lView); // Remove deleted nodes - for (let i = rootIndex + 1; i <= lastCreatedNode.index - HEADER_OFFSET; i++) { - if (visitedNodes.indexOf(i) === -1) { - removeNode(i, lView, /* markAsDetached */ true); + let index = rootIndex + 1; + while (index <= lastCreatedNode.index - HEADER_OFFSET) { + if (visitedNodes.indexOf(index) === -1) { + removeNode(index, lView, /* markAsDetached */ true); } + // Check if an element has any local refs and skip them + const tNode = getTNode(index, lView); + if (tNode && (tNode.type === TNodeType.Element || tNode.type === TNodeType.ElementContainer) && + tNode.localNames !== null) { + // Divide by 2 to get the number of local refs, + // since they are stored as an array that also includes directive indexes, + // i.e. ["localRef", directiveIndex, ...] + index += tNode.localNames.length >> 1; + } + index++; } } diff --git a/packages/core/test/acceptance/i18n_spec.ts b/packages/core/test/acceptance/i18n_spec.ts index 16fd89ffd5f29..99b184896a2f9 100644 --- a/packages/core/test/acceptance/i18n_spec.ts +++ b/packages/core/test/acceptance/i18n_spec.ts @@ -287,6 +287,43 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { expect(instance.clicks).toBe(1); }); + it('should support local refs inside i18n block', () => { + loadTranslations({ + [computeMsgId( + '{$START_TAG_NG_CONTAINER} One {$CLOSE_TAG_NG_CONTAINER}' + + '{$START_TAG_DIV} Two {$CLOSE_TAG_DIV}' + + '{$START_TAG_SPAN} Three {$CLOSE_TAG_SPAN}')]: + '{$START_TAG_NG_CONTAINER} Une {$CLOSE_TAG_NG_CONTAINER}' + + '{$START_TAG_DIV} Deux {$CLOSE_TAG_DIV}' + + '{$START_TAG_SPAN} Trois {$CLOSE_TAG_SPAN}' + }); + const fixture = initWithTemplate(AppComp, ` +
+ One +
Two
+ Three +
+ `); + expect(fixture.nativeElement.textContent).toBe(' Une Deux Trois '); + }); + + it('should handle local refs correctly in case an element is removed in translation', () => { + loadTranslations({ + [computeMsgId( + '{$START_TAG_NG_CONTAINER} One {$CLOSE_TAG_NG_CONTAINER}' + + '{$START_TAG_DIV} Two {$CLOSE_TAG_DIV}' + + '{$START_TAG_SPAN} Three {$CLOSE_TAG_SPAN}')]: '{$START_TAG_DIV} Deux {$CLOSE_TAG_DIV}' + }); + const fixture = initWithTemplate(AppComp, ` +
+ One +
Two
+ Three +
+ `); + expect(fixture.nativeElement.textContent).toBe(' Deux '); + }); + describe('ng-container and ng-template support', () => { it('should support ng-container', () => { loadTranslations({[computeMsgId('text')]: 'texte'});