From 38ec05f53375dc4cc4bf89cecf288eec8b5f4bd5 Mon Sep 17 00:00:00 2001
From: Olivier Combe
Date: Fri, 21 Jul 2017 19:49:45 +0200
Subject: [PATCH] fix(compiler): add equiv & disp attributes to Xliff2 ICU
placeholders (#18283)
Fixes #17344
PR Close #18283
---
.../compiler/src/i18n/serializers/xliff2.ts | 9 +-
.../test/i18n/integration_xliff2_spec.ts | 416 ++++++++++++++++++
.../test/i18n/serializers/xliff2_spec.ts | 34 +-
3 files changed, 449 insertions(+), 10 deletions(-)
create mode 100644 packages/compiler/test/i18n/integration_xliff2_spec.ts
diff --git a/packages/compiler/src/i18n/serializers/xliff2.ts b/packages/compiler/src/i18n/serializers/xliff2.ts
index 6db2de5d9c..ea754b34fc 100644
--- a/packages/compiler/src/i18n/serializers/xliff2.ts
+++ b/packages/compiler/src/i18n/serializers/xliff2.ts
@@ -165,15 +165,20 @@ class _WriteVisitor implements i18n.Visitor {
}
visitPlaceholder(ph: i18n.Placeholder, context?: any): xml.Node[] {
+ const idStr = (this._nextPlaceholderId++).toString();
return [new xml.Tag(_PLACEHOLDER_TAG, {
- id: (this._nextPlaceholderId++).toString(),
+ id: idStr,
equiv: ph.name,
disp: `{{${ph.value}}}`,
})];
}
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): xml.Node[] {
- return [new xml.Tag(_PLACEHOLDER_TAG, {id: (this._nextPlaceholderId++).toString()})];
+ const cases = Object.keys(ph.value.cases).map((value: string) => value + ' {...}').join(' ');
+ const idStr = (this._nextPlaceholderId++).toString();
+ return [new xml.Tag(
+ _PLACEHOLDER_TAG,
+ {id: idStr, equiv: ph.name, disp: `{${ph.value.expression}, ${ph.value.type}, ${cases}}`})];
}
serialize(nodes: i18n.Node[]): xml.Node[] {
diff --git a/packages/compiler/test/i18n/integration_xliff2_spec.ts b/packages/compiler/test/i18n/integration_xliff2_spec.ts
new file mode 100644
index 0000000000..3594db225a
--- /dev/null
+++ b/packages/compiler/test/i18n/integration_xliff2_spec.ts
@@ -0,0 +1,416 @@
+/**
+ * @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 {Xliff2} from '@angular/compiler/src/i18n/serializers/xliff2';
+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 2.0 integration spec', () => {
+
+ beforeEach(async(() => {
+ TestBed.configureCompiler({
+ providers: [
+ {provide: ResourceLoader, useClass: SpyResourceLoader},
+ {provide: NgLocalization, useClass: FrLocalization},
+ {provide: TRANSLATIONS, useValue: XLIFF2_TOMERGE},
+ {provide: TRANSLATIONS_FORMAT, useValue: 'xlf2'},
+ ]
+ });
+
+ TestBed.configureTestingModule({declarations: [I18nComponent]});
+ }));
+
+ it('should extract from templates', () => {
+ const catalog = new MessageBundle(new HtmlParser, [], {});
+ const serializer = new Xliff2();
+ catalog.updateFromTemplate(HTML, 'file.ts', DEFAULT_INTERPOLATION_CONFIG);
+
+ expect(catalog.write(serializer)).toContain(XLIFF2_EXTRACTED);
+ });
+
+ it('should translate templates', () => {
+ const tb: ComponentFixture =
+ TestBed.overrideTemplate(I18nComponent, HTML).createComponent(I18nComponent);
+ const cmp: I18nComponent = tb.componentInstance;
+ const el: DebugElement = tb.debugElement;
+
+ validateHtml(tb, cmp, el);
+ });
+ });
+}
+
+const XLIFF2_TOMERGE = `
+
+
+
+ attributs i18n sur les balises
+
+
+
+
+
+ imbriqué
+
+
+
+
+
+ imbriqué
+
+
+
+
+
+ avec des espaces réservés
+
+
+
+
+ file.ts:11
+
+
+
+ avec espaces réservés imbriqués
+
+
+
+
+
+ sur des balises non traductibles
+
+
+
+
+
+ sur des balises traductibles
+
+
+
+
+
+ {VAR_PLURAL, plural, =0 {zero} =1 {un} =2 {deux} other {beaucoup} }
+
+
+
+
+
+
+
+
+
+
+ file.ts:23
+
+
+
+ {VAR_SELECT, select, 0 {autre} m {homme} f {femme} }
+
+
+
+
+ file.ts:25,27
+
+
+
+
+
+
+
+
+
+ {VAR_SELECT, select, m {homme} f {femme} }
+
+
+
+
+
+
+
+
+
+
+
+ sexe =
+
+
+
+
+
+
+
+
+
+
+
+ dans une section traductible
+
+
+
+
+
+
+ Balises dans les commentaires html
+
+
+
+
+
+
+
+
+ ca devrait marcher
+
+
+
+
+
+ avec un ID explicite
+
+
+
+
+
+ {VAR_PLURAL, plural, =0 {zero} =1 {un} =2 {deux} other {beaucoup} }
+
+
+
+
+
+ {VAR_PLURAL, plural, =0 {Pas de réponse} =1 {une réponse} other {Trouvé réponses} }
+
+
+
+
+
+ FOOBAR
+
+
+
+
+
+
+
+ `;
+
+const XLIFF2_EXTRACTED = `
+
+
+ file.ts:3
+
+
+
+
+
+
+
+ file.ts:5
+
+
+
+
+
+
+
+ different meaning
+ file.ts:7
+
+
+
+
+
+
+
+ file.ts:9
+ file.ts:10
+
+
+
+
+
+
+
+ file.ts:11
+
+
+
+
+
+
+
+ file.ts:14
+
+
+
+
+
+
+
+ file.ts:15
+
+
+
+
+
+
+
+ file.ts:20
+ file.ts:37
+
+
+
+
+
+
+
+ file.ts:22,24
+
+
+
+
+
+
+
+ file.ts:23
+
+
+
+
+
+
+
+ file.ts:25,27
+
+
+
+
+
+
+
+ file.ts:26
+
+
+
+
+
+
+
+ file.ts:29
+
+
+
+
+
+
+
+ file.ts:30
+
+
+
+
+
+
+
+ file.ts:31
+
+
+
+
+
+
+
+ file.ts:36
+ file.ts:54
+
+
+
+
+
+
+
+ file.ts:34,38
+
+
+
+
+
+
+
+ file.ts:40
+
+
+
+
+
+
+
+ file.ts:42
+
+
+
+
+
+
+
+ file.ts:43
+
+
+
+
+
+
+
+ desc
+ file.ts:46,52
+
+
+
+
+
+
+
+ file.ts:54
+
+
+
+
+
+
+
+ file.ts:56
+
+
+
+
+ `;
diff --git a/packages/compiler/test/i18n/serializers/xliff2_spec.ts b/packages/compiler/test/i18n/serializers/xliff2_spec.ts
index 5c10135c92..2ed9c998ab 100644
--- a/packages/compiler/test/i18n/serializers/xliff2_spec.ts
+++ b/packages/compiler/test/i18n/serializers/xliff2_spec.ts
@@ -23,7 +23,7 @@ const HTML = `
hello
{ count, plural, =0 { { sex, select, other {
deeply nested
}} }}
-{ count, plural, =0 { { sex, select, other {
deeply nested
}} }}
+Test: { count, plural, =0 { { sex, select, other {
deeply nested
}} } =other {a lot}}
multi
lines
`;
@@ -100,12 +100,20 @@ const WRITE_XLIFF = `
-
+
file.ts:10
-
+
+
+
+
+
+ file.ts:10
+
+
+
@@ -201,13 +209,22 @@ const LOAD_XLIFF = `
{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {profondément imbriqué} } } }
-
+
file.ts:10
-
- {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {profondément imbriqué} } } }
+
+ Test:
+
+
+
+
+ file.ts:10
+
+
+
+ {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {profondément imbriqué} } } =other {beaucoup} }
@@ -268,8 +285,9 @@ export function main(): void {
'6536355551500405293': ' olleh',
'baz':
'{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[, profondément imbriqué, ]}}, ]}}',
- '2015957479576096115': '{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[, profondément imbriqué, ]}}, ]}}',
+ '6997386649824869937': 'Test: ',
+ '5229984852258993423': '{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[, profondément imbriqué, ]}}, ]}, =other {[beaucoup]}}',
'2340165783990709777': `multi
lignes`
});