diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts
index 5cfb37f14e..0d921754c9 100644
--- a/packages/core/src/render3/i18n.ts
+++ b/packages/core/src/render3/i18n.ts
@@ -556,8 +556,8 @@ export function ɵɵi18nPostprocess(
const templateIdsStack: number[] = [ROOT_TEMPLATE_ID];
result = result.replace(PP_PLACEHOLDERS_REGEXP, (m: any, phs: string, tmpl: string): string => {
const content = phs || tmpl;
- if (!matches[content]) {
- const placeholders: PostprocessPlaceholder[] = [];
+ const placeholders: PostprocessPlaceholder[] = matches[content] || [];
+ if (!placeholders.length) {
content.split('|').forEach((placeholder: string) => {
const match = placeholder.match(PP_TEMPLATE_ID_REGEXP);
const templateId = match ? parseInt(match[1], 10) : ROOT_TEMPLATE_ID;
@@ -566,11 +566,12 @@ export function ɵɵi18nPostprocess(
});
matches[content] = placeholders;
}
- if (!matches[content].length) {
+
+ if (!placeholders.length) {
throw new Error(`i18n postprocess: unmatched placeholder - ${content}`);
}
+
const currentTemplateId = templateIdsStack[templateIdsStack.length - 1];
- const placeholders = matches[content];
let idx = 0;
// find placeholder index that matches current template id
for (let i = 0; i < placeholders.length; i++) {
@@ -590,12 +591,6 @@ export function ɵɵi18nPostprocess(
placeholders.splice(idx, 1);
return placeholder;
});
-
- // verify that we injected all values
- const hasUnmatchedValues = Object.keys(matches).some(key => !!matches[key].length);
- if (hasUnmatchedValues) {
- throw new Error(`i18n postprocess: unmatched values - ${JSON.stringify(matches)}`);
- }
}
// return current result if no replacements specified
diff --git a/packages/core/test/acceptance/i18n_spec.ts b/packages/core/test/acceptance/i18n_spec.ts
index 046aad5755..51f615d830 100644
--- a/packages/core/test/acceptance/i18n_spec.ts
+++ b/packages/core/test/acceptance/i18n_spec.ts
@@ -847,8 +847,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
.toEqual('Bonjour monde!
');
});
- // FW-1312: Wrong i18n code generated by the compiler when the template has 2 empty `span`
- xit('should project translations with selectors', () => {
+ it('should project translations with selectors', () => {
@Component({selector: 'child', template: ``})
class Child {
}
diff --git a/packages/core/test/render3/i18n_spec.ts b/packages/core/test/render3/i18n_spec.ts
index 10df144f31..154e974cde 100644
--- a/packages/core/test/render3/i18n_spec.ts
+++ b/packages/core/test/render3/i18n_spec.ts
@@ -780,22 +780,10 @@ describe('Runtime i18n', () => {
});
it('should throw in case we have invalid string', () => {
- const arr = ['�*1:1��#2:1�', '�#4:2�', '�6:4�', '�/#2:1��/*1:1�'];
- const str = `[${arr.join('|')}]`;
-
- const cases = [
- // less placeholders than we have
- [`Start: ${str}, ${str} and ${str} end.`, {}],
-
- // more placeholders than we have
- [`Start: ${str}, ${str} and ${str}, ${str} ${str} end.`, {}],
-
- // not enough ICU replacements
- ['My ICU #1: �I18N_EXP_ICU�, My ICU #2: �I18N_EXP_ICU�', {ICU: ['ICU_VALUE_1']}]
- ];
- cases.forEach(([input, replacements, output]) => {
- expect(() => ɵɵi18nPostprocess(input as string, replacements as any)).toThrowError();
- });
+ expect(
+ () => ɵɵi18nPostprocess(
+ 'My ICU #1: �I18N_EXP_ICU�, My ICU #2: �I18N_EXP_ICU�', {ICU: ['ICU_VALUE_1']}))
+ .toThrowError();
});
});
});