fix(i18n): translate attributes inside elements marked for translation
fixes #13796 fixes #13814
This commit is contained in:
parent
5cb2008e6c
commit
424e6c4cb9
|
@ -55,20 +55,22 @@ enum _VisitorMode {
|
|||
* @internal
|
||||
*/
|
||||
class _Visitor implements html.Visitor {
|
||||
private _depth: number;
|
||||
|
||||
// <el i18n>...</el>
|
||||
private _inI18nNode: boolean;
|
||||
private _depth: number;
|
||||
private _inImplicitNode: boolean;
|
||||
|
||||
// <!--i18n-->...<!--/i18n-->
|
||||
private _inI18nBlock: boolean;
|
||||
private _blockMeaningAndDesc: string;
|
||||
private _blockChildren: html.Node[];
|
||||
private _blockStartDepth: number;
|
||||
private _inI18nBlock: boolean;
|
||||
|
||||
// {<icu message>}
|
||||
private _inIcu: boolean;
|
||||
|
||||
// set to void 0 when not in a section
|
||||
private _msgCountAtSectionStart: number;
|
||||
private _errors: I18nError[];
|
||||
private _mode: _VisitorMode;
|
||||
|
@ -210,50 +212,31 @@ class _Visitor implements html.Visitor {
|
|||
this._depth++;
|
||||
const wasInI18nNode = this._inI18nNode;
|
||||
const wasInImplicitNode = this._inImplicitNode;
|
||||
let childNodes: html.Node[];
|
||||
let childNodes: html.Node[] = [];
|
||||
let translatedChildNodes: html.Node[];
|
||||
|
||||
// Extract only top level nodes with the (implicit) "i18n" attribute if not in a block or an ICU
|
||||
// message
|
||||
// Extract:
|
||||
// - top level nodes with the (implicit) "i18n" attribute if not already in a section
|
||||
// - ICU messages
|
||||
const i18nAttr = _getI18nAttr(el);
|
||||
const i18nMeta = i18nAttr ? i18nAttr.value : '';
|
||||
const isImplicit = this._implicitTags.some(tag => el.name === tag) && !this._inIcu &&
|
||||
!this._isInTranslatableSection;
|
||||
const isTopLevelImplicit = !wasInImplicitNode && isImplicit;
|
||||
this._inImplicitNode = this._inImplicitNode || isImplicit;
|
||||
this._inImplicitNode = wasInImplicitNode || isImplicit;
|
||||
|
||||
if (!this._isInTranslatableSection && !this._inIcu) {
|
||||
if (i18nAttr) {
|
||||
// explicit translation
|
||||
if (i18nAttr || isTopLevelImplicit) {
|
||||
this._inI18nNode = true;
|
||||
const message = this._addMessage(el.children, i18nAttr.value);
|
||||
childNodes = this._translateMessage(el, message);
|
||||
} else if (isTopLevelImplicit) {
|
||||
// implicit translation
|
||||
this._inI18nNode = true;
|
||||
const message = this._addMessage(el.children);
|
||||
childNodes = this._translateMessage(el, message);
|
||||
const message = this._addMessage(el.children, i18nMeta);
|
||||
translatedChildNodes = this._translateMessage(el, message);
|
||||
}
|
||||
|
||||
if (this._mode == _VisitorMode.Extract) {
|
||||
const isTranslatable = i18nAttr || isTopLevelImplicit;
|
||||
if (isTranslatable) {
|
||||
this._openTranslatableSection(el);
|
||||
}
|
||||
if (isTranslatable) this._openTranslatableSection(el);
|
||||
html.visitAll(this, el.children);
|
||||
if (isTranslatable) {
|
||||
this._closeTranslatableSection(el, el.children);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._mode === _VisitorMode.Merge && !i18nAttr && !isTopLevelImplicit) {
|
||||
childNodes = [];
|
||||
el.children.forEach(child => {
|
||||
const visited = child.visit(this, context);
|
||||
if (visited && !this._isInTranslatableSection) {
|
||||
// Do not add the children from translatable sections (= i18n blocks here)
|
||||
// They will be added when the section is close (i.e. on `<!-- /i18n -->`)
|
||||
childNodes = childNodes.concat(visited);
|
||||
}
|
||||
});
|
||||
if (isTranslatable) this._closeTranslatableSection(el, el.children);
|
||||
}
|
||||
} else {
|
||||
if (i18nAttr || isTopLevelImplicit) {
|
||||
|
@ -265,19 +248,18 @@ class _Visitor implements html.Visitor {
|
|||
// Descend into child nodes for extraction
|
||||
html.visitAll(this, el.children);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._mode == _VisitorMode.Merge) {
|
||||
// Translate attributes in ICU messages
|
||||
childNodes = [];
|
||||
el.children.forEach(child => {
|
||||
const visited = child.visit(this, context);
|
||||
if (visited && !this._isInTranslatableSection) {
|
||||
// Do not add the children from translatable sections (= i18n blocks here)
|
||||
// They will be added when the section is close (i.e. on `<!-- /i18n -->`)
|
||||
childNodes = childNodes.concat(visited);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this._mode === _VisitorMode.Merge) {
|
||||
const visitNodes = translatedChildNodes || el.children;
|
||||
visitNodes.forEach(child => {
|
||||
const visited = child.visit(this, context);
|
||||
if (visited && !this._isInTranslatableSection) {
|
||||
// Do not add the children from translatable sections (= i18n blocks here)
|
||||
// They will be added later in this loop when the block closes (i.e. on `<!-- /i18n -->`)
|
||||
childNodes = childNodes.concat(visited);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this._visitAttributesOf(el);
|
||||
|
@ -287,7 +269,6 @@ class _Visitor implements html.Visitor {
|
|||
this._inImplicitNode = wasInImplicitNode;
|
||||
|
||||
if (this._mode === _VisitorMode.Merge) {
|
||||
// There are no childNodes in translatable sections - those nodes will be replace anyway
|
||||
const translatedAttrs = this._translateAttributes(el);
|
||||
return new html.Element(
|
||||
el.name, translatedAttrs, childNodes, el.sourceSpan, el.startSourceSpan,
|
||||
|
@ -434,7 +415,7 @@ class _Visitor implements html.Visitor {
|
|||
|
||||
/**
|
||||
* A translatable section could be:
|
||||
* - a translatable element,
|
||||
* - the content of translatable element,
|
||||
* - nodes between `<!-- i18n -->` and `<!-- /i18n -->` comments
|
||||
*/
|
||||
private get _isInTranslatableSection(): boolean {
|
||||
|
|
|
@ -106,6 +106,8 @@ export function main() {
|
|||
.toBe('<div id="i18n-13" title="dans une section traductible"></div>');
|
||||
expectHtml(el, '#i18n-15').toMatch(/ca <b>devrait<\/b> marcher/);
|
||||
expectHtml(el, '#i18n-16').toMatch(/avec un ID explicite/);
|
||||
expectHtml(el, '#i18n-18')
|
||||
.toEqual('<div id="i18n-18">FOO<a title="dans une section traductible">BAR</a></div>');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -162,6 +164,7 @@ const XTB = `
|
|||
<translation id="i18n17">{VAR_PLURAL, plural, =0 {zero} =1 {un} =2 {deux} other {<ph
|
||||
name="START_BOLD_TEXT"><ex><b></ex></ph>beaucoup<ph name="CLOSE_BOLD_TEXT"><ex></b></ex></ph>} }</translation>
|
||||
<translation id="4085484936881858615">{VAR_PLURAL, plural, =0 {Pas de réponse} =1 {une réponse} other {<ph name="INTERPOLATION"><ex>INTERPOLATION</ex></ph> réponse} }</translation>
|
||||
<translation id="4035252431381981115">FOO<ph name="START_LINK"><ex><a></ex></ph>BAR<ph name="CLOSE_LINK"><ex></a></ex></ph></translation>
|
||||
</translationbundle>`;
|
||||
|
||||
const XMB = ` <msg id="615790887472569365">i18n attribute on tags</msg>
|
||||
|
@ -187,7 +190,8 @@ const XMB = ` <msg id="615790887472569365">i18n attribute on tags</msg>
|
|||
<msg id="1491627405349178954">it <ph name="START_BOLD_TEXT"><ex><b></ex></ph>should<ph name="CLOSE_BOLD_TEXT"><ex></b></ex></ph> work</msg>
|
||||
<msg id="i18n16">with an explicit ID</msg>
|
||||
<msg id="i18n17">{VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {<ph name="START_BOLD_TEXT"><ex><b></ex></ph>many<ph name="CLOSE_BOLD_TEXT"><ex></b></ex></ph>} }</msg>
|
||||
<msg id="4085484936881858615" desc="desc">{VAR_PLURAL, plural, =0 {Found no results} =1 {Found one result} other {Found <ph name="INTERPOLATION"><ex>INTERPOLATION</ex></ph> results} }</msg>`;
|
||||
<msg id="4085484936881858615" desc="desc">{VAR_PLURAL, plural, =0 {Found no results} =1 {Found one result} other {Found <ph name="INTERPOLATION"><ex>INTERPOLATION</ex></ph> results} }</msg>
|
||||
<msg id="4035252431381981115">foo<ph name="START_LINK"><ex><a></ex></ph>bar<ph name="CLOSE_LINK"><ex></a></ex></ph></msg>`;
|
||||
|
||||
const HTML = `
|
||||
<div>
|
||||
|
@ -240,4 +244,6 @@ const HTML = `
|
|||
=1 {Found one result}
|
||||
other {Found {{response.getItemsList().length}} results}
|
||||
}</div>
|
||||
|
||||
<div i18n id="i18n-18">foo<a i18n-title title="in a translatable section">bar</a></div>
|
||||
`;
|
||||
|
|
Loading…
Reference in New Issue