fix(localize): render text of extracted placeholders (#38536)
Formats like XLIFF allow the text of the original source to be included as metadata. This commit fixes the message extractor to also render this text when available. PR Close #38536
This commit is contained in:
parent
db3a21b382
commit
14e90bef58
|
@ -77,6 +77,20 @@ export class MessageExtractor {
|
||||||
for (const message of messages) {
|
for (const message of messages) {
|
||||||
if (message.location !== undefined) {
|
if (message.location !== undefined) {
|
||||||
message.location = this.getOriginalLocation(sourceFile, message.location);
|
message.location = this.getOriginalLocation(sourceFile, message.location);
|
||||||
|
|
||||||
|
if (message.messagePartLocations) {
|
||||||
|
message.messagePartLocations = message.messagePartLocations.map(
|
||||||
|
location => location && this.getOriginalLocation(sourceFile, location));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.substitutionLocations) {
|
||||||
|
const placeholderNames = Object.keys(message.substitutionLocations);
|
||||||
|
for (const placeholderName of placeholderNames) {
|
||||||
|
const location = message.substitutionLocations[placeholderName];
|
||||||
|
message.substitutionLocations[placeholderName] =
|
||||||
|
location && this.getOriginalLocation(sourceFile, location);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,8 @@ export class Xliff1TranslationSerializer implements TranslationSerializer {
|
||||||
const length = message.messageParts.length - 1;
|
const length = message.messageParts.length - 1;
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
this.serializeTextPart(xml, message.messageParts[i]);
|
this.serializeTextPart(xml, message.messageParts[i]);
|
||||||
xml.startTag('x', {id: message.placeholderNames[i]}, {selfClosing: true});
|
const location = message.substitutionLocations?.[message.placeholderNames[i]];
|
||||||
|
this.serializePlaceholder(xml, message.placeholderNames[i], location?.text);
|
||||||
}
|
}
|
||||||
this.serializeTextPart(xml, message.messageParts[length]);
|
this.serializeTextPart(xml, message.messageParts[length]);
|
||||||
}
|
}
|
||||||
|
@ -77,11 +78,19 @@ export class Xliff1TranslationSerializer implements TranslationSerializer {
|
||||||
const length = pieces.length - 1;
|
const length = pieces.length - 1;
|
||||||
for (let i = 0; i < length; i += 2) {
|
for (let i = 0; i < length; i += 2) {
|
||||||
xml.text(pieces[i]);
|
xml.text(pieces[i]);
|
||||||
xml.startTag('x', {id: pieces[i + 1]}, {selfClosing: true});
|
this.serializePlaceholder(xml, pieces[i + 1], undefined);
|
||||||
}
|
}
|
||||||
xml.text(pieces[length]);
|
xml.text(pieces[length]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private serializePlaceholder(xml: XmlFile, id: string, text: string|undefined): void {
|
||||||
|
const attrs: Record<string, string> = {id};
|
||||||
|
if (text !== undefined) {
|
||||||
|
attrs['equiv-text'] = text;
|
||||||
|
}
|
||||||
|
xml.startTag('x', attrs, {selfClosing: true});
|
||||||
|
}
|
||||||
|
|
||||||
private serializeNote(xml: XmlFile, name: string, value: string): void {
|
private serializeNote(xml: XmlFile, name: string, value: string): void {
|
||||||
xml.startTag('note', {priority: '1', from: name}, {preserveWhitespace: true});
|
xml.startTag('note', {priority: '1', from: name}, {preserveWhitespace: true});
|
||||||
xml.text(value);
|
xml.text(value);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {AbsoluteFsPath, relative} from '@angular/compiler-cli/src/ngtsc/file_system';
|
import {AbsoluteFsPath, relative} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||||
import {ɵParsedMessage} from '@angular/localize';
|
import {ɵParsedMessage, ɵSourceLocation} from '@angular/localize';
|
||||||
|
|
||||||
import {extractIcuPlaceholders} from './icu_parsing';
|
import {extractIcuPlaceholders} from './icu_parsing';
|
||||||
import {TranslationSerializer} from './translation_serializer';
|
import {TranslationSerializer} from './translation_serializer';
|
||||||
|
@ -80,7 +80,7 @@ export class Xliff2TranslationSerializer implements TranslationSerializer {
|
||||||
const length = message.messageParts.length - 1;
|
const length = message.messageParts.length - 1;
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
this.serializeTextPart(xml, message.messageParts[i]);
|
this.serializeTextPart(xml, message.messageParts[i]);
|
||||||
this.serializePlaceholder(xml, message.placeholderNames[i]);
|
this.serializePlaceholder(xml, message.placeholderNames[i], message.substitutionLocations);
|
||||||
}
|
}
|
||||||
this.serializeTextPart(xml, message.messageParts[length]);
|
this.serializeTextPart(xml, message.messageParts[length]);
|
||||||
}
|
}
|
||||||
|
@ -90,24 +90,40 @@ export class Xliff2TranslationSerializer implements TranslationSerializer {
|
||||||
const length = pieces.length - 1;
|
const length = pieces.length - 1;
|
||||||
for (let i = 0; i < length; i += 2) {
|
for (let i = 0; i < length; i += 2) {
|
||||||
xml.text(pieces[i]);
|
xml.text(pieces[i]);
|
||||||
this.serializePlaceholder(xml, pieces[i + 1]);
|
this.serializePlaceholder(xml, pieces[i + 1], undefined);
|
||||||
}
|
}
|
||||||
xml.text(pieces[length]);
|
xml.text(pieces[length]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private serializePlaceholder(xml: XmlFile, placeholderName: string): void {
|
private serializePlaceholder(
|
||||||
|
xml: XmlFile, placeholderName: string,
|
||||||
|
substitutionLocations: Record<string, ɵSourceLocation|undefined>|undefined): void {
|
||||||
|
const text = substitutionLocations?.[placeholderName]?.text;
|
||||||
|
|
||||||
if (placeholderName.startsWith('START_')) {
|
if (placeholderName.startsWith('START_')) {
|
||||||
xml.startTag('pc', {
|
const closingPlaceholderName = placeholderName.replace(/^START/, 'CLOSE');
|
||||||
|
const closingText = substitutionLocations?.[closingPlaceholderName]?.text;
|
||||||
|
const attrs: Record<string, string> = {
|
||||||
id: `${this.currentPlaceholderId++}`,
|
id: `${this.currentPlaceholderId++}`,
|
||||||
equivStart: placeholderName,
|
equivStart: placeholderName,
|
||||||
equivEnd: placeholderName.replace(/^START/, 'CLOSE')
|
equivEnd: closingPlaceholderName,
|
||||||
});
|
};
|
||||||
|
if (text !== undefined) {
|
||||||
|
attrs.dispStart = text;
|
||||||
|
}
|
||||||
|
if (closingText !== undefined) {
|
||||||
|
attrs.dispEnd = closingText;
|
||||||
|
}
|
||||||
|
xml.startTag('pc', attrs);
|
||||||
} else if (placeholderName.startsWith('CLOSE_')) {
|
} else if (placeholderName.startsWith('CLOSE_')) {
|
||||||
xml.endTag('pc');
|
xml.endTag('pc');
|
||||||
} else {
|
} else {
|
||||||
xml.startTag(
|
const attrs:
|
||||||
'ph', {id: `${this.currentPlaceholderId++}`, equiv: placeholderName},
|
Record<string, string> = {id: `${this.currentPlaceholderId++}`, equiv: placeholderName};
|
||||||
{selfClosing: true});
|
if (text !== undefined) {
|
||||||
|
attrs.disp = text;
|
||||||
|
}
|
||||||
|
xml.startTag('ph', attrs, {selfClosing: true});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,8 @@ runInEachFileSystem(() => {
|
||||||
` "8669027859022295761": "try{$PH}me",`,
|
` "8669027859022295761": "try{$PH}me",`,
|
||||||
` "custom-id": "Custom id message",`,
|
` "custom-id": "Custom id message",`,
|
||||||
` "273296103957933077": "Legacy id message",`,
|
` "273296103957933077": "Legacy id message",`,
|
||||||
` "custom-id-2": "Custom and legacy message"`,
|
` "custom-id-2": "Custom and legacy message",`,
|
||||||
|
` "2932901491976224757": "pre{$START_TAG_SPAN}inner-pre{$START_BOLD_TEXT}bold{$CLOSE_BOLD_TEXT}inner-post{$CLOSE_TAG_SPAN}post"`,
|
||||||
` }`,
|
` }`,
|
||||||
`}`,
|
`}`,
|
||||||
].join('\n'));
|
].join('\n'));
|
||||||
|
@ -127,6 +128,8 @@ runInEachFileSystem(() => {
|
||||||
'12345678901234567890' :
|
'12345678901234567890' :
|
||||||
'273296103957933077'}"><source>test_files/test.js:5</source>Legacy id message</msg>`,
|
'273296103957933077'}"><source>test_files/test.js:5</source>Legacy id message</msg>`,
|
||||||
` <msg id="custom-id-2"><source>test_files/test.js:7</source>Custom and legacy message</msg>`,
|
` <msg id="custom-id-2"><source>test_files/test.js:7</source>Custom and legacy message</msg>`,
|
||||||
|
` <msg id="2932901491976224757"><source>test_files/test.js:8,10</source>pre<ph name="START_TAG_SPAN"/>` +
|
||||||
|
`inner-pre<ph name="START_BOLD_TEXT"/>bold<ph name="CLOSE_BOLD_TEXT"/>inner-post<ph name="CLOSE_TAG_SPAN"/>post</msg>`,
|
||||||
`</messagebundle>\n`,
|
`</messagebundle>\n`,
|
||||||
].join('\n'));
|
].join('\n'));
|
||||||
});
|
});
|
||||||
|
@ -149,14 +152,14 @@ runInEachFileSystem(() => {
|
||||||
` <file source-language="en-CA" datatype="plaintext">`,
|
` <file source-language="en-CA" datatype="plaintext">`,
|
||||||
` <body>`,
|
` <body>`,
|
||||||
` <trans-unit id="3291030485717846467" datatype="html">`,
|
` <trans-unit id="3291030485717846467" datatype="html">`,
|
||||||
` <source>Hello, <x id="PH"/>!</source>`,
|
` <source>Hello, <x id="PH" equiv-text="name"/>!</source>`,
|
||||||
` <context-group purpose="location">`,
|
` <context-group purpose="location">`,
|
||||||
` <context context-type="sourcefile">test_files/test.js</context>`,
|
` <context context-type="sourcefile">test_files/test.js</context>`,
|
||||||
` <context context-type="linenumber">2</context>`,
|
` <context context-type="linenumber">2</context>`,
|
||||||
` </context-group>`,
|
` </context-group>`,
|
||||||
` </trans-unit>`,
|
` </trans-unit>`,
|
||||||
` <trans-unit id="8669027859022295761" datatype="html">`,
|
` <trans-unit id="8669027859022295761" datatype="html">`,
|
||||||
` <source>try<x id="PH"/>me</source>`,
|
` <source>try<x id="PH" equiv-text="40 + 2"/>me</source>`,
|
||||||
` <context-group purpose="location">`,
|
` <context-group purpose="location">`,
|
||||||
` <context context-type="sourcefile">test_files/test.js</context>`,
|
` <context context-type="sourcefile">test_files/test.js</context>`,
|
||||||
` <context context-type="linenumber">3</context>`,
|
` <context context-type="linenumber">3</context>`,
|
||||||
|
@ -185,6 +188,15 @@ runInEachFileSystem(() => {
|
||||||
` <context context-type="linenumber">8</context>`,
|
` <context context-type="linenumber">8</context>`,
|
||||||
` </context-group>`,
|
` </context-group>`,
|
||||||
` </trans-unit>`,
|
` </trans-unit>`,
|
||||||
|
` <trans-unit id="2932901491976224757" datatype="html">`,
|
||||||
|
` <source>pre<x id="START_TAG_SPAN" equiv-text="'<span>'"/>` +
|
||||||
|
`inner-pre<x id="START_BOLD_TEXT" equiv-text="'<b>'"/>bold<x id="CLOSE_BOLD_TEXT" equiv-text="'</b>'"/>` +
|
||||||
|
`inner-post<x id="CLOSE_TAG_SPAN" equiv-text="'</span>'"/>post</source>`,
|
||||||
|
` <context-group purpose="location">`,
|
||||||
|
` <context context-type="sourcefile">test_files/test.js</context>`,
|
||||||
|
` <context context-type="linenumber">9,10</context>`,
|
||||||
|
` </context-group>`,
|
||||||
|
` </trans-unit>`,
|
||||||
` </body>`,
|
` </body>`,
|
||||||
` </file>`,
|
` </file>`,
|
||||||
`</xliff>\n`,
|
`</xliff>\n`,
|
||||||
|
@ -209,12 +221,12 @@ runInEachFileSystem(() => {
|
||||||
` <file>`,
|
` <file>`,
|
||||||
` <unit id="3291030485717846467">`,
|
` <unit id="3291030485717846467">`,
|
||||||
` <segment>`,
|
` <segment>`,
|
||||||
` <source>Hello, <ph id="0" equiv="PH"/>!</source>`,
|
` <source>Hello, <ph id="0" equiv="PH" disp="name"/>!</source>`,
|
||||||
` </segment>`,
|
` </segment>`,
|
||||||
` </unit>`,
|
` </unit>`,
|
||||||
` <unit id="8669027859022295761">`,
|
` <unit id="8669027859022295761">`,
|
||||||
` <segment>`,
|
` <segment>`,
|
||||||
` <source>try<ph id="0" equiv="PH"/>me</source>`,
|
` <source>try<ph id="0" equiv="PH" disp="40 + 2"/>me</source>`,
|
||||||
` </segment>`,
|
` </segment>`,
|
||||||
` </unit>`,
|
` </unit>`,
|
||||||
` <unit id="custom-id">`,
|
` <unit id="custom-id">`,
|
||||||
|
@ -232,6 +244,13 @@ runInEachFileSystem(() => {
|
||||||
` <source>Custom and legacy message</source>`,
|
` <source>Custom and legacy message</source>`,
|
||||||
` </segment>`,
|
` </segment>`,
|
||||||
` </unit>`,
|
` </unit>`,
|
||||||
|
` <unit id="2932901491976224757">`,
|
||||||
|
` <segment>`,
|
||||||
|
` <source>pre<pc id="0" equivStart="START_TAG_SPAN" equivEnd="CLOSE_TAG_SPAN" dispStart="'<span>'" dispEnd="'</span>'">` +
|
||||||
|
`inner-pre<pc id="1" equivStart="START_BOLD_TEXT" equivEnd="CLOSE_BOLD_TEXT" dispStart="'<b>'" dispEnd="'</b>'">bold</pc>` +
|
||||||
|
`inner-post</pc>post</source>`,
|
||||||
|
` </segment>`,
|
||||||
|
` </unit>`,
|
||||||
` </file>`,
|
` </file>`,
|
||||||
`</xliff>\n`,
|
`</xliff>\n`,
|
||||||
].join('\n'));
|
].join('\n'));
|
||||||
|
@ -260,7 +279,7 @@ runInEachFileSystem(() => {
|
||||||
` <file source-language="en-CA" datatype="plaintext">`,
|
` <file source-language="en-CA" datatype="plaintext">`,
|
||||||
` <body>`,
|
` <body>`,
|
||||||
` <trans-unit id="157258427077572998" datatype="html">`,
|
` <trans-unit id="157258427077572998" datatype="html">`,
|
||||||
` <source>Message in <x id="a-file"/>!</source>`,
|
` <source>Message in <x id="a-file" equiv-text="file"/>!</source>`,
|
||||||
` <context-group purpose="location">`,
|
` <context-group purpose="location">`,
|
||||||
// These source file paths are due to how Bazel TypeScript compilation source-maps work
|
// These source file paths are due to how Bazel TypeScript compilation source-maps work
|
||||||
` <context context-type="sourcefile">../packages/localize/src/tools/test/extract/integration/test_files/src/a.ts</context>`,
|
` <context context-type="sourcefile">../packages/localize/src/tools/test/extract/integration/test_files/src/a.ts</context>`,
|
||||||
|
@ -268,7 +287,7 @@ runInEachFileSystem(() => {
|
||||||
` </context-group>`,
|
` </context-group>`,
|
||||||
` </trans-unit>`,
|
` </trans-unit>`,
|
||||||
` <trans-unit id="7829869508202074508" datatype="html">`,
|
` <trans-unit id="7829869508202074508" datatype="html">`,
|
||||||
` <source>Message in <x id="b-file"/>!</source>`,
|
` <source>Message in <x id="b-file" equiv-text="file"/>!</source>`,
|
||||||
` <context-group purpose="location">`,
|
` <context-group purpose="location">`,
|
||||||
` <context context-type="sourcefile">../packages/localize/src/tools/test/extract/integration/test_files/src/b.ts</context>`,
|
` <context context-type="sourcefile">../packages/localize/src/tools/test/extract/integration/test_files/src/b.ts</context>`,
|
||||||
` <context context-type="linenumber">3</context>`,
|
` <context context-type="linenumber">3</context>`,
|
||||||
|
|
|
@ -6,3 +6,5 @@ var legacyMessage =
|
||||||
$localize`:␟1234567890123456789012345678901234567890␟12345678901234567890:Legacy id message`;
|
$localize`:␟1234567890123456789012345678901234567890␟12345678901234567890:Legacy id message`;
|
||||||
var customAndLegacyMessage =
|
var customAndLegacyMessage =
|
||||||
$localize`:@@custom-id-2␟1234567890123456789012345678901234567890␟12345678901234567890:Custom and legacy message`;
|
$localize`:@@custom-id-2␟1234567890123456789012345678901234567890␟12345678901234567890:Custom and legacy message`;
|
||||||
|
var containers = $localize`pre${'<span>'}:START_TAG_SPAN:inner-pre${'<b>'}:START_BOLD_TEXT:bold${
|
||||||
|
'</b>'}:CLOSE_BOLD_TEXT:inner-post${'</span>'}:CLOSE_TAG_SPAN:post`;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {ɵParsedMessage} from '@angular/localize';
|
import {ɵParsedMessage} from '@angular/localize';
|
||||||
import {SourceLocation} from '@angular/localize/src/utils';
|
import {MessageId, SourceLocation} from '@angular/localize/src/utils';
|
||||||
|
|
||||||
export interface MockMessageOptions {
|
export interface MockMessageOptions {
|
||||||
customId?: string;
|
customId?: string;
|
||||||
|
@ -14,6 +14,8 @@ export interface MockMessageOptions {
|
||||||
description?: string;
|
description?: string;
|
||||||
location?: SourceLocation;
|
location?: SourceLocation;
|
||||||
legacyIds?: string[];
|
legacyIds?: string[];
|
||||||
|
messagePartLocations?: (SourceLocation|undefined)[];
|
||||||
|
substitutionLocations?: Record<string, SourceLocation|undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,23 +23,18 @@ export interface MockMessageOptions {
|
||||||
* `TranslationSerializer` tests.
|
* `TranslationSerializer` tests.
|
||||||
*/
|
*/
|
||||||
export function mockMessage(
|
export function mockMessage(
|
||||||
id: string, messageParts: string[], placeholderNames: string[],
|
id: MessageId, messageParts: string[], placeholderNames: string[],
|
||||||
{customId, meaning = '', description = '', location, legacyIds = []}: MockMessageOptions):
|
options: MockMessageOptions): ɵParsedMessage {
|
||||||
ɵParsedMessage {
|
|
||||||
let text = messageParts[0];
|
let text = messageParts[0];
|
||||||
for (let i = 1; i < messageParts.length; i++) {
|
for (let i = 1; i < messageParts.length; i++) {
|
||||||
text += `{$${placeholderNames[i - 1]}}${messageParts[i]}`;
|
text += `{$${placeholderNames[i - 1]}}${messageParts[i]}`;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
id: customId || id, // customId trumps id
|
substitutions: [],
|
||||||
|
...options,
|
||||||
|
id: options.customId || id, // customId trumps id
|
||||||
text,
|
text,
|
||||||
messageParts,
|
messageParts,
|
||||||
placeholderNames,
|
placeholderNames,
|
||||||
customId,
|
|
||||||
description,
|
|
||||||
meaning,
|
|
||||||
substitutions: [],
|
|
||||||
legacyIds,
|
|
||||||
location,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
import {absoluteFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
|
import {absoluteFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||||
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
||||||
import {ɵParsedMessage} from '@angular/localize';
|
import {ɵParsedMessage, ɵSourceLocation} from '@angular/localize';
|
||||||
|
|
||||||
import {Xliff1TranslationSerializer} from '../../../src/extract/translation_files/xliff1_translation_serializer';
|
import {Xliff1TranslationSerializer} from '../../../src/extract/translation_files/xliff1_translation_serializer';
|
||||||
|
|
||||||
|
@ -18,6 +18,18 @@ runInEachFileSystem(() => {
|
||||||
[false, true].forEach(useLegacyIds => {
|
[false, true].forEach(useLegacyIds => {
|
||||||
describe(`renderFile() [using ${useLegacyIds ? 'legacy' : 'canonical'} ids]`, () => {
|
describe(`renderFile() [using ${useLegacyIds ? 'legacy' : 'canonical'} ids]`, () => {
|
||||||
it('should convert a set of parsed messages into an XML string', () => {
|
it('should convert a set of parsed messages into an XML string', () => {
|
||||||
|
const phLocation: ɵSourceLocation = {
|
||||||
|
start: {line: 0, column: 10},
|
||||||
|
end: {line: 1, column: 15},
|
||||||
|
file: absoluteFrom('/project/file.ts'),
|
||||||
|
text: 'placeholder + 1'
|
||||||
|
};
|
||||||
|
const messagePartLocation: ɵSourceLocation = {
|
||||||
|
start: {line: 0, column: 5},
|
||||||
|
end: {line: 0, column: 10},
|
||||||
|
file: absoluteFrom('/project/file.ts'),
|
||||||
|
text: 'message part'
|
||||||
|
};
|
||||||
const messages: ɵParsedMessage[] = [
|
const messages: ɵParsedMessage[] = [
|
||||||
mockMessage('12345', ['a', 'b', 'c'], ['PH', 'PH_1'], {
|
mockMessage('12345', ['a', 'b', 'c'], ['PH', 'PH_1'], {
|
||||||
meaning: 'some meaning',
|
meaning: 'some meaning',
|
||||||
|
@ -31,6 +43,8 @@ runInEachFileSystem(() => {
|
||||||
mockMessage('54321', ['a', 'b', 'c'], ['PH', 'PH_1'], {
|
mockMessage('54321', ['a', 'b', 'c'], ['PH', 'PH_1'], {
|
||||||
customId: 'someId',
|
customId: 'someId',
|
||||||
legacyIds: ['87654321FEDCBA0987654321FEDCBA0987654321', '563965274788097516'],
|
legacyIds: ['87654321FEDCBA0987654321FEDCBA0987654321', '563965274788097516'],
|
||||||
|
messagePartLocations: [undefined, messagePartLocation, undefined],
|
||||||
|
substitutionLocations: {'PH': phLocation, 'PH_1': undefined},
|
||||||
}),
|
}),
|
||||||
mockMessage(
|
mockMessage(
|
||||||
'67890', ['a', '', 'c'], ['START_TAG_SPAN', 'CLOSE_TAG_SPAN'],
|
'67890', ['a', '', 'c'], ['START_TAG_SPAN', 'CLOSE_TAG_SPAN'],
|
||||||
|
@ -71,7 +85,7 @@ runInEachFileSystem(() => {
|
||||||
` <note priority="1" from="meaning">some meaning</note>`,
|
` <note priority="1" from="meaning">some meaning</note>`,
|
||||||
` </trans-unit>`,
|
` </trans-unit>`,
|
||||||
` <trans-unit id="someId" datatype="html">`,
|
` <trans-unit id="someId" datatype="html">`,
|
||||||
` <source>a<x id="PH"/>b<x id="PH_1"/>c</source>`,
|
` <source>a<x id="PH" equiv-text="placeholder + 1"/>b<x id="PH_1"/>c</source>`,
|
||||||
` </trans-unit>`,
|
` </trans-unit>`,
|
||||||
` <trans-unit id="67890" datatype="html">`,
|
` <trans-unit id="67890" datatype="html">`,
|
||||||
` <source>a<x id="START_TAG_SPAN"/><x id="CLOSE_TAG_SPAN"/>c</source>`,
|
` <source>a<x id="START_TAG_SPAN"/><x id="CLOSE_TAG_SPAN"/>c</source>`,
|
||||||
|
|
|
@ -5,10 +5,9 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {computeMsgId} from '@angular/compiler';
|
|
||||||
import {absoluteFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
|
import {absoluteFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||||
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
||||||
import {ɵParsedMessage} from '@angular/localize';
|
import {ɵParsedMessage, ɵSourceLocation} from '@angular/localize';
|
||||||
|
|
||||||
import {Xliff2TranslationSerializer} from '../../../src/extract/translation_files/xliff2_translation_serializer';
|
import {Xliff2TranslationSerializer} from '../../../src/extract/translation_files/xliff2_translation_serializer';
|
||||||
|
|
||||||
|
@ -19,6 +18,18 @@ runInEachFileSystem(() => {
|
||||||
[false, true].forEach(useLegacyIds => {
|
[false, true].forEach(useLegacyIds => {
|
||||||
describe(`renderFile() [using ${useLegacyIds ? 'legacy' : 'canonical'} ids]`, () => {
|
describe(`renderFile() [using ${useLegacyIds ? 'legacy' : 'canonical'} ids]`, () => {
|
||||||
it('should convert a set of parsed messages into an XML string', () => {
|
it('should convert a set of parsed messages into an XML string', () => {
|
||||||
|
const phLocation: ɵSourceLocation = {
|
||||||
|
start: {line: 0, column: 10},
|
||||||
|
end: {line: 1, column: 15},
|
||||||
|
file: absoluteFrom('/project/file.ts'),
|
||||||
|
text: 'placeholder + 1'
|
||||||
|
};
|
||||||
|
const messagePartLocation: ɵSourceLocation = {
|
||||||
|
start: {line: 0, column: 5},
|
||||||
|
end: {line: 0, column: 10},
|
||||||
|
file: absoluteFrom('/project/file.ts'),
|
||||||
|
text: 'message part'
|
||||||
|
};
|
||||||
const messages: ɵParsedMessage[] = [
|
const messages: ɵParsedMessage[] = [
|
||||||
mockMessage('12345', ['a', 'b', 'c'], ['PH', 'PH_1'], {
|
mockMessage('12345', ['a', 'b', 'c'], ['PH', 'PH_1'], {
|
||||||
meaning: 'some meaning',
|
meaning: 'some meaning',
|
||||||
|
@ -32,6 +43,8 @@ runInEachFileSystem(() => {
|
||||||
mockMessage('54321', ['a', 'b', 'c'], ['PH', 'PH_1'], {
|
mockMessage('54321', ['a', 'b', 'c'], ['PH', 'PH_1'], {
|
||||||
customId: 'someId',
|
customId: 'someId',
|
||||||
legacyIds: ['87654321FEDCBA0987654321FEDCBA0987654321', '563965274788097516'],
|
legacyIds: ['87654321FEDCBA0987654321FEDCBA0987654321', '563965274788097516'],
|
||||||
|
messagePartLocations: [undefined, messagePartLocation, undefined],
|
||||||
|
substitutionLocations: {'PH': phLocation, 'PH_1': undefined},
|
||||||
}),
|
}),
|
||||||
mockMessage('67890', ['a', '', 'c'], ['START_TAG_SPAN', 'CLOSE_TAG_SPAN'], {
|
mockMessage('67890', ['a', '', 'c'], ['START_TAG_SPAN', 'CLOSE_TAG_SPAN'], {
|
||||||
description: 'some description',
|
description: 'some description',
|
||||||
|
@ -76,7 +89,7 @@ runInEachFileSystem(() => {
|
||||||
` </unit>`,
|
` </unit>`,
|
||||||
` <unit id="someId">`,
|
` <unit id="someId">`,
|
||||||
` <segment>`,
|
` <segment>`,
|
||||||
` <source>a<ph id="0" equiv="PH"/>b<ph id="1" equiv="PH_1"/>c</source>`,
|
` <source>a<ph id="0" equiv="PH" disp="placeholder + 1"/>b<ph id="1" equiv="PH_1"/>c</source>`,
|
||||||
` </segment>`,
|
` </segment>`,
|
||||||
` </unit>`,
|
` </unit>`,
|
||||||
` <unit id="67890">`,
|
` <unit id="67890">`,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
import {absoluteFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
|
import {absoluteFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||||
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
||||||
import {ɵParsedMessage} from '@angular/localize';
|
import {ɵParsedMessage, ɵSourceLocation} from '@angular/localize';
|
||||||
|
|
||||||
import {XmbTranslationSerializer} from '../../../src/extract/translation_files/xmb_translation_serializer';
|
import {XmbTranslationSerializer} from '../../../src/extract/translation_files/xmb_translation_serializer';
|
||||||
|
|
||||||
|
@ -18,6 +18,18 @@ runInEachFileSystem(() => {
|
||||||
[false, true].forEach(useLegacyIds => {
|
[false, true].forEach(useLegacyIds => {
|
||||||
describe(`renderFile() [using ${useLegacyIds ? 'legacy' : 'canonical'} ids]`, () => {
|
describe(`renderFile() [using ${useLegacyIds ? 'legacy' : 'canonical'} ids]`, () => {
|
||||||
it('should convert a set of parsed messages into an XML string', () => {
|
it('should convert a set of parsed messages into an XML string', () => {
|
||||||
|
const phLocation: ɵSourceLocation = {
|
||||||
|
start: {line: 0, column: 10},
|
||||||
|
end: {line: 1, column: 15},
|
||||||
|
file: absoluteFrom('/project/file.ts'),
|
||||||
|
text: 'placeholder + 1'
|
||||||
|
};
|
||||||
|
const messagePartLocation: ɵSourceLocation = {
|
||||||
|
start: {line: 0, column: 5},
|
||||||
|
end: {line: 0, column: 10},
|
||||||
|
file: absoluteFrom('/project/file.ts'),
|
||||||
|
text: 'message part'
|
||||||
|
};
|
||||||
const messages: ɵParsedMessage[] = [
|
const messages: ɵParsedMessage[] = [
|
||||||
mockMessage('12345', ['a', 'b', 'c'], ['PH', 'PH_1'], {
|
mockMessage('12345', ['a', 'b', 'c'], ['PH', 'PH_1'], {
|
||||||
meaning: 'some meaning',
|
meaning: 'some meaning',
|
||||||
|
@ -26,6 +38,8 @@ runInEachFileSystem(() => {
|
||||||
mockMessage('54321', ['a', 'b', 'c'], ['PH', 'PH_1'], {
|
mockMessage('54321', ['a', 'b', 'c'], ['PH', 'PH_1'], {
|
||||||
customId: 'someId',
|
customId: 'someId',
|
||||||
legacyIds: ['87654321FEDCBA0987654321FEDCBA0987654321', '563965274788097516'],
|
legacyIds: ['87654321FEDCBA0987654321FEDCBA0987654321', '563965274788097516'],
|
||||||
|
messagePartLocations: [undefined, messagePartLocation, undefined],
|
||||||
|
substitutionLocations: {'PH': phLocation, 'PH_1': undefined},
|
||||||
}),
|
}),
|
||||||
mockMessage(
|
mockMessage(
|
||||||
'67890', ['a', '', 'c'], ['START_TAG_SPAN', 'CLOSE_TAG_SPAN'],
|
'67890', ['a', '', 'c'], ['START_TAG_SPAN', 'CLOSE_TAG_SPAN'],
|
||||||
|
|
Loading…
Reference in New Issue