diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts
index 40bef90382..063fe67d78 100644
--- a/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts
+++ b/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts
@@ -3385,6 +3385,30 @@ describe('i18n support in the template compiler', () => {
verify(input, output);
});
+
+ it('should attach metadata in case an ICU represents the whole message', () => {
+ const input = `
+
{count, select, 1 {one} other {more than one}}
+ `;
+
+ const output = String.raw `
+ var $I18N_0$;
+ if (ngI18nClosureMode) {
+ /**
+ * @desc descA
+ * @meaning meaningA
+ */
+ const $MSG_EXTERNAL_idA$$APP_SPEC_TS_1$ = goog.getMsg("{VAR_SELECT, select, 1 {one} other {more than one}}");
+ $I18N_0$ = $MSG_EXTERNAL_idA$$APP_SPEC_TS_1$;
+ }
+ else {
+ $I18N_0$ = $localize \`:meaningA|descA@@idA:{VAR_SELECT, select, 1 {one} other {more than one}}\`;
+ }
+ $I18N_0$ = i0.ɵɵi18nPostprocess($I18N_0$, { "VAR_SELECT": "\uFFFD0\uFFFD" });
+ `;
+
+ verify(input, output);
+ });
});
describe('errors', () => {
diff --git a/packages/compiler/src/render3/view/i18n/meta.ts b/packages/compiler/src/render3/view/i18n/meta.ts
index afee55bade..313a83e69e 100644
--- a/packages/compiler/src/render3/view/i18n/meta.ts
+++ b/packages/compiler/src/render3/view/i18n/meta.ts
@@ -111,7 +111,7 @@ export class I18nMetaVisitor implements html.Visitor {
element.attrs = attrs;
}
}
- html.visitAll(this, element.children);
+ html.visitAll(this, element.children, element.i18n);
return element;
}
@@ -127,8 +127,10 @@ export class I18nMetaVisitor implements html.Visitor {
const icu = icuFromI18nMessage(message);
icu.name = name;
} else {
- // when ICU is a root level translation
- message = this._generateI18nMessage([expansion], meta);
+ // ICU is a top level message, try to use metadata from container element if provided via
+ // `context` argument. Note: context may not be available for standalone ICUs (without
+ // wrapping element), so fallback to ICU metadata in this case.
+ message = this._generateI18nMessage([expansion], context || meta);
}
expansion.i18n = message;
return expansion;
diff --git a/packages/core/test/acceptance/i18n_spec.ts b/packages/core/test/acceptance/i18n_spec.ts
index 58469b704e..344384e022 100644
--- a/packages/core/test/acceptance/i18n_spec.ts
+++ b/packages/core/test/acceptance/i18n_spec.ts
@@ -1031,6 +1031,26 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
expect(fixture.debugElement.nativeElement.innerHTML).toContain('A');
expect(fixture.debugElement.nativeElement.innerHTML).toContain('B');
});
+
+ it('should use metadata from container element if a message is a single ICU', () => {
+ loadTranslations({idA: '{VAR_SELECT, select, 1 {un} other {plus d\'un}}'});
+
+ @Component({
+ selector: 'app',
+ template: `
+ {count, select, 1 {one} other {more than one}}
+ `
+ })
+ class AppComponent {
+ count = 2;
+ }
+
+ TestBed.configureTestingModule({declarations: [AppComponent]});
+
+ const fixture = TestBed.createComponent(AppComponent);
+ fixture.detectChanges();
+ expect(fixture.debugElement.nativeElement.innerHTML).toContain('plus d\'un');
+ });
});
describe('should support attributes', () => {