feat(compiler): support ICU messages in XLIFF
Fixes #12636 Closes #15068
This commit is contained in:
parent
95afaf495b
commit
b8d5f87f96
|
@ -77,13 +77,14 @@ export class Xliff extends Serializer {
|
|||
{locale: string, i18nNodesByMsgId: {[msgId: string]: i18n.Node[]}} {
|
||||
// xliff to xml nodes
|
||||
const xliffParser = new XliffParser();
|
||||
const {locale, mlNodesByMsgId, errors} = xliffParser.parse(content, url);
|
||||
const {locale, msgIdToHtml, errors} = xliffParser.parse(content, url);
|
||||
|
||||
// xml nodes to i18n nodes
|
||||
const i18nNodesByMsgId: {[msgId: string]: i18n.Node[]} = {};
|
||||
const converter = new XmlToI18n();
|
||||
Object.keys(mlNodesByMsgId).forEach(msgId => {
|
||||
const {i18nNodes, errors: e} = converter.convert(mlNodesByMsgId[msgId]);
|
||||
|
||||
Object.keys(msgIdToHtml).forEach(msgId => {
|
||||
const {i18nNodes, errors: e} = converter.convert(msgIdToHtml[msgId], url);
|
||||
errors.push(...e);
|
||||
i18nNodesByMsgId[msgId] = i18nNodes;
|
||||
});
|
||||
|
@ -99,8 +100,6 @@ export class Xliff extends Serializer {
|
|||
}
|
||||
|
||||
class _WriteVisitor implements i18n.Visitor {
|
||||
private _isInIcu: boolean;
|
||||
|
||||
visitText(text: i18n.Text, context?: any): xml.Node[] { return [new xml.Text(text.value)]; }
|
||||
|
||||
visitContainer(container: i18n.Container, context?: any): xml.Node[] {
|
||||
|
@ -110,18 +109,13 @@ class _WriteVisitor implements i18n.Visitor {
|
|||
}
|
||||
|
||||
visitIcu(icu: i18n.Icu, context?: any): xml.Node[] {
|
||||
if (this._isInIcu) {
|
||||
// nested ICU is not supported
|
||||
throw new Error('xliff does not support nested ICU messages');
|
||||
}
|
||||
this._isInIcu = true;
|
||||
const nodes = [new xml.Text(`{${icu.expressionPlaceholder}, ${icu.type}, `)];
|
||||
|
||||
// TODO(vicb): support ICU messages
|
||||
// https://lists.oasis-open.org/archives/xliff/201201/msg00028.html
|
||||
// http://docs.oasis-open.org/xliff/v1.2/xliff-profile-po/xliff-profile-po-1.2-cd02.html
|
||||
const nodes: xml.Node[] = [];
|
||||
Object.keys(icu.cases).forEach((c: string) => {
|
||||
nodes.push(new xml.Text(`${c} {`), ...icu.cases[c].visit(this), new xml.Text(`} `));
|
||||
});
|
||||
|
||||
this._isInIcu = false;
|
||||
nodes.push(new xml.Text(`}`));
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
@ -149,7 +143,6 @@ class _WriteVisitor implements i18n.Visitor {
|
|||
}
|
||||
|
||||
serialize(nodes: i18n.Node[]): xml.Node[] {
|
||||
this._isInIcu = false;
|
||||
return [].concat(...nodes.map(node => node.visit(this)));
|
||||
}
|
||||
}
|
||||
|
@ -157,14 +150,14 @@ class _WriteVisitor implements i18n.Visitor {
|
|||
// TODO(vicb): add error management (structure)
|
||||
// Extract messages as xml nodes from the xliff file
|
||||
class XliffParser implements ml.Visitor {
|
||||
private _unitMlNodes: ml.Node[];
|
||||
private _unitMlString: string;
|
||||
private _errors: I18nError[];
|
||||
private _mlNodesByMsgId: {[msgId: string]: ml.Node[]};
|
||||
private _msgIdToHtml: {[msgId: string]: string};
|
||||
private _locale: string|null = null;
|
||||
|
||||
parse(xliff: string, url: string) {
|
||||
this._unitMlNodes = [];
|
||||
this._mlNodesByMsgId = {};
|
||||
this._unitMlString = null;
|
||||
this._msgIdToHtml = {};
|
||||
|
||||
const xml = new XmlParser().parse(xliff, url, false);
|
||||
|
||||
|
@ -172,7 +165,7 @@ class XliffParser implements ml.Visitor {
|
|||
ml.visitAll(this, xml.rootNodes, null);
|
||||
|
||||
return {
|
||||
mlNodesByMsgId: this._mlNodesByMsgId,
|
||||
msgIdToHtml: this._msgIdToHtml,
|
||||
errors: this._errors,
|
||||
locale: this._locale,
|
||||
};
|
||||
|
@ -181,18 +174,18 @@ class XliffParser implements ml.Visitor {
|
|||
visitElement(element: ml.Element, context: any): any {
|
||||
switch (element.name) {
|
||||
case _UNIT_TAG:
|
||||
this._unitMlNodes = null;
|
||||
this._unitMlString = null;
|
||||
const idAttr = element.attrs.find((attr) => attr.name === 'id');
|
||||
if (!idAttr) {
|
||||
this._addError(element, `<${_UNIT_TAG}> misses the "id" attribute`);
|
||||
} else {
|
||||
const id = idAttr.value;
|
||||
if (this._mlNodesByMsgId.hasOwnProperty(id)) {
|
||||
if (this._msgIdToHtml.hasOwnProperty(id)) {
|
||||
this._addError(element, `Duplicated translations for msg ${id}`);
|
||||
} else {
|
||||
ml.visitAll(this, element.children, null);
|
||||
if (this._unitMlNodes) {
|
||||
this._mlNodesByMsgId[id] = this._unitMlNodes;
|
||||
if (typeof this._unitMlString === 'string') {
|
||||
this._msgIdToHtml[id] = this._unitMlString;
|
||||
} else {
|
||||
this._addError(element, `Message ${id} misses a translation`);
|
||||
}
|
||||
|
@ -205,7 +198,11 @@ class XliffParser implements ml.Visitor {
|
|||
break;
|
||||
|
||||
case _TARGET_TAG:
|
||||
this._unitMlNodes = element.children;
|
||||
const innerTextStart = element.startSourceSpan.end.offset;
|
||||
const innerTextEnd = element.endSourceSpan.start.offset;
|
||||
const content = element.startSourceSpan.start.file.content;
|
||||
const innerText = content.slice(innerTextStart, innerTextEnd);
|
||||
this._unitMlString = innerText;
|
||||
break;
|
||||
|
||||
case _FILE_TAG:
|
||||
|
@ -242,10 +239,16 @@ class XliffParser implements ml.Visitor {
|
|||
class XmlToI18n implements ml.Visitor {
|
||||
private _errors: I18nError[];
|
||||
|
||||
convert(nodes: ml.Node[]) {
|
||||
this._errors = [];
|
||||
convert(message: string, url: string) {
|
||||
const xmlIcu = new XmlParser().parse(message, url, true);
|
||||
this._errors = xmlIcu.errors;
|
||||
|
||||
const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ?
|
||||
[] :
|
||||
ml.visitAll(this, xmlIcu.rootNodes);
|
||||
|
||||
return {
|
||||
i18nNodes: ml.visitAll(this, nodes),
|
||||
i18nNodes: i18nNodes,
|
||||
errors: this._errors,
|
||||
};
|
||||
}
|
||||
|
@ -265,9 +268,22 @@ class XmlToI18n implements ml.Visitor {
|
|||
}
|
||||
}
|
||||
|
||||
visitExpansion(icu: ml.Expansion, context: any) {}
|
||||
visitExpansion(icu: ml.Expansion, context: any) {
|
||||
const caseMap: {[value: string]: i18n.Node} = {};
|
||||
|
||||
visitExpansionCase(icuCase: ml.ExpansionCase, context: any): any {}
|
||||
ml.visitAll(this, icu.cases).forEach((c: any) => {
|
||||
caseMap[c.value] = new i18n.Container(c.nodes, icu.sourceSpan);
|
||||
});
|
||||
|
||||
return new i18n.Icu(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
|
||||
}
|
||||
|
||||
visitExpansionCase(icuCase: ml.ExpansionCase, context: any): any {
|
||||
return {
|
||||
value: icuCase.value,
|
||||
nodes: ml.visitAll(this, icuCase.expression),
|
||||
};
|
||||
}
|
||||
|
||||
visitComment(comment: ml.Comment, context: any) {}
|
||||
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
import {NgLocalization} from '@angular/common';
|
||||
import {ResourceLoader} from '@angular/compiler';
|
||||
import {MessageBundle} from '@angular/compiler/src/i18n/message_bundle';
|
||||
import {Xliff} from '@angular/compiler/src/i18n/serializers/xliff';
|
||||
import {HtmlParser} from '@angular/compiler/src/ml_parser/html_parser';
|
||||
import {DEFAULT_INTERPOLATION_CONFIG} from '@angular/compiler/src/ml_parser/interpolation_config';
|
||||
import {DebugElement, TRANSLATIONS, TRANSLATIONS_FORMAT} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
import {SpyResourceLoader} from '../spies';
|
||||
|
||||
import {FrLocalization, HTML, I18nComponent, validateHtml} from './integration_common';
|
||||
|
||||
export function main() {
|
||||
describe('i18n XLIFF integration spec', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureCompiler({
|
||||
providers: [
|
||||
{provide: ResourceLoader, useClass: SpyResourceLoader},
|
||||
{provide: NgLocalization, useClass: FrLocalization},
|
||||
{provide: TRANSLATIONS, useValue: XLIFF_TOMERGE},
|
||||
{provide: TRANSLATIONS_FORMAT, useValue: 'xliff'},
|
||||
]
|
||||
});
|
||||
|
||||
TestBed.configureTestingModule({declarations: [I18nComponent]});
|
||||
}));
|
||||
|
||||
it('should extract from templates', () => {
|
||||
const catalog = new MessageBundle(new HtmlParser, [], {});
|
||||
const serializer = new Xliff();
|
||||
catalog.updateFromTemplate(HTML, '', DEFAULT_INTERPOLATION_CONFIG);
|
||||
|
||||
expect(catalog.write(serializer)).toContain(XLIFF_EXTRACTED);
|
||||
});
|
||||
|
||||
it('should translate templates', () => {
|
||||
const tb: ComponentFixture<I18nComponent> =
|
||||
TestBed.overrideTemplate(I18nComponent, HTML).createComponent(I18nComponent);
|
||||
const cmp: I18nComponent = tb.componentInstance;
|
||||
const el: DebugElement = tb.debugElement;
|
||||
|
||||
validateHtml(tb, cmp, el);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const XLIFF_TOMERGE = `
|
||||
<trans-unit id="3cb04208df1c2f62553ed48e75939cf7107f9dad" datatype="html">
|
||||
<source>i18n attribute on tags</source>
|
||||
<target>attributs i18n sur les balises</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="52895b1221effb3f3585b689f049d2784d714952" datatype="html">
|
||||
<source>nested</source>
|
||||
<target>imbriqué</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="88d5f22050a9df477ee5646153558b3a4862d47e" datatype="html">
|
||||
<source>nested</source>
|
||||
<target>imbriqué</target>
|
||||
<note priority="1" from="meaning">different meaning</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="34fec9cc62e28e8aa6ffb306fa8569ef0a8087fe" datatype="html">
|
||||
<source><x id="START_ITALIC_TEXT" ctype="x-i"/>with placeholders<x id="CLOSE_ITALIC_TEXT" ctype="x-i"/></source>
|
||||
<target><x id="START_ITALIC_TEXT" ctype="x-i"/>avec des espaces réservés<x id="CLOSE_ITALIC_TEXT" ctype="x-i"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="1fe4616cce80a57c7707bac1c97054aa8e244a67" datatype="html">
|
||||
<source>on not translatable node</source>
|
||||
<target>sur des balises non traductibles</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="67162b5af5f15fd0eb6480c88688dafdf952b93a" datatype="html">
|
||||
<source>on translatable node</source>
|
||||
<target>sur des balises traductibles</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="dc5536bb9e0e07291c185a0d306601a2ecd4813f" datatype="html">
|
||||
<source>{VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {<x id="START_BOLD_TEXT" ctype="x-b"/>many<x id="CLOSE_BOLD_TEXT" ctype="x-b"/>} }</source>
|
||||
<target>{VAR_PLURAL, plural, =0 {zero} =1 {un} =2 {deux} other {<x id="START_BOLD_TEXT" ctype="x-b"/>beaucoup<x id="CLOSE_BOLD_TEXT" ctype="x-b"/>} }</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="85ef51de59fe5a8d13fba977b6689f164420c8ca" datatype="html">
|
||||
<source>
|
||||
<x id="ICU"/>
|
||||
</source>
|
||||
<target><x id="ICU"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="c0ca5e58fe954d528bbfa516007a5a11690a7e99" datatype="html">
|
||||
<source>{VAR_SELECT, select, m {male} f {female} }</source>
|
||||
<target>{VAR_SELECT, select, m {homme} f {femme} }</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="078b7089573c5f66a2f78dce0adaa55e6715beb1" datatype="html">
|
||||
<source>
|
||||
<x id="ICU"/>
|
||||
</source>
|
||||
<target><x id="ICU"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="a25cf2e21a299f30be1392e731163825233edc61" datatype="html">
|
||||
<source>{VAR_SELECT, select, m {male} f {female} }</source>
|
||||
<target>{VAR_SELECT, select, m {homme} f {femme} }</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="d9879678f727b244bc7c7e20f22b63d98cb14890" datatype="html">
|
||||
<source><x id="INTERPOLATION"/></source>
|
||||
<target><x id="INTERPOLATION"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="50dac33dc6fc0578884baac79d875785ed77c928" datatype="html">
|
||||
<source>sex = <x id="INTERPOLATION"/></source>
|
||||
<target>sexe = <x id="INTERPOLATION"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="a46f833b1fe6ca49e8b97c18f4b7ea0b930c9383" datatype="html">
|
||||
<source><x id="CUSTOM_NAME"/></source>
|
||||
<target><x id="CUSTOM_NAME"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="2ec983b4893bcd5b24af33bebe3ecba63868453c" datatype="html">
|
||||
<source>in a translatable section</source>
|
||||
<target>dans une section traductible</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="eee74a5be8a75881a4785905bd8302a71f7d9f75" datatype="html">
|
||||
<source>
|
||||
<x id="START_HEADING_LEVEL1" ctype="x-h1"/>Markers in html comments<x id="CLOSE_HEADING_LEVEL1" ctype="x-h1"/>
|
||||
<x id="START_TAG_DIV" ctype="x-div"/><x id="CLOSE_TAG_DIV" ctype="x-div"/>
|
||||
<x id="START_TAG_DIV_1" ctype="x-div"/><x id="ICU"/><x id="CLOSE_TAG_DIV" ctype="x-div"/>
|
||||
</source>
|
||||
<target>
|
||||
<x id="START_HEADING_LEVEL1" ctype="x-h1"/>Balises dans les commentaires html<x id="CLOSE_HEADING_LEVEL1" ctype="x-h1"/>
|
||||
<x id="START_TAG_DIV" ctype="x-div"/><x id="CLOSE_TAG_DIV" ctype="x-div"/>
|
||||
<x id="START_TAG_DIV_1" ctype="x-div"/><x id="ICU"/><x id="CLOSE_TAG_DIV" ctype="x-div"/>
|
||||
</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="93a30c67d4e6c9b37aecfe2ac0f2b5d366d7b520" datatype="html">
|
||||
<source>it <x id="START_BOLD_TEXT" ctype="x-b"/>should<x id="CLOSE_BOLD_TEXT" ctype="x-b"/> work</source>
|
||||
<target>ca <x id="START_BOLD_TEXT" ctype="x-b"/>devrait<x id="CLOSE_BOLD_TEXT" ctype="x-b"/> marcher</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="i18n16" datatype="html">
|
||||
<source>with an explicit ID</source>
|
||||
<target>avec un ID explicite</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="i18n17" datatype="html">
|
||||
<source>{VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {<x id="START_BOLD_TEXT" ctype="x-b"/>many<x id="CLOSE_BOLD_TEXT" ctype="x-b"/>} }</source>
|
||||
<target>{VAR_PLURAL, plural, =0 {zero} =1 {un} =2 {deux} other {<x id="START_BOLD_TEXT" ctype="x-b"/>beaucoup<x id="CLOSE_BOLD_TEXT" ctype="x-b"/>} }</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="2370d995bdcc1e7496baa32df20654aff65c2d10" datatype="html">
|
||||
<source>{VAR_PLURAL, plural, =0 {Found no results} =1 {Found one result} other {Found <x id="INTERPOLATION"/> results} }</source>
|
||||
<target>{VAR_PLURAL, plural, =0 {Pas de réponse} =1 {une réponse} other {Found <x id="INTERPOLATION"/> réponse} }</target>
|
||||
<note priority="1" from="description">desc</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="296ab5eab8d370822488c152586db3a5875ee1a2" datatype="html">
|
||||
<source>foo<x id="START_LINK" ctype="x-a"/>bar<x id="CLOSE_LINK" ctype="x-a"/></source>
|
||||
<target>FOO<x id="START_LINK" ctype="x-a"/>BAR<x id="CLOSE_LINK" ctype="x-a"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="2e013b311caa0916478941a985887e091d8288b6" datatype="html">
|
||||
<source><x id="MAP NAME"/></source>
|
||||
<target><x id="MAP NAME"/></target>
|
||||
</trans-unit>`;
|
||||
|
||||
const XLIFF_EXTRACTED = `
|
||||
<trans-unit id="3cb04208df1c2f62553ed48e75939cf7107f9dad" datatype="html">
|
||||
<source>i18n attribute on tags</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="52895b1221effb3f3585b689f049d2784d714952" datatype="html">
|
||||
<source>nested</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="88d5f22050a9df477ee5646153558b3a4862d47e" datatype="html">
|
||||
<source>nested</source>
|
||||
<target/>
|
||||
<note priority="1" from="meaning">different meaning</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="34fec9cc62e28e8aa6ffb306fa8569ef0a8087fe" datatype="html">
|
||||
<source><x id="START_ITALIC_TEXT" ctype="x-i"/>with placeholders<x id="CLOSE_ITALIC_TEXT" ctype="x-i"/></source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="1fe4616cce80a57c7707bac1c97054aa8e244a67" datatype="html">
|
||||
<source>on not translatable node</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="67162b5af5f15fd0eb6480c88688dafdf952b93a" datatype="html">
|
||||
<source>on translatable node</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="dc5536bb9e0e07291c185a0d306601a2ecd4813f" datatype="html">
|
||||
<source>{VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {<x id="START_BOLD_TEXT" ctype="x-b"/>many<x id="CLOSE_BOLD_TEXT" ctype="x-b"/>} }</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="85ef51de59fe5a8d13fba977b6689f164420c8ca" datatype="html">
|
||||
<source>
|
||||
<x id="ICU"/>
|
||||
</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="c0ca5e58fe954d528bbfa516007a5a11690a7e99" datatype="html">
|
||||
<source>{VAR_SELECT, select, m {male} f {female} }</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="078b7089573c5f66a2f78dce0adaa55e6715beb1" datatype="html">
|
||||
<source>
|
||||
<x id="ICU"/>
|
||||
</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="a25cf2e21a299f30be1392e731163825233edc61" datatype="html">
|
||||
<source>{VAR_SELECT, select, m {male} f {female} }</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="d9879678f727b244bc7c7e20f22b63d98cb14890" datatype="html">
|
||||
<source><x id="INTERPOLATION"/></source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="50dac33dc6fc0578884baac79d875785ed77c928" datatype="html">
|
||||
<source>sex = <x id="INTERPOLATION"/></source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="a46f833b1fe6ca49e8b97c18f4b7ea0b930c9383" datatype="html">
|
||||
<source><x id="CUSTOM_NAME"/></source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="2ec983b4893bcd5b24af33bebe3ecba63868453c" datatype="html">
|
||||
<source>in a translatable section</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="eee74a5be8a75881a4785905bd8302a71f7d9f75" datatype="html">
|
||||
<source>
|
||||
<x id="START_HEADING_LEVEL1" ctype="x-h1"/>Markers in html comments<x id="CLOSE_HEADING_LEVEL1" ctype="x-h1"/>
|
||||
<x id="START_TAG_DIV" ctype="x-div"/><x id="CLOSE_TAG_DIV" ctype="x-div"/>
|
||||
<x id="START_TAG_DIV_1" ctype="x-div"/><x id="ICU"/><x id="CLOSE_TAG_DIV" ctype="x-div"/>
|
||||
</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="93a30c67d4e6c9b37aecfe2ac0f2b5d366d7b520" datatype="html">
|
||||
<source>it <x id="START_BOLD_TEXT" ctype="x-b"/>should<x id="CLOSE_BOLD_TEXT" ctype="x-b"/> work</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="i18n16" datatype="html">
|
||||
<source>with an explicit ID</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="i18n17" datatype="html">
|
||||
<source>{VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {<x id="START_BOLD_TEXT" ctype="x-b"/>many<x id="CLOSE_BOLD_TEXT" ctype="x-b"/>} }</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="2370d995bdcc1e7496baa32df20654aff65c2d10" datatype="html">
|
||||
<source>{VAR_PLURAL, plural, =0 {Found no results} =1 {Found one result} other {Found <x id="INTERPOLATION"/> results} }</source>
|
||||
<target/>
|
||||
<note priority="1" from="description">desc</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="296ab5eab8d370822488c152586db3a5875ee1a2" datatype="html">
|
||||
<source>foo<x id="START_LINK" ctype="x-a"/>bar<x id="CLOSE_LINK" ctype="x-a"/></source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="2e013b311caa0916478941a985887e091d8288b6" datatype="html">
|
||||
<source><x id="MAP NAME"/></source>
|
||||
<target/>
|
||||
</trans-unit>`;
|
|
@ -17,10 +17,13 @@ import {DEFAULT_INTERPOLATION_CONFIG} from '../../../src/ml_parser/interpolation
|
|||
const HTML = `
|
||||
<p i18n-title title="translatable attribute">not translatable</p>
|
||||
<p i18n>translatable element <b>with placeholders</b> {{ interpolation}}</p>
|
||||
<!-- i18n -->{ count, plural, =0 {<p>test</p>}}<!-- /i18n -->
|
||||
<p i18n="m|d">foo</p>
|
||||
<p i18n="m|d@@i">foo</p>
|
||||
<p i18n="@@bar">foo</p>
|
||||
<p i18n="ph names"><br><img><div></div></p>
|
||||
<p i18n="@@baz">{ count, plural, =0 { { sex, select, other {<p>deeply nested</p>}} }}</p>
|
||||
<p i18n>{ count, plural, =0 { { sex, select, other {<p>deeply nested</p>}} }}</p>
|
||||
`;
|
||||
|
||||
const WRITE_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
@ -35,6 +38,10 @@ const WRITE_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
|
|||
<source>translatable element <x id="START_BOLD_TEXT" ctype="x-b"/>with placeholders<x id="CLOSE_BOLD_TEXT" ctype="x-b"/> <x id="INTERPOLATION"/></source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="e2ccf3d131b15f54aa1fcf1314b1ca77c14bfcc2" datatype="html">
|
||||
<source>{VAR_PLURAL, plural, =0 {<x id="START_PARAGRAPH" ctype="x-p"/>test<x id="CLOSE_PARAGRAPH" ctype="x-p"/>} }</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="db3e0a6a5a96481f60aec61d98c3eecddef5ac23" datatype="html">
|
||||
<source>foo</source>
|
||||
<target/>
|
||||
|
@ -56,6 +63,14 @@ const WRITE_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
|
|||
<target/>
|
||||
<note priority="1" from="description">ph names</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="baz" datatype="html">
|
||||
<source>{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<x id="START_PARAGRAPH" ctype="x-p"/>deeply nested<x id="CLOSE_PARAGRAPH" ctype="x-p"/>} } } }</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
<trans-unit id="0e16a673a5a7a135c9f7b957ec2c5c6f6ee6e2c4" datatype="html">
|
||||
<source>{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<x id="START_PARAGRAPH" ctype="x-p"/>deeply nested<x id="CLOSE_PARAGRAPH" ctype="x-p"/>} } } }</source>
|
||||
<target/>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
@ -73,6 +88,10 @@ const LOAD_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
|
|||
<source>translatable element <x id="START_BOLD_TEXT" ctype="b"/>with placeholders<x id="CLOSE_BOLD_TEXT" ctype="b"/> <x id="INTERPOLATION"/></source>
|
||||
<target><x id="INTERPOLATION"/> footnemele elbatalsnart <x id="START_BOLD_TEXT" ctype="x-b"/>sredlohecalp htiw<x id="CLOSE_BOLD_TEXT" ctype="x-b"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="e2ccf3d131b15f54aa1fcf1314b1ca77c14bfcc2" datatype="html">
|
||||
<source>{VAR_PLURAL, plural, =0 {<x id="START_PARAGRAPH" ctype="x-p"/>test<x id="CLOSE_PARAGRAPH" ctype="x-p"/>} }</source>
|
||||
<target>{VAR_PLURAL, plural, =0 {<x id="START_PARAGRAPH" ctype="x-p"/>TEST<x id="CLOSE_PARAGRAPH" ctype="x-p"/>} }</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="db3e0a6a5a96481f60aec61d98c3eecddef5ac23" datatype="html">
|
||||
<source>foo</source>
|
||||
<target>oof</target>
|
||||
|
@ -99,6 +118,14 @@ const LOAD_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
|
|||
<target/>
|
||||
<note priority="1" from="description">ph names</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="baz" datatype="html">
|
||||
<source>{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<x id="START_PARAGRAPH" ctype="x-p"/>deeply nested<x id="CLOSE_PARAGRAPH" ctype="x-p"/>} } } }</source>
|
||||
<target>{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<x id="START_PARAGRAPH" ctype="x-p"/>profondément imbriqué<x id="CLOSE_PARAGRAPH" ctype="x-p"/>} } } }</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="0e16a673a5a7a135c9f7b957ec2c5c6f6ee6e2c4" datatype="html">
|
||||
<source>{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<x id="START_PARAGRAPH" ctype="x-p"/>deeply nested<x id="CLOSE_PARAGRAPH" ctype="x-p"/>} } } }</source>
|
||||
<target>{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<x id="START_PARAGRAPH" ctype="x-p"/>profondément imbriqué<x id="CLOSE_PARAGRAPH" ctype="x-p"/>} } } }</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
@ -136,12 +163,18 @@ export function main(): void {
|
|||
'983775b9a51ce14b036be72d4cfd65d68d64e231': 'etubirtta elbatalsnart',
|
||||
'ec1d033f2436133c14ab038286c4f5df4697484a':
|
||||
'<ph name="INTERPOLATION"/> footnemele elbatalsnart <ph name="START_BOLD_TEXT"/>sredlohecalp htiw<ph name="CLOSE_BOLD_TEXT"/>',
|
||||
'e2ccf3d131b15f54aa1fcf1314b1ca77c14bfcc2':
|
||||
'{VAR_PLURAL, plural, =0 {[<ph name="START_PARAGRAPH"/>, TEST, <ph name="CLOSE_PARAGRAPH"/>]}}',
|
||||
'db3e0a6a5a96481f60aec61d98c3eecddef5ac23': 'oof',
|
||||
'i': 'toto',
|
||||
'bar': 'tata',
|
||||
'd7fa2d59aaedcaa5309f13028c59af8c85b8c49d':
|
||||
'<ph name="START_TAG_DIV"/><ph name="CLOSE_TAG_DIV"/><ph name="TAG_IMG"/><ph name="LINE_BREAK"/>',
|
||||
'empty target': '',
|
||||
'baz':
|
||||
'{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[<ph name="START_PARAGRAPH"/>, profondément imbriqué, <ph name="CLOSE_PARAGRAPH"/>]}}, ]}}',
|
||||
'0e16a673a5a7a135c9f7b957ec2c5c6f6ee6e2c4':
|
||||
'{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[<ph name="START_PARAGRAPH"/>, profondément imbriqué, <ph name="CLOSE_PARAGRAPH"/>]}}, ]}}'
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue