fix(ivy): don't throw on unmatched placeholder replacements in i18nPostprocess
(#30632)
Depending on which placeholders the translation uses, there are some legitimate cases where we might not use all placeholder replacements in `i18nPostprocess`. For example if some of the placeholders of the original messages have been removed in the translation. FW-1312 #resolve PR Close #30632
This commit is contained in:
parent
9b3af1468d
commit
68cd0cab8c
@ -556,8 +556,8 @@ export function ɵɵi18nPostprocess(
|
|||||||
const templateIdsStack: number[] = [ROOT_TEMPLATE_ID];
|
const templateIdsStack: number[] = [ROOT_TEMPLATE_ID];
|
||||||
result = result.replace(PP_PLACEHOLDERS_REGEXP, (m: any, phs: string, tmpl: string): string => {
|
result = result.replace(PP_PLACEHOLDERS_REGEXP, (m: any, phs: string, tmpl: string): string => {
|
||||||
const content = phs || tmpl;
|
const content = phs || tmpl;
|
||||||
if (!matches[content]) {
|
const placeholders: PostprocessPlaceholder[] = matches[content] || [];
|
||||||
const placeholders: PostprocessPlaceholder[] = [];
|
if (!placeholders.length) {
|
||||||
content.split('|').forEach((placeholder: string) => {
|
content.split('|').forEach((placeholder: string) => {
|
||||||
const match = placeholder.match(PP_TEMPLATE_ID_REGEXP);
|
const match = placeholder.match(PP_TEMPLATE_ID_REGEXP);
|
||||||
const templateId = match ? parseInt(match[1], 10) : ROOT_TEMPLATE_ID;
|
const templateId = match ? parseInt(match[1], 10) : ROOT_TEMPLATE_ID;
|
||||||
@ -566,11 +566,12 @@ export function ɵɵi18nPostprocess(
|
|||||||
});
|
});
|
||||||
matches[content] = placeholders;
|
matches[content] = placeholders;
|
||||||
}
|
}
|
||||||
if (!matches[content].length) {
|
|
||||||
|
if (!placeholders.length) {
|
||||||
throw new Error(`i18n postprocess: unmatched placeholder - ${content}`);
|
throw new Error(`i18n postprocess: unmatched placeholder - ${content}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentTemplateId = templateIdsStack[templateIdsStack.length - 1];
|
const currentTemplateId = templateIdsStack[templateIdsStack.length - 1];
|
||||||
const placeholders = matches[content];
|
|
||||||
let idx = 0;
|
let idx = 0;
|
||||||
// find placeholder index that matches current template id
|
// find placeholder index that matches current template id
|
||||||
for (let i = 0; i < placeholders.length; i++) {
|
for (let i = 0; i < placeholders.length; i++) {
|
||||||
@ -590,12 +591,6 @@ export function ɵɵi18nPostprocess(
|
|||||||
placeholders.splice(idx, 1);
|
placeholders.splice(idx, 1);
|
||||||
return placeholder;
|
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
|
// return current result if no replacements specified
|
||||||
|
@ -847,8 +847,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||||||
.toEqual('<child><grand-child><div>Bonjour monde!</div></grand-child></child>');
|
.toEqual('<child><grand-child><div>Bonjour monde!</div></grand-child></child>');
|
||||||
});
|
});
|
||||||
|
|
||||||
// FW-1312: Wrong i18n code generated by the compiler when the template has 2 empty `span`
|
it('should project translations with selectors', () => {
|
||||||
xit('should project translations with selectors', () => {
|
|
||||||
@Component({selector: 'child', template: `<ng-content select="span"></ng-content>`})
|
@Component({selector: 'child', template: `<ng-content select="span"></ng-content>`})
|
||||||
class Child {
|
class Child {
|
||||||
}
|
}
|
||||||
|
@ -780,22 +780,10 @@ describe('Runtime i18n', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should throw in case we have invalid string', () => {
|
it('should throw in case we have invalid string', () => {
|
||||||
const arr = ['<27>*1:1<><31>#2:1<>', '<27>#4:2<>', '<27>6:4<>', '<27>/#2:1<><31>/*1:1<>'];
|
expect(
|
||||||
const str = `[${arr.join('|')}]`;
|
() => ɵɵi18nPostprocess(
|
||||||
|
'My ICU #1: <20>I18N_EXP_ICU<43>, My ICU #2: <20>I18N_EXP_ICU<43>', {ICU: ['ICU_VALUE_1']}))
|
||||||
const cases = [
|
.toThrowError();
|
||||||
// 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: <20>I18N_EXP_ICU<43>, My ICU #2: <20>I18N_EXP_ICU<43>', {ICU: ['ICU_VALUE_1']}]
|
|
||||||
];
|
|
||||||
cases.forEach(([input, replacements, output]) => {
|
|
||||||
expect(() => ɵɵi18nPostprocess(input as string, replacements as any)).toThrowError();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user