From b3085e96c22636486c5d8dc7e09ec046e969a7ed Mon Sep 17 00:00:00 2001 From: Olivier Combe Date: Wed, 12 Jul 2017 16:27:53 +0200 Subject: [PATCH] feat(compiler): add representation of placeholders to xliff & xmb Closes #17345 --- .../compiler/src/i18n/serializers/xliff.ts | 15 +- packages/compiler/src/i18n/serializers/xmb.ts | 9 +- .../compiler/test/i18n/integration_common.ts | 1 + .../test/i18n/integration_xliff_spec.ts | 133 ++++++++++-------- .../test/i18n/integration_xmb_xtb_spec.ts | 44 +++--- .../test/i18n/serializers/xliff_spec.ts | 40 ++++-- .../test/i18n/serializers/xmb_spec.ts | 7 +- 7 files changed, 147 insertions(+), 102 deletions(-) diff --git a/packages/compiler/src/i18n/serializers/xliff.ts b/packages/compiler/src/i18n/serializers/xliff.ts index 5e054f468e..11a59441a6 100644 --- a/packages/compiler/src/i18n/serializers/xliff.ts +++ b/packages/compiler/src/i18n/serializers/xliff.ts @@ -139,23 +139,28 @@ class _WriteVisitor implements i18n.Visitor { visitTagPlaceholder(ph: i18n.TagPlaceholder, context?: any): xml.Node[] { const ctype = getCtypeForTag(ph.tag); - const startTagPh = new xml.Tag(_PLACEHOLDER_TAG, {id: ph.startName, ctype}); if (ph.isVoid) { // void tags have no children nor closing tags - return [startTagPh]; + return [new xml.Tag( + _PLACEHOLDER_TAG, {id: ph.startName, ctype, 'equiv-text': `<${ph.tag}/>`})]; } - const closeTagPh = new xml.Tag(_PLACEHOLDER_TAG, {id: ph.closeName, ctype}); + const startTagPh = + new xml.Tag(_PLACEHOLDER_TAG, {id: ph.startName, ctype, 'equiv-text': `<${ph.tag}>`}); + const closeTagPh = + new xml.Tag(_PLACEHOLDER_TAG, {id: ph.closeName, ctype, 'equiv-text': ``}); return [startTagPh, ...this.serialize(ph.children), closeTagPh]; } visitPlaceholder(ph: i18n.Placeholder, context?: any): xml.Node[] { - return [new xml.Tag(_PLACEHOLDER_TAG, {id: ph.name})]; + return [new xml.Tag(_PLACEHOLDER_TAG, {id: ph.name, 'equiv-text': `{{${ph.value}}}`})]; } visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): xml.Node[] { - return [new xml.Tag(_PLACEHOLDER_TAG, {id: ph.name})]; + const equivText = + `{${ph.value.expression}, ${ph.value.type}, ${Object.keys(ph.value.cases).map((value: string) => value + ' {...}').join(' ')}}`; + return [new xml.Tag(_PLACEHOLDER_TAG, {id: ph.name, 'equiv-text': equivText})]; } serialize(nodes: i18n.Node[]): xml.Node[] { diff --git a/packages/compiler/src/i18n/serializers/xmb.ts b/packages/compiler/src/i18n/serializers/xmb.ts index c9ee3eb52b..dde588f7aa 100644 --- a/packages/compiler/src/i18n/serializers/xmb.ts +++ b/packages/compiler/src/i18n/serializers/xmb.ts @@ -129,11 +129,16 @@ class _Visitor implements i18n.Visitor { } visitPlaceholder(ph: i18n.Placeholder, context?: any): xml.Node[] { - return [new xml.Tag(_PLACEHOLDER_TAG, {name: ph.name})]; + const exTag = new xml.Tag(_EXEMPLE_TAG, {}, [new xml.Text(`{{${ph.value}}}`)]); + return [new xml.Tag(_PLACEHOLDER_TAG, {name: ph.name}, [exTag])]; } visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): xml.Node[] { - return [new xml.Tag(_PLACEHOLDER_TAG, {name: ph.name})]; + 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])]; } serialize(nodes: i18n.Node[]): xml.Node[] { diff --git a/packages/compiler/test/i18n/integration_common.ts b/packages/compiler/test/i18n/integration_common.ts index bb612e5783..b2abdb8d0d 100644 --- a/packages/compiler/test/i18n/integration_common.ts +++ b/packages/compiler/test/i18n/integration_common.ts @@ -113,6 +113,7 @@ export const HTML = `

with placeholders

with placeholders

+
with
nested
placeholders

diff --git a/packages/compiler/test/i18n/integration_xliff_spec.ts b/packages/compiler/test/i18n/integration_xliff_spec.ts index 6637224a7e..1bcc2f0cc6 100644 --- a/packages/compiler/test/i18n/integration_xliff_spec.ts +++ b/packages/compiler/test/i18n/integration_xliff_spec.ts @@ -70,9 +70,17 @@ const XLIFF_TOMERGE = ` different meaning - with placeholders + with placeholders avec des espaces réservés + + with nested placeholders + with nested placeholders + + file.ts + 11 + + on not translatable node sur des balises non traductibles @@ -82,12 +90,12 @@ const XLIFF_TOMERGE = ` sur des balises traductibles - {VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {many} } + {VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {many} } {VAR_PLURAL, plural, =0 {zero} =1 {un} =2 {deux} other {beaucoup} } - + @@ -97,7 +105,7 @@ const XLIFF_TOMERGE = ` - + @@ -106,15 +114,15 @@ const XLIFF_TOMERGE = ` {VAR_SELECT, select, m {homme} f {femme} } - + - sex = + sex = sexe = - + @@ -123,9 +131,9 @@ const XLIFF_TOMERGE = ` - Markers in html comments - - + Markers in html comments + + Balises dans les commentaires html @@ -134,7 +142,7 @@ const XLIFF_TOMERGE = ` - it should work + it should work ca devrait marcher @@ -142,20 +150,20 @@ const XLIFF_TOMERGE = ` avec un ID explicite - {VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {many} } + {VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {many} } {VAR_PLURAL, plural, =0 {zero} =1 {un} =2 {deux} other {beaucoup} } - {VAR_PLURAL, plural, =0 {Found no results} =1 {Found one result} other {Found results} } + {VAR_PLURAL, plural, =0 {Found no results} =1 {Found one result} other {Found results} } {VAR_PLURAL, plural, =0 {Pas de réponse} =1 {une réponse} other {Found réponse} } desc - foobar + foobar FOOBAR - + `; @@ -183,7 +191,7 @@ const XLIFF_EXTRACTED = ` different meaning - with placeholders + with placeholders file.ts 9 @@ -193,146 +201,153 @@ const XLIFF_EXTRACTED = ` 10 + + with nested placeholders + + file.ts + 11 + + on not translatable node file.ts - 13 + 14 on translatable node file.ts - 14 + 15 - {VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {many} } + {VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {many} } file.ts - 19 + 20 file.ts - 36 + 37 - + file.ts - 21 + 22 {VAR_SELECT, select, 0 {other} m {male} f {female} } file.ts - 22 + 23 - + file.ts - 24 + 25 {VAR_SELECT, select, m {male} f {female} } file.ts - 25 + 26 - - - file.ts - 28 - - - - sex = + file.ts 29 - - + + sex = file.ts 30 + + + + file.ts + 31 + + in a translatable section file.ts - 35 + 36 file.ts - 53 + 54 - Markers in html comments - - + Markers in html comments + + file.ts - 33 + 34 - it should work + it should work file.ts - 39 + 40 with an explicit ID - - file.ts - 41 - - - - {VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {many} } file.ts 42 - - {VAR_PLURAL, plural, =0 {Found no results} =1 {Found one result} other {Found results} } + + {VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {many} } file.ts - 45 + 43 + + + + {VAR_PLURAL, plural, =0 {Found no results} =1 {Found one result} other {Found results} } + + file.ts + 46 desc - foobar + foobar file.ts - 53 + 54 - + file.ts - 55 + 56 `; diff --git a/packages/compiler/test/i18n/integration_xmb_xtb_spec.ts b/packages/compiler/test/i18n/integration_xmb_xtb_spec.ts index 679a22e218..ebd7c324f7 100644 --- a/packages/compiler/test/i18n/integration_xmb_xtb_spec.ts +++ b/packages/compiler/test/i18n/integration_xmb_xtb_spec.ts @@ -61,6 +61,7 @@ const XTB = ` imbriqué imbriqué avec des espaces réservés + <div>avec <div>des espaces réservés</div> imbriqués</div> sur des balises non traductibles sur des balises traductibles {VAR_PLURAL, plural, =0 {zero} =1 {un} =2 {deux} other {beaucoup}} @@ -90,29 +91,30 @@ const XMB = `file.ts:3i18n attribu file.ts:5nested file.ts:7nested file.ts:9file.ts:10<i>with placeholders</i> - file.ts:13on not translatable node - file.ts:14on translatable node - file.ts:19file.ts:36{VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {<b>many</b>} } - file.ts:21,23 - ICU + file.ts:11<div>with <div>nested</div> placeholders</div> + file.ts:14on not translatable node + file.ts:15on translatable node + file.ts:20file.ts:37{VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {<b>many</b>} } + file.ts:22,24 + {sex, select, 0 {...} m {...} f {...}} - file.ts:22{VAR_SELECT, select, 0 {other} m {male} f {female} } - file.ts:24,26 - ICU + file.ts:23{VAR_SELECT, select, 0 {other} m {male} f {female} } + file.ts:25,27 + {sexB, select, m {...} f {...}} - file.ts:25{VAR_SELECT, select, m {male} f {female} } - file.ts:28INTERPOLATION - file.ts:29sex = INTERPOLATION - file.ts:30CUSTOM_NAME - file.ts:35file.ts:53in a translatable section - file.ts:33,37 + file.ts:26{VAR_SELECT, select, m {male} f {female} } + file.ts:29{{ "count = " + count }} + file.ts:30sex = {{ sex }} + file.ts:31{{ "custom name" //i18n(ph="CUSTOM_NAME") }} + file.ts:36file.ts:54in a translatable section + file.ts:34,38 <h1>Markers in html comments</h1> <div></div> - <div>ICU</div> + <div>{count, plural, =0 {...} =1 {...} =2 {...} other {...}}</div> - file.ts:39it <b>should</b> work - file.ts:41with an explicit ID - file.ts:42{VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {<b>many</b>} } - file.ts:45,51{VAR_PLURAL, plural, =0 {Found no results} =1 {Found one result} other {Found INTERPOLATION results} } - file.ts:53foo<a>bar</a> - file.ts:55MAP_NAME`; + file.ts:40it <b>should</b> work + file.ts:42with an explicit ID + file.ts:43{VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {<b>many</b>} } + file.ts:46,52{VAR_PLURAL, plural, =0 {Found no results} =1 {Found one result} other {Found {{response.getItemsList().length}} results} } + file.ts:54foo<a>bar</a> + file.ts:56{{ 'test' //i18n(ph="map name") }}`; diff --git a/packages/compiler/test/i18n/serializers/xliff_spec.ts b/packages/compiler/test/i18n/serializers/xliff_spec.ts index 1a1071abf1..c5f6a2c128 100644 --- a/packages/compiler/test/i18n/serializers/xliff_spec.ts +++ b/packages/compiler/test/i18n/serializers/xliff_spec.ts @@ -24,7 +24,7 @@ const HTML = `

foo


{ 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

`; @@ -41,14 +41,14 @@ const WRITE_XLIFF = `
- translatable element with placeholders + translatable element with placeholders file.ts 3 - {VAR_PLURAL, plural, =0 {test} } + {VAR_PLURAL, plural, =0 {test} } file.ts 4 @@ -84,7 +84,7 @@ const WRITE_XLIFF = ` - + file.ts 9 @@ -92,14 +92,21 @@ const WRITE_XLIFF = ` ph names - {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {deeply nested} } } } + {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {deeply nested} } } } file.ts 10 - - {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {deeply nested} } } } + + Test: + + file.ts + 11 + + + + {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {deeply nested} } } =other {a lot} } file.ts 11 @@ -192,9 +199,17 @@ const LOAD_XLIFF = ` {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {deeply nested} } } } {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {profondément imbriqué} } } } - - {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {deeply nested} } } } - {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {profondément imbriqué} } } } + + Test: + Test: + + file.ts + 11 + + + + {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {deeply nested} } } =other {a lot} } + {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {profondément imbriqué} } } =other {beaucoup} } multi @@ -253,9 +268,10 @@ export function main(): void { 'empty target': '', 'baz': '{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[, profondément imbriqué, ]}}, ]}}', - '0e16a673a5a7a135c9f7b957ec2c5c6f6ee6e2c4': + '52ffa620dcd76247a56d5331f34e73f340a43cdb': 'Test: ', + '1503afd0ccc20ff01d5e2266a9157b7b342ba494': '{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[, profondément imbriqué, ]}}, ]}}', + ' name="START_PARAGRAPH"/>, profondément imbriqué, ]}}, ]}, =other {[beaucoup]}}', 'fcfa109b0e152d4c217dbc02530be0bcb8123ad1': `multi lignes` }); diff --git a/packages/compiler/test/i18n/serializers/xmb_spec.ts b/packages/compiler/test/i18n/serializers/xmb_spec.ts index 58084111b4..a65678e997 100644 --- a/packages/compiler/test/i18n/serializers/xmb_spec.ts +++ b/packages/compiler/test/i18n/serializers/xmb_spec.ts @@ -21,7 +21,7 @@ export function main(): void {

foo

foo

{ 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

`; @@ -48,13 +48,14 @@ lines

`; ]> - file.ts:3translatable element <b>with placeholders</b> INTERPOLATION + file.ts:3translatable element <b>with placeholders</b> {{ interpolation}} file.ts:4{VAR_PLURAL, plural, =0 {<p>test</p>} } file.ts:5foo file.ts:6foo file.ts:7foo file.ts:8{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<p>deeply nested</p>} } } } - file.ts:9{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<p>deeply nested</p>} } } } + file.ts:9Test: { count, plural, =0 {...} =other {...}} + file.ts:9{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<p>deeply nested</p>} } } =other {a lot} } file.ts:10,11multi lines