diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index 754586036b..f0d6142ffd 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -25,11 +25,11 @@ import {NO_CHANGE} from './tokens'; import {addAllToArray, getNativeByIndex, getNativeByTNode, getTNode, isLContainer, stringify} from './util'; const MARKER = `�`; -const ICU_BLOCK_REGEX = /^\s*(�\d+�)\s*,\s*(select|plural)\s*,/; +const ICU_BLOCK_REGEX = /^\s*(�\d+:?\d*�)\s*,\s*(select|plural)\s*,/; const SUBTEMPLATE_REGEXP = /�\/?\*(\d+:\d+)�/gi; const PH_REGEXP = /�(\/?[#*]\d+):?\d*�/gi; const BINDING_REGEXP = /�(\d+):?\d*�/gi; -const ICU_REGEXP = /({\s*�\d+�\s*,\s*\S{6}\s*,[\s\S]*})/gi; +const ICU_REGEXP = /({\s*�\d+:?\d*�\s*,\s*\S{6}\s*,[\s\S]*})/gi; // i18nPostproocess regexps const PP_PLACEHOLDERS = /\[(�.+?�?)\]/g; diff --git a/packages/core/test/render3/i18n_spec.ts b/packages/core/test/render3/i18n_spec.ts index e64c420812..b39783b1fc 100644 --- a/packages/core/test/render3/i18n_spec.ts +++ b/packages/core/test/render3/i18n_spec.ts @@ -15,7 +15,7 @@ import {getNativeByIndex} from '../../src/render3/util'; import {NgIf} from './common_with_def'; -import {element, elementEnd, elementStart, template, text, bind, elementProperty, projectionDef, projection} from '../../src/render3/instructions'; +import {element, elementEnd, elementStart, template, text, nextContext, bind, elementProperty, projectionDef, projection} from '../../src/render3/instructions'; import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nUpdateOpCode, I18nUpdateOpCodes, TI18n} from '../../src/render3/interfaces/i18n'; import {HEADER_OFFSET, LView, TVIEW} from '../../src/render3/interfaces/view'; import {ComponentFixture, TemplateFixture} from './render_util'; @@ -656,6 +656,65 @@ describe('Runtime i18n', () => { expect(fixture.html).toEqual('
'); }); + it('for ICU expressions inside templates', () => { + const MSG_DIV = `�*2:1��#1:1�{�0:1�, plural, + =0 {no emails!} + =1 {one email} + other {�0:1� emails} + }�/#1:1��/*2:1�`; + + function subTemplate_1(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + i18nStart(0, MSG_DIV, 1); + element(1, 'span'); + i18nEnd(); + } + if (rf & RenderFlags.Update) { + const ctx = nextContext(); + i18nExp(bind(ctx.value0)); + i18nExp(bind(ctx.value1)); + i18nApply(0); + } + } + + class MyApp { + value0 = 0; + value1 = 'emails label'; + + static ngComponentDef = defineComponent({ + type: MyApp, + selectors: [['my-app']], + directives: [NgIf], + factory: () => new MyApp(), + consts: 3, + vars: 1, + template: (rf: RenderFlags, ctx: MyApp) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'div'); + i18nStart(1, MSG_DIV); + template(2, subTemplate_1, 2, 2, 'span', [3, 'ngIf']); + i18nEnd(); + elementEnd(); + } + if (rf & RenderFlags.Update) { + elementProperty(2, 'ngIf', true); + } + } + }); + } + + const fixture = new ComponentFixture(MyApp); + expect(fixture.html) + .toEqual('
no emails!
'); + + // Update the value + fixture.component.value0 = 3; + fixture.update(); + expect(fixture.html) + .toEqual( + '
3 emails
'); + }); + it('for nested ICU expressions', () => { const MSG_DIV = `{�0�, plural, =0 {zero}