fix(localize): render correct closing tag placeholder names in XLIFF 2 (#41152)
When there are elements in a translated message, the start and end tags are encoded as placeholders. The names of these placeholders are computed from the name of the element. For example `<a> will be `START_LINK` and `</a>` will be `CLOSE_LINK`. If there are more than one element with the same name, but different attributes, then the starting placeholder name is made unique. For example `<a href="a">` would be `START_LINK`, while `<a href="b">` in the same message would then be called `START_LINK_1`. But the closing tags will not be made unique since there are no attrbutes; the always have the same text `</a>`, which will produce, for example, `CLOSE_LINK`. Previously, when extracting XLIFF 2 formatted translation files, the closing tag placeholder names were computed incorrectly from the opening tag placeholder names. For example `CLOSE_LINK_1`. This commit strips these `_1` type endings from the start tag placeholder name when computing the closing tag placeholder name. It also ensures that the `type` of the placeholder is computed accurately in these cases too. Fixes #41142 PR Close #41152
This commit is contained in:
parent
1fb0dbb300
commit
b5e8c28640
|
@ -113,7 +113,9 @@ export class Xliff2TranslationSerializer implements TranslationSerializer {
|
||||||
const text = substitutionLocations?.[placeholderName]?.text;
|
const text = substitutionLocations?.[placeholderName]?.text;
|
||||||
|
|
||||||
if (placeholderName.startsWith('START_')) {
|
if (placeholderName.startsWith('START_')) {
|
||||||
const closingPlaceholderName = placeholderName.replace(/^START/, 'CLOSE');
|
// Replace the `START` with `CLOSE` and strip off any `_1` ids from the end.
|
||||||
|
const closingPlaceholderName =
|
||||||
|
placeholderName.replace(/^START/, 'CLOSE').replace(/_\d+$/, '');
|
||||||
const closingText = substitutionLocations?.[closingPlaceholderName]?.text;
|
const closingText = substitutionLocations?.[closingPlaceholderName]?.text;
|
||||||
const attrs: Record<string, string> = {
|
const attrs: Record<string, string> = {
|
||||||
id: `${this.currentPlaceholderId++}`,
|
id: `${this.currentPlaceholderId++}`,
|
||||||
|
@ -186,7 +188,7 @@ export class Xliff2TranslationSerializer implements TranslationSerializer {
|
||||||
* and links are special cases.
|
* and links are special cases.
|
||||||
*/
|
*/
|
||||||
function getTypeForPlaceholder(placeholder: string): string|null {
|
function getTypeForPlaceholder(placeholder: string): string|null {
|
||||||
const tag = placeholder.replace(/^(START_|CLOSE_)/, '');
|
const tag = placeholder.replace(/^(START_|CLOSE_)/, '').replace(/_\d+$/, '');
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case 'BOLD_TEXT':
|
case 'BOLD_TEXT':
|
||||||
case 'EMPHASISED_TEXT':
|
case 'EMPHASISED_TEXT':
|
||||||
|
|
|
@ -301,6 +301,27 @@ runInEachFileSystem(() => {
|
||||||
'<source>a<pc id="0" equivStart="START_TAG_DIV" equivEnd="CLOSE_TAG_DIV" type="other">b</pc>c</source>',
|
'<source>a<pc id="0" equivStart="START_TAG_DIV" equivEnd="CLOSE_TAG_DIV" type="other">b</pc>c</source>',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render the "type" for link elements', () => {
|
||||||
|
const serializer = new Xliff2TranslationSerializer(
|
||||||
|
'xx', absoluteFrom('/project'), useLegacyIds, options);
|
||||||
|
const output = serializer.serialize(
|
||||||
|
[mockMessage('6', ['a', 'b', 'c'], ['START_LINK', 'CLOSE_LINK'], {})]);
|
||||||
|
expect(output).toContain(
|
||||||
|
'<source>a<pc id="0" equivStart="START_LINK" equivEnd="CLOSE_LINK" type="link">b</pc>c</source>',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render generic close tag placeholders for additional elements', () => {
|
||||||
|
const serializer = new Xliff2TranslationSerializer(
|
||||||
|
'xx', absoluteFrom('/project'), useLegacyIds, options);
|
||||||
|
const output = serializer.serialize([mockMessage(
|
||||||
|
'6', ['a', 'b', 'c', 'd', 'e'],
|
||||||
|
['START_LINK', 'CLOSE_LINK', 'START_LINK_1', 'CLOSE_LINK'], {})]);
|
||||||
|
expect(output).toContain(
|
||||||
|
'<source>a<pc id="0" equivStart="START_LINK" equivEnd="CLOSE_LINK" type="link">b</pc>c<pc id="1" equivStart="START_LINK_1" equivEnd="CLOSE_LINK" type="link">d</pc>e</source>',
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue