Skip to content
Permalink
Browse files

fix(ivy): i18n - correctly parse XLIFF placeholders (#34155)

The ViewEngine translation extractor does not convert `-` to `_` for
placeholders that represent custom elements. For example `<app-component>`
gets converted to placeholders like `START_TAG_APP-COMPONENT`.

In `$localize` placeholders are expected to be snake-case, not kebab-case.
So we must normalize them when parsing a translation file that might have
been created via the View Engine translation extractor.

The `$localize` extraction code will normalize these placeholders when
creating translation files in the first place.

Fixes #34151

PR Close #34155
  • Loading branch information
petebacondarwin authored and mhevery committed Nov 29, 2019
1 parent 69d27f3 commit d5a48b2cc0f77921b4e2e196a369b2ec9e451e41
@@ -35,7 +35,9 @@ export class TargetMessageRenderer implements MessageRenderer<ɵParsedTranslatio
this.icuDepth--;
this.text('}');
}
private normalizePlaceholderName(name: string) { return name.replace(/-/g, '_'); }
private renderPlaceholder(name: string) {
name = this.normalizePlaceholderName(name);
if (this.icuDepth > 0) {
this.text(`{${name}}`);
} else {
@@ -88,7 +88,7 @@ describe('Xliff1TranslationParser', () => {
* Source HTML:
*
* ```
* <div i18n>translatable element <b>>with placeholders</b> {{ interpolation}}</div>
* <div i18n>translatable element <b>with placeholders</b> {{ interpolation}}</div>
* ```
*/
const XLIFF = `
@@ -117,6 +117,38 @@ describe('Xliff1TranslationParser', () => {
['INTERPOLATION', 'START_BOLD_TEXT', 'CLOSE_BOLD_TEXT']));
});

it('should extract translations with placeholders containing hyphens', () => {
/**
* Source HTML:
*
* ```
* <div i18n><app-my-component></app-my-component> Welcome</div>
* ```
*/
const XLIFF = `
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" target-language="fr" datatype="plaintext" original="ng2.template">
<body>
<trans-unit id="2877147807876214810" datatype="html">
<source><x id="START_TAG_APP-MY-COMPONENT" ctype="x-app-my-component" equiv-text="&lt;app-my-component&gt;"/><x id="CLOSE_TAG_APP-MY-COMPONENT" ctype="x-app-my-component" equiv-text="&lt;/app-my-component&gt;"/> Welcome</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">1</context>
</context-group>
<target><x id="START_TAG_APP-MY-COMPONENT" ctype="x-app-my-component" equiv-text="&lt;app-my-component&gt;"/><x id="CLOSE_TAG_APP-MY-COMPONENT" ctype="x-app-my-component" equiv-text="&lt;/app-my-component&gt;"/> Translate</target>
</trans-unit>
</body>
</file>
</xliff>`;
const parser = new Xliff1TranslationParser();
const result = parser.parse('/some/file.xlf', XLIFF);
const id =
ɵcomputeMsgId('{$START_TAG_APP_MY_COMPONENT}{$CLOSE_TAG_APP_MY_COMPONENT} Welcome');
expect(result.translations[id]).toEqual(ɵmakeParsedTranslation(['', '', ' Translate'], [
'START_TAG_APP_MY_COMPONENT', 'CLOSE_TAG_APP_MY_COMPONENT'
]));
});

it('should extract translations with simple ICU expressions', () => {
/**
* Source HTML:

0 comments on commit d5a48b2

Please sign in to comment.
You can’t perform that action at this time.