fix(compiler): only lex messages that are needed by angular (#14208)
To avoid the lexer erroring on syntax not supported by Angular. PR Close #14208
This commit is contained in:
parent
52b21275f4
commit
5921c872b6
|
@ -24,7 +24,7 @@ export class Xtb extends Serializer {
|
||||||
load(content: string, url: string): {[msgId: string]: i18n.Node[]} {
|
load(content: string, url: string): {[msgId: string]: i18n.Node[]} {
|
||||||
// xtb to xml nodes
|
// xtb to xml nodes
|
||||||
const xtbParser = new XtbParser();
|
const xtbParser = new XtbParser();
|
||||||
const {mlNodesByMsgId, errors} = xtbParser.parse(content, url);
|
const {msgIdToHtml, errors} = xtbParser.parse(content, url);
|
||||||
|
|
||||||
// xml nodes to i18n nodes
|
// xml nodes to i18n nodes
|
||||||
const i18nNodesByMsgId: {[msgId: string]: i18n.Node[]} = {};
|
const i18nNodesByMsgId: {[msgId: string]: i18n.Node[]} = {};
|
||||||
|
@ -33,9 +33,9 @@ export class Xtb extends Serializer {
|
||||||
// Because we should be able to load xtb files that rely on features not supported by angular,
|
// Because we should be able to load xtb files that rely on features not supported by angular,
|
||||||
// we need to delay the conversion of html to i18n nodes so that non angular messages are not
|
// we need to delay the conversion of html to i18n nodes so that non angular messages are not
|
||||||
// converted
|
// converted
|
||||||
Object.keys(mlNodesByMsgId).forEach(msgId => {
|
Object.keys(msgIdToHtml).forEach(msgId => {
|
||||||
const valueFn = function() {
|
const valueFn = function() {
|
||||||
const {i18nNodes, errors} = converter.convert(mlNodesByMsgId[msgId]);
|
const {i18nNodes, errors} = converter.convert(msgIdToHtml[msgId], url);
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
throw new Error(`xtb parse errors:\n${errors.join('\n')}`);
|
throw new Error(`xtb parse errors:\n${errors.join('\n')}`);
|
||||||
}
|
}
|
||||||
|
@ -75,19 +75,21 @@ function createLazyProperty(messages: any, id: string, valueFn: () => any) {
|
||||||
class XtbParser implements ml.Visitor {
|
class XtbParser implements ml.Visitor {
|
||||||
private _bundleDepth: number;
|
private _bundleDepth: number;
|
||||||
private _errors: I18nError[];
|
private _errors: I18nError[];
|
||||||
private _mlNodesByMsgId: {[msgId: string]: ml.Node[]};
|
private _msgIdToHtml: {[msgId: string]: string};
|
||||||
|
|
||||||
parse(xtb: string, url: string) {
|
parse(xtb: string, url: string) {
|
||||||
this._bundleDepth = 0;
|
this._bundleDepth = 0;
|
||||||
this._mlNodesByMsgId = {};
|
this._msgIdToHtml = {};
|
||||||
|
|
||||||
const xml = new XmlParser().parse(xtb, url, true);
|
// We can not parse the ICU messages at this point as some messages might not originate
|
||||||
|
// from Angular that could not be lex'd.
|
||||||
|
const xml = new XmlParser().parse(xtb, url, false);
|
||||||
|
|
||||||
this._errors = xml.errors;
|
this._errors = xml.errors;
|
||||||
ml.visitAll(this, xml.rootNodes);
|
ml.visitAll(this, xml.rootNodes);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mlNodesByMsgId: this._mlNodesByMsgId,
|
msgIdToHtml: this._msgIdToHtml,
|
||||||
errors: this._errors,
|
errors: this._errors,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -109,10 +111,14 @@ class XtbParser implements ml.Visitor {
|
||||||
this._addError(element, `<${_TRANSLATION_TAG}> misses the "id" attribute`);
|
this._addError(element, `<${_TRANSLATION_TAG}> misses the "id" attribute`);
|
||||||
} else {
|
} else {
|
||||||
const id = idAttr.value;
|
const id = idAttr.value;
|
||||||
if (this._mlNodesByMsgId.hasOwnProperty(id)) {
|
if (this._msgIdToHtml.hasOwnProperty(id)) {
|
||||||
this._addError(element, `Duplicated translations for msg ${id}`);
|
this._addError(element, `Duplicated translations for msg ${id}`);
|
||||||
} else {
|
} else {
|
||||||
this._mlNodesByMsgId[id] = 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._msgIdToHtml[id] = innerText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -141,10 +147,16 @@ class XtbParser implements ml.Visitor {
|
||||||
class XmlToI18n implements ml.Visitor {
|
class XmlToI18n implements ml.Visitor {
|
||||||
private _errors: I18nError[];
|
private _errors: I18nError[];
|
||||||
|
|
||||||
convert(nodes: ml.Node[]) {
|
convert(message: string, url: string) {
|
||||||
this._errors = [];
|
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 {
|
return {
|
||||||
i18nNodes: ml.visitAll(this, nodes),
|
i18nNodes,
|
||||||
errors: this._errors,
|
errors: this._errors,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ export function main(): void {
|
||||||
const XTB = `<?xml version="1.0" encoding="UTF-8" ?>
|
const XTB = `<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<translationbundle>
|
<translationbundle>
|
||||||
<translation id="angular">is great</translation>
|
<translation id="angular">is great</translation>
|
||||||
<translation id="non angular">is <invalid>less</invalid> great</translation>
|
<translation id="non angular">is <invalid>less</invalid> {count, plural, =0 {{GREAT}}}</translation>
|
||||||
</translationbundle>`;
|
</translationbundle>`;
|
||||||
|
|
||||||
// Invalid messages should not cause the parser to throw
|
// Invalid messages should not cause the parser to throw
|
||||||
|
|
Loading…
Reference in New Issue