Skip to content

Commit e67a331

Browse files
petebacondarwinmhevery
authored andcommitted
fix(compiler): ensure that i18n message-parts have the correct source-span (#39589)
In an i18n message, two placeholders next to each other must have an "empty" message-part to separate them. Previously, the source-span for this message-part was pointing to the wrong original location. This caused problems in the generated source-maps and lead to extracted i18n messages from being rendered incorrectly. PR Close #39589
1 parent 08e077c commit e67a331

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

packages/compiler/src/render3/view/i18n/localize_utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ function processMessagePieces(pieces: o.MessagePiece[]):
120120
placeHolders.push(part);
121121
if (pieces[i - 1] instanceof o.PlaceholderPiece) {
122122
// There were two placeholders in a row, so we need to add an empty message part.
123-
messageParts.push(createEmptyMessagePart(part.sourceSpan.end));
123+
messageParts.push(createEmptyMessagePart(pieces[i - 1].sourceSpan.end));
124124
}
125125
}
126126
}

packages/compiler/test/render3/view/i18n_spec.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,14 +458,33 @@ describe('serializeI18nMessageForLocalize', () => {
458458
expect(placeHolders[3].sourceSpan.toString()).toEqual('</span>');
459459
});
460460

461+
it('should create the correct source-spans when there are two placeholders next to each other',
462+
() => {
463+
const {messageParts, placeHolders} = serialize('<b>{{value}}</b>');
464+
expect(messageParts[0].text).toEqual('');
465+
expect(humanizeSourceSpan(messageParts[0].sourceSpan)).toEqual('"" (10-10)');
466+
expect(messageParts[1].text).toEqual('');
467+
expect(humanizeSourceSpan(messageParts[1].sourceSpan)).toEqual('"" (13-13)');
468+
expect(messageParts[2].text).toEqual('');
469+
expect(humanizeSourceSpan(messageParts[2].sourceSpan)).toEqual('"" (22-22)');
470+
expect(messageParts[3].text).toEqual('');
471+
expect(humanizeSourceSpan(messageParts[3].sourceSpan)).toEqual('"" (26-26)');
472+
473+
expect(placeHolders[0].text).toEqual('START_BOLD_TEXT');
474+
expect(humanizeSourceSpan(placeHolders[0].sourceSpan)).toEqual('"<b>" (10-13)');
475+
expect(placeHolders[1].text).toEqual('INTERPOLATION');
476+
expect(humanizeSourceSpan(placeHolders[1].sourceSpan)).toEqual('"{{value}}" (13-22)');
477+
expect(placeHolders[2].text).toEqual('CLOSE_BOLD_TEXT');
478+
expect(humanizeSourceSpan(placeHolders[2].sourceSpan)).toEqual('"</b>" (22-26)');
479+
});
480+
461481
it('should serialize simple ICU for `$localize()`', () => {
462482
expect(serialize('{age, plural, 10 {ten} other {other}}')).toEqual({
463483
messageParts: [literal('{VAR_PLURAL, plural, 10 {ten} other {other}}')],
464484
placeHolders: []
465485
});
466486
});
467487

468-
469488
it('should serialize nested ICUs for `$localize()`', () => {
470489
expect(serialize(
471490
'{age, plural, 10 {ten {size, select, 1 {one} 2 {two} other {2+}}} other {other}}'))
@@ -478,7 +497,6 @@ describe('serializeI18nMessageForLocalize', () => {
478497
});
479498
});
480499

481-
482500
it('should serialize ICU with embedded HTML for `$localize()`', () => {
483501
expect(serialize('{age, plural, 10 {<b>ten</b>} other {<div class="A">other</div>}}')).toEqual({
484502
messageParts: [
@@ -564,3 +582,7 @@ function literal(text: string, span: any = jasmine.any(ParseSourceSpan)): o.Lite
564582
function placeholder(name: string, span: any = jasmine.any(ParseSourceSpan)): o.PlaceholderPiece {
565583
return new o.PlaceholderPiece(name, span);
566584
}
585+
586+
function humanizeSourceSpan(span: ParseSourceSpan): string {
587+
return `"${span.toString()}" (${span.start.offset}-${span.end.offset})`;
588+
}

0 commit comments

Comments
 (0)