fix(core): handle missing withI18nSupport() call for components that use i18n blocks (#56175)

This commit updates hydration serialization logic to handle a case when the `withI18nSupport()` call is not present for an application that has a component that uses i18n blocks. Note: the issue is only reproducible for components that also inject `ViewContainerRef`, since it triggers a special serialization code path.

Resolves #56074.

PR Close #56175
This commit is contained in:
Andrew Kushnir 2024-05-29 21:23:44 -07:00 committed by Jessica Janiuk
parent 4cd546571d
commit 290a47d842
2 changed files with 31 additions and 0 deletions

View file

@ -182,6 +182,14 @@ function annotateLContainerForHydration(lContainer: LContainer, context: Hydrati
// Serialize the root component itself.
const componentLViewNghIndex = annotateComponentLViewForHydration(componentLView, context);
if (componentLViewNghIndex === null) {
// Component was not serialized (for example, if hydration was skipped by adding
// the `ngSkipHydration` attribute or this component uses i18n blocks in the template,
// but `withI18nSupport()` was not added), avoid annotating host element with the `ngh`
// attribute.
return;
}
const hostElement = unwrapRNode(componentLView[HOST]!) as HTMLElement;
// Serialize all views within this view container.

View file

@ -1964,6 +1964,29 @@ describe('platform-server hydration integration', () => {
clearTranslations();
});
it('should append skip hydration flag if component uses i18n blocks and no `withI18nSupport()` call present', async () => {
@Component({
standalone: true,
selector: 'app',
template: '<div i18n>Hi!</div>',
})
class SimpleComponent {
// Having `ViewContainerRef` here is important: it triggers
// a code path that serializes top-level `LContainer`s.
vcr = inject(ViewContainerRef);
}
const hydrationFeatures = [] as unknown as HydrationFeature<any>[];
const html = await ssr(SimpleComponent, {hydrationFeatures});
const ssrContents = getAppContents(html);
// Since `withI18nSupport()` was not included and a component has i18n blocks -
// we expect that the `ngSkipHydration` attribute was added during serialization.
expect(ssrContents).not.toContain('ngh="');
expect(ssrContents).toContain('ngskiphydration="');
});
it('should not append skip hydration flag if component uses i18n blocks', async () => {
@Component({
standalone: true,