feat(compiler): add "original" placeholder value on extracted XMB (#25079)
Update XMB placeholders(<ph>) to include the original value on top of an example. Placeholders can by definition have one example(<ex>) tag and a text node. The text node is used by TC as the "original" value from the placeholder, while the example should represent a dummy value. For example: <ph name="PET"><ex>Gopher</ex>{{ petName }}</ph>. This change makes sure that we have the original text, but it *DOES NOT* make sure that the example is correct. The example has the same wrong behavior of showing the interpolation text rather than a useful example. No breaking changes, but tools that depend on the previous behavior and don't consider the full XMB definition may fail to parse the XMB. Fixes b/72565847 PR Close #25079
This commit is contained in:

committed by
Igor Minar

parent
24789e9ad9
commit
e99d860393
@ -15,7 +15,7 @@ import * as xml from './xml_helper';
|
||||
const _MESSAGES_TAG = 'messagebundle';
|
||||
const _MESSAGE_TAG = 'msg';
|
||||
const _PLACEHOLDER_TAG = 'ph';
|
||||
const _EXEMPLE_TAG = 'ex';
|
||||
const _EXAMPLE_TAG = 'ex';
|
||||
const _SOURCE_TAG = 'source';
|
||||
|
||||
const _DOCTYPE = `<!ELEMENT messagebundle (msg)*>
|
||||
@ -115,30 +115,45 @@ class _Visitor implements i18n.Visitor {
|
||||
}
|
||||
|
||||
visitTagPlaceholder(ph: i18n.TagPlaceholder, context?: any): xml.Node[] {
|
||||
const startEx = new xml.Tag(_EXEMPLE_TAG, {}, [new xml.Text(`<${ph.tag}>`)]);
|
||||
const startTagPh = new xml.Tag(_PLACEHOLDER_TAG, {name: ph.startName}, [startEx]);
|
||||
const startTagAsText = new xml.Text(`<${ph.tag}>`);
|
||||
const startEx = new xml.Tag(_EXAMPLE_TAG, {}, [startTagAsText]);
|
||||
// TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
|
||||
const startTagPh =
|
||||
new xml.Tag(_PLACEHOLDER_TAG, {name: ph.startName}, [startEx, startTagAsText]);
|
||||
if (ph.isVoid) {
|
||||
// void tags have no children nor closing tags
|
||||
return [startTagPh];
|
||||
}
|
||||
|
||||
const closeEx = new xml.Tag(_EXEMPLE_TAG, {}, [new xml.Text(`</${ph.tag}>`)]);
|
||||
const closeTagPh = new xml.Tag(_PLACEHOLDER_TAG, {name: ph.closeName}, [closeEx]);
|
||||
const closeTagAsText = new xml.Text(`</${ph.tag}>`);
|
||||
const closeEx = new xml.Tag(_EXAMPLE_TAG, {}, [closeTagAsText]);
|
||||
// TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
|
||||
const closeTagPh =
|
||||
new xml.Tag(_PLACEHOLDER_TAG, {name: ph.closeName}, [closeEx, closeTagAsText]);
|
||||
|
||||
return [startTagPh, ...this.serialize(ph.children), closeTagPh];
|
||||
}
|
||||
|
||||
visitPlaceholder(ph: i18n.Placeholder, context?: any): xml.Node[] {
|
||||
const exTag = new xml.Tag(_EXEMPLE_TAG, {}, [new xml.Text(`{{${ph.value}}}`)]);
|
||||
return [new xml.Tag(_PLACEHOLDER_TAG, {name: ph.name}, [exTag])];
|
||||
const interpolationAsText = new xml.Text(`{{${ph.value}}}`);
|
||||
// Example tag needs to be not-empty for TC.
|
||||
const exTag = new xml.Tag(_EXAMPLE_TAG, {}, [interpolationAsText]);
|
||||
return [
|
||||
// TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
|
||||
new xml.Tag(_PLACEHOLDER_TAG, {name: ph.name}, [exTag, interpolationAsText])
|
||||
];
|
||||
}
|
||||
|
||||
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): xml.Node[] {
|
||||
const exTag = new xml.Tag(_EXEMPLE_TAG, {}, [
|
||||
new xml.Text(
|
||||
`{${ph.value.expression}, ${ph.value.type}, ${Object.keys(ph.value.cases).map((value: string) => value + ' {...}').join(' ')}}`)
|
||||
]);
|
||||
return [new xml.Tag(_PLACEHOLDER_TAG, {name: ph.name}, [exTag])];
|
||||
const icuExpression = ph.value.expression;
|
||||
const icuType = ph.value.type;
|
||||
const icuCases = Object.keys(ph.value.cases).map((value: string) => value + ' {...}').join(' ');
|
||||
const icuAsText = new xml.Text(`{${icuExpression}, ${icuType}, ${icuCases}}`);
|
||||
const exTag = new xml.Tag(_EXAMPLE_TAG, {}, [icuAsText]);
|
||||
return [
|
||||
// TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
|
||||
new xml.Tag(_PLACEHOLDER_TAG, {name: ph.name}, [exTag, icuAsText])
|
||||
];
|
||||
}
|
||||
|
||||
serialize(nodes: i18n.Node[]): xml.Node[] {
|
||||
@ -161,7 +176,7 @@ class ExampleVisitor implements xml.IVisitor {
|
||||
if (tag.name === _PLACEHOLDER_TAG) {
|
||||
if (!tag.children || tag.children.length == 0) {
|
||||
const exText = new xml.Text(tag.attrs['name'] || '...');
|
||||
tag.children = [new xml.Tag(_EXEMPLE_TAG, {}, [exText])];
|
||||
tag.children = [new xml.Tag(_EXAMPLE_TAG, {}, [exText])];
|
||||
}
|
||||
} else if (tag.children) {
|
||||
tag.children.forEach(node => node.visit(this));
|
||||
|
Reference in New Issue
Block a user