From 56c361ff6adee8c9d03e495f04eaab8a9d4cc1f4 Mon Sep 17 00:00:00 2001
From: maxime-allex
Date: Tue, 6 Dec 2016 15:04:59 +0100
Subject: [PATCH] test(compiler): test i18n explicit id
closes #13272
---
.../@angular/compiler/src/i18n/i18n_parser.ts | 3 +-
.../compiler/test/i18n/digest_spec.ts | 15 +-
.../test/i18n/extractor_merger_spec.ts | 135 ++++++++++++------
.../compiler/test/i18n/integration_spec.ts | 12 +-
.../test/i18n/serializers/xliff_spec.ts | 24 ++++
.../test/i18n/serializers/xmb_spec.ts | 6 +
.../test/i18n/translation_bundle_spec.ts | 18 +--
7 files changed, 154 insertions(+), 59 deletions(-)
diff --git a/modules/@angular/compiler/src/i18n/i18n_parser.ts b/modules/@angular/compiler/src/i18n/i18n_parser.ts
index e3af025a50..cac8435660 100644
--- a/modules/@angular/compiler/src/i18n/i18n_parser.ts
+++ b/modules/@angular/compiler/src/i18n/i18n_parser.ts
@@ -40,7 +40,8 @@ class _I18nVisitor implements html.Visitor {
private _expressionParser: ExpressionParser,
private _interpolationConfig: InterpolationConfig) {}
- public toI18nMessage(nodes: html.Node[], meaning: string, description: string, id: string): i18n.Message {
+ public toI18nMessage(nodes: html.Node[], meaning: string, description: string, id: string):
+ i18n.Message {
this._isIcu = nodes.length == 1 && nodes[0] instanceof html.Expansion;
this._icuDepth = 0;
this._placeholderRegistry = new PlaceholderRegistry();
diff --git a/modules/@angular/compiler/test/i18n/digest_spec.ts b/modules/@angular/compiler/test/i18n/digest_spec.ts
index 07b7bbe390..7297f6cc76 100644
--- a/modules/@angular/compiler/test/i18n/digest_spec.ts
+++ b/modules/@angular/compiler/test/i18n/digest_spec.ts
@@ -6,10 +6,23 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {computeMsgId, sha1} from '../../src/i18n/digest';
+import {computeMsgId, digest, sha1} from '../../src/i18n/digest';
export function main(): void {
describe('digest', () => {
+ describe('digest', () => {
+ it('must return the ID if it\'s explicit', () => {
+ expect(digest({
+ id: 'i',
+ nodes: [],
+ placeholders: {},
+ placeholderToMessage: {},
+ meaning: '',
+ description: '',
+ })).toEqual('i');
+ });
+ });
+
describe('sha1', () => {
it('should work on empty strings',
() => { expect(sha1('')).toEqual('da39a3ee5e6b4b0d3255bfef95601890afd80709'); });
diff --git a/modules/@angular/compiler/test/i18n/extractor_merger_spec.ts b/modules/@angular/compiler/test/i18n/extractor_merger_spec.ts
index c175425507..0e88c7359d 100644
--- a/modules/@angular/compiler/test/i18n/extractor_merger_spec.ts
+++ b/modules/@angular/compiler/test/i18n/extractor_merger_spec.ts
@@ -20,7 +20,10 @@ export function main() {
describe('elements', () => {
it('should extract from elements', () => {
expect(extract('textnested
')).toEqual([
- [['text', 'nested '], 'm', 'd|e'],
+ [
+ ['text', 'nested '], 'm', 'd|e',
+ ''
+ ],
]);
});
@@ -29,11 +32,45 @@ export function main() {
extract(
'nested
'))
.toEqual([
- [['nested '], 'm1', 'd1'],
- [['single child'], 'm2', 'd2'],
+ [['nested '], 'm1', 'd1', ''],
+ [['single child'], 'm2', 'd2', ''],
]);
});
+ it('should extract from attributes with id', () => {
+ expect(
+ extract(
+ 'nested
'))
+ .toEqual([
+ [
+ ['nested '], 'm1', 'd1',
+ 'i1'
+ ],
+ [['single child'], 'm2', 'd2', 'i2'],
+ ]);
+ });
+
+ it('should extract from attributes without meaning and with id', () => {
+ expect(
+ extract(
+ 'nested
'))
+ .toEqual([
+ [['nested '], '', 'd1', 'i1'],
+ [['single child'], '', 'd2', 'i2'],
+ ]);
+ });
+
+ it('should extract from attributes with id only', () => {
+ expect(
+ extract(
+ 'nested
'))
+ .toEqual([
+ [['nested '], '', '', 'i1'],
+ [['single child'], '', '', 'i2'],
+ ]);
+ });
+
+
it('should extract from ICU messages', () => {
expect(
extract(
@@ -43,10 +80,10 @@ export function main() {
[
'{count, plural, =0 {[ ]}}'
],
- 'm', 'd'
+ 'm', 'd', ''
],
- [['title'], '', ''],
- [['desc'], '', ''],
+ [['title'], '', '', ''],
+ [['desc'], '', '', ''],
]);
});
@@ -55,7 +92,7 @@ export function main() {
it('should ignore implicit elements in translatable elements', () => {
expect(extract('', ['p'])).toEqual([
- [[' '], 'm', 'd']
+ [[' '], 'm', 'd', '']
]);
});
});
@@ -64,17 +101,19 @@ export function main() {
it('should extract from blocks', () => {
expect(extract(`message1
message2
- message3`))
+ message3
+ message4
+ message5`))
.toEqual([
- [['message1'], 'meaning1', 'desc1'],
- [['message2'], '', 'desc2'],
- [['message3'], '', ''],
+ [['message1'], 'meaning1', 'desc1', ''], [['message2'], '', 'desc2', ''],
+ [['message3'], '', '', ''], [['message4'], 'meaning4', 'desc4', 'id4'],
+ [['message5'], '', '', 'id5']
]);
});
it('should ignore implicit elements in blocks', () => {
expect(extract('
', ['p'])).toEqual([
- [[' '], 'm', 'd']
+ [[' '], 'm', 'd', '']
]);
});
@@ -88,7 +127,7 @@ export function main() {
[
'{count, plural, =0 {[html ]}}'
],
- '', ''
+ '', '', ''
],
[
[
@@ -98,15 +137,15 @@ export function main() {
' name="START_TAG_SPAN">html]}}',
'[interp ]'
],
- '', ''
+ '', '', ''
],
]);
});
it('should ignore other comments', () => {
- expect(extract(`message1`))
+ expect(extract(`message1`))
.toEqual([
- [['message1'], 'meaning1', 'desc1'],
+ [['message1'], 'meaning1', 'desc1', 'id1'],
]);
});
@@ -118,34 +157,37 @@ export function main() {
it('should extract ICU messages from translatable elements', () => {
// single message when ICU is the only children
expect(extract('{count, plural, =0 {text}}
')).toEqual([
- [['{count, plural, =0 {[text]}}'], 'm', 'd'],
+ [['{count, plural, =0 {[text]}}'], 'm', 'd', ''],
]);
// single message when ICU is the only (implicit) children
expect(extract('{count, plural, =0 {text}}
', ['div'])).toEqual([
- [['{count, plural, =0 {[text]}}'], '', ''],
+ [['{count, plural, =0 {[text]}}'], '', '', ''],
]);
// one message for the element content and one message for the ICU
- expect(extract('before{count, plural, =0 {text}}after
')).toEqual([
- [['before', '{count, plural, =0 {[text]}} ', 'after'], 'm', 'd'],
- [['{count, plural, =0 {[text]}}'], '', ''],
+ expect(extract('before{count, plural, =0 {text}}after
')).toEqual([
+ [
+ ['before', '{count, plural, =0 {[text]}} ', 'after'], 'm', 'd',
+ 'i'
+ ],
+ [['{count, plural, =0 {[text]}}'], '', '', ''],
]);
});
it('should extract ICU messages from translatable block', () => {
// single message when ICU is the only children
expect(extract('{count, plural, =0 {text}}')).toEqual([
- [['{count, plural, =0 {[text]}}'], 'm', 'd'],
+ [['{count, plural, =0 {[text]}}'], 'm', 'd', ''],
]);
// one message for the block content and one message for the ICU
expect(extract('before{count, plural, =0 {text}}after'))
.toEqual([
- [['{count, plural, =0 {[text]}}'], '', ''],
+ [['{count, plural, =0 {[text]}}'], '', '', ''],
[
['before', '{count, plural, =0 {[text]}} ', 'after'], 'm',
- 'd'
+ 'd', ''
],
]);
});
@@ -156,20 +198,20 @@ export function main() {
it('should ignore nested ICU messages', () => {
expect(extract('{count, plural, =0 { {sex, select, male {m}} }}
'))
.toEqual([
- [['{count, plural, =0 {[{sex, select, male {[m]}}, ]}}'], 'm', 'd'],
+ [['{count, plural, =0 {[{sex, select, male {[m]}}, ]}}'], 'm', 'd', ''],
]);
});
it('should ignore implicit elements in non translatable ICU messages', () => {
- expect(
- extract(
- '{count, plural, =0 { {sex, select, male {
ignore
}} }}
',
- ['p']))
+ expect(extract(
+ '{count, plural, =0 { {sex, select, male {
ignore
}}' +
+ ' }}
',
+ ['p']))
.toEqual([[
[
'{count, plural, =0 {[{sex, select, male {[ignore ]}}, ]}}'
],
- 'm', 'd'
+ 'm', 'd', 'i'
]]);
});
@@ -181,46 +223,45 @@ export function main() {
describe('attributes', () => {
it('should extract from attributes outside of translatable sections', () => {
- expect(extract('
')).toEqual([
- [['msg'], 'm', 'd'],
+ expect(extract('
')).toEqual([
+ [['msg'], 'm', 'd', 'i'],
]);
});
it('should extract from attributes in translatable elements', () => {
- expect(extract('')).toEqual([
+ expect(extract('')).toEqual([
[
[' '],
- '', ''
+ '', '', ''
],
- [['msg'], 'm', 'd'],
+ [['msg'], 'm', 'd', 'i'],
]);
});
it('should extract from attributes in translatable blocks', () => {
expect(extract('
'))
.toEqual([
- [['msg'], 'm', 'd'],
+ [['msg'], 'm', 'd', ''],
[
[' '],
- '', ''
+ '', '', ''
],
]);
});
it('should extract from attributes in translatable ICUs', () => {
- expect(
- extract(
- '{count, plural, =0 {
}}'))
+ expect(extract(`{count, plural, =0 {
}}`))
.toEqual([
- [['msg'], 'm', 'd'],
+ [['msg'], 'm', 'd', 'i'],
[
[
'{count, plural, =0 {[ ]}}'
],
- '', ''
+ '', '', ''
],
]);
});
@@ -228,7 +269,7 @@ export function main() {
it('should extract from attributes in non translatable ICUs', () => {
expect(extract('{count, plural, =0 {
}}'))
.toEqual([
- [['msg'], 'm', 'd'],
+ [['msg'], 'm', 'd', ''],
]);
});
@@ -239,7 +280,7 @@ export function main() {
describe('implicit elements', () => {
it('should extract from implicit elements', () => {
expect(extract('bold italic ', ['b'])).toEqual([
- [['bold'], '', ''],
+ [['bold'], '', '', ''],
]);
});
@@ -251,7 +292,7 @@ export function main() {
}).not.toThrow();
expect(result).toEqual([
- [['outer', 'inner '], '', ''],
+ [['outer', 'inner '], '', '', ''],
]);
});
@@ -261,7 +302,7 @@ export function main() {
it('should extract implicit attributes', () => {
expect(extract('bold italic ', [], {'b': ['title']}))
.toEqual([
- [['bb'], '', ''],
+ [['bb'], '', '', ''],
]);
});
});
@@ -433,7 +474,7 @@ function extract(
// clang-format off
// https://github.com/angular/clang-format/issues/35
return result.messages.map(
- message => [serializeI18nNodes(message.nodes), message.meaning, message.description, ]) as [string[], string, string][];
+ message => [serializeI18nNodes(message.nodes), message.meaning, message.description, message.id]) as [string[], string, string][];
// clang-format on
}
diff --git a/modules/@angular/compiler/test/i18n/integration_spec.ts b/modules/@angular/compiler/test/i18n/integration_spec.ts
index ade32405dd..7823c42634 100644
--- a/modules/@angular/compiler/test/i18n/integration_spec.ts
+++ b/modules/@angular/compiler/test/i18n/integration_spec.ts
@@ -59,14 +59,17 @@ export function main() {
tb.detectChanges();
expect(el.query(By.css('#i18n-7')).nativeElement).toHaveText('un');
expect(el.query(By.css('#i18n-14')).nativeElement).toHaveText('un');
+ expect(el.query(By.css('#i18n-17')).nativeElement).toHaveText('un');
cmp.count = 2;
tb.detectChanges();
expect(el.query(By.css('#i18n-7')).nativeElement).toHaveText('deux');
expect(el.query(By.css('#i18n-14')).nativeElement).toHaveText('deux');
+ expect(el.query(By.css('#i18n-17')).nativeElement).toHaveText('deux');
cmp.count = 3;
tb.detectChanges();
expect(el.query(By.css('#i18n-7')).nativeElement).toHaveText('beaucoup');
expect(el.query(By.css('#i18n-14')).nativeElement).toHaveText('beaucoup');
+ expect(el.query(By.css('#i18n-17')).nativeElement).toHaveText('beaucoup');
cmp.sex = 'm';
cmp.sexB = 'f';
@@ -90,8 +93,8 @@ export function main() {
.toEqual('Balises dans les commentaires html ');
expectHtml(el, '#i18n-13')
.toBe('
');
-
expectHtml(el, '#i18n-15').toMatch(/ca devrait<\/b> marcher/);
+ expectHtml(el, '#i18n-16').toMatch(/avec un ID explicite/);
});
});
}
@@ -141,6 +144,8 @@ function expectHtml(el: DebugElement, cssSelector: string): any {
it should work
+with an explicit ID
+{count, plural, =0 {zero} =1 {one} =2 {two} other {many }}
`
})
class I18nComponent {
@@ -182,6 +187,9 @@ const XTB = `
ca devrait marcher
+ avec un ID explicite
+ {VAR_PLURAL, plural, =0 {zero} =1 {un} =2 {deux} other {<b> beaucoup</b> } }
`;
// unused, for reference only
@@ -210,5 +218,7 @@ const XMB = `
<div> </div>
it <b> should</b> work
+ with an explicit ID
+ {VAR_PLURAL, plural, =0 {zero} =1 {one} =2 {two} other {<b> many</b> } }
`;
diff --git a/modules/@angular/compiler/test/i18n/serializers/xliff_spec.ts b/modules/@angular/compiler/test/i18n/serializers/xliff_spec.ts
index 5c8f9af5a3..6d7b3fb7cf 100644
--- a/modules/@angular/compiler/test/i18n/serializers/xliff_spec.ts
+++ b/modules/@angular/compiler/test/i18n/serializers/xliff_spec.ts
@@ -18,6 +18,8 @@ const HTML = `
not translatable
translatable element with placeholders {{ interpolation}}
foo
+foo
+foo
`;
@@ -39,6 +41,16 @@ const WRITE_XLIFF = `
d
m
+
+ foo
+
+ d
+ m
+
+
+ foo
+
+
@@ -67,6 +79,16 @@ const LOAD_XLIFF = `
d
m
+
+ foo
+ toto
+ d
+ m
+
+
+ foo
+ tata
+
@@ -107,6 +129,8 @@ export function main(): void {
'ec1d033f2436133c14ab038286c4f5df4697484a':
' footnemele elbatalsnart sredlohecalp htiw ',
'db3e0a6a5a96481f60aec61d98c3eecddef5ac23': 'oof',
+ 'i': 'toto',
+ 'bar': 'tata',
'd7fa2d59aaedcaa5309f13028c59af8c85b8c49d':
' ',
});
diff --git a/modules/@angular/compiler/test/i18n/serializers/xmb_spec.ts b/modules/@angular/compiler/test/i18n/serializers/xmb_spec.ts
index 319370102e..ecfe0b1519 100644
--- a/modules/@angular/compiler/test/i18n/serializers/xmb_spec.ts
+++ b/modules/@angular/compiler/test/i18n/serializers/xmb_spec.ts
@@ -18,6 +18,9 @@ export function main(): void {
translatable element with placeholders {{ interpolation}}
{ count, plural, =0 {test
}}
foo
+foo
+foo
+{ count, plural, =0 { { sex, select, other {
deeply nested
}} }}
{ count, plural, =0 { { sex, select, other {
deeply nested
}} }}`;
const XMB = `
@@ -46,6 +49,9 @@ export function main(): void {
translatable element <b> with placeholders</b>
{VAR_PLURAL, plural, =0 {<p> test</p> } }
foo
+ foo
+ foo
+ {VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<p> deeply nested</p> } } } }
{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<p> deeply nested</p> } } } }
`;
diff --git a/modules/@angular/compiler/test/i18n/translation_bundle_spec.ts b/modules/@angular/compiler/test/i18n/translation_bundle_spec.ts
index d6f51e331d..2aa45331f8 100644
--- a/modules/@angular/compiler/test/i18n/translation_bundle_spec.ts
+++ b/modules/@angular/compiler/test/i18n/translation_bundle_spec.ts
@@ -21,7 +21,7 @@ export function main(): void {
it('should translate a plain message', () => {
const msgMap = {foo: [new i18n.Text('bar', null)]};
const tb = new TranslationBundle(msgMap, (_) => 'foo');
- const msg = new i18n.Message([srcNode], {}, {}, 'm', 'd');
+ const msg = new i18n.Message([srcNode], {}, {}, 'm', 'd', 'i');
expect(serializeNodes(tb.get(msg))).toEqual(['bar']);
});
@@ -36,7 +36,7 @@ export function main(): void {
ph1: '*phContent*',
};
const tb = new TranslationBundle(msgMap, (_) => 'foo');
- const msg = new i18n.Message([srcNode], phMap, {}, 'm', 'd');
+ const msg = new i18n.Message([srcNode], phMap, {}, 'm', 'd', 'i');
expect(serializeNodes(tb.get(msg))).toEqual(['bar*phContent*']);
});
@@ -51,8 +51,8 @@ export function main(): void {
new i18n.Text('*refMsg*', null),
],
};
- const refMsg = new i18n.Message([srcNode], {}, {}, 'm', 'd');
- const msg = new i18n.Message([srcNode], {}, {ph1: refMsg}, 'm', 'd');
+ const refMsg = new i18n.Message([srcNode], {}, {}, 'm', 'd', 'i');
+ const msg = new i18n.Message([srcNode], {}, {ph1: refMsg}, 'm', 'd', 'i');
let count = 0;
const digest = (_: any) => count++ ? 'ref' : 'foo';
const tb = new TranslationBundle(msgMap, digest);
@@ -69,13 +69,13 @@ export function main(): void {
]
};
const tb = new TranslationBundle(msgMap, (_) => 'foo');
- const msg = new i18n.Message([srcNode], {}, {}, 'm', 'd');
+ const msg = new i18n.Message([srcNode], {}, {}, 'm', 'd', 'i');
expect(() => tb.get(msg)).toThrowError(/Unknown placeholder/);
});
it('should report missing translation', () => {
const tb = new TranslationBundle({}, (_) => 'foo');
- const msg = new i18n.Message([srcNode], {}, {}, 'm', 'd');
+ const msg = new i18n.Message([srcNode], {}, {}, 'm', 'd', 'i');
expect(() => tb.get(msg)).toThrowError(/Missing translation for message foo/);
});
@@ -83,8 +83,8 @@ export function main(): void {
const msgMap = {
foo: [new i18n.Placeholder('', 'ph1', span)],
};
- const refMsg = new i18n.Message([srcNode], {}, {}, 'm', 'd');
- const msg = new i18n.Message([srcNode], {}, {ph1: refMsg}, 'm', 'd');
+ const refMsg = new i18n.Message([srcNode], {}, {}, 'm', 'd', 'i');
+ const msg = new i18n.Message([srcNode], {}, {ph1: refMsg}, 'm', 'd', 'i');
let count = 0;
const digest = (_: any) => count++ ? 'ref' : 'foo';
const tb = new TranslationBundle(msgMap, digest);
@@ -102,7 +102,7 @@ export function main(): void {
ph1: '',
};
const tb = new TranslationBundle(msgMap, (_) => 'foo');
- const msg = new i18n.Message([srcNode], phMap, {}, 'm', 'd');
+ const msg = new i18n.Message([srcNode], phMap, {}, 'm', 'd', 'i');
expect(() => tb.get(msg)).toThrowError(/Unexpected closing tag "b"/);
});
});