From 9d5fbf74f42d134b1d717dac259f76b03d9e37f6 Mon Sep 17 00:00:00 2001
From: maxime-allex
Date: Tue, 6 Dec 2016 15:00:25 +0100
Subject: [PATCH 1/3] feat(compiler): add id property to i18nMessage
---
.../compiler/src/i18n/extractor_merger.ts | 29 ++++++++++++-------
.../@angular/compiler/src/i18n/i18n_ast.ts | 3 +-
.../@angular/compiler/src/i18n/i18n_parser.ts | 12 ++++----
3 files changed, 27 insertions(+), 17 deletions(-)
diff --git a/modules/@angular/compiler/src/i18n/extractor_merger.ts b/modules/@angular/compiler/src/i18n/extractor_merger.ts
index ab7396129443..97015e8d8bba 100644
--- a/modules/@angular/compiler/src/i18n/extractor_merger.ts
+++ b/modules/@angular/compiler/src/i18n/extractor_merger.ts
@@ -18,6 +18,8 @@ import {TranslationBundle} from './translation_bundle';
const _I18N_ATTR = 'i18n';
const _I18N_ATTR_PREFIX = 'i18n-';
const _I18N_COMMENT_PREFIX_REGEXP = /^i18n:?/;
+const MEANING_SEPARATOR = '|';
+const ID_SEPARATOR = '@@';
/**
* Extract translatable messages from an html AST
@@ -77,7 +79,7 @@ class _Visitor implements html.Visitor {
// _VisitorMode.Merge only
private _translations: TranslationBundle;
private _createI18nMessage:
- (msg: html.Node[], meaning: string, description: string) => i18n.Message;
+ (msg: html.Node[], meaning: string, description: string, id: string) => i18n.Message;
constructor(private _implicitTags: string[], private _implicitAttrs: {[k: string]: string[]}) {}
@@ -330,15 +332,15 @@ class _Visitor implements html.Visitor {
}
// add a translatable message
- private _addMessage(ast: html.Node[], meaningAndDesc?: string): i18n.Message {
+ private _addMessage(ast: html.Node[], msgMeta?: string): i18n.Message {
if (ast.length == 0 ||
ast.length == 1 && ast[0] instanceof html.Attribute && !(ast[0]).value) {
// Do not create empty messages
return;
}
- const [meaning, description] = _splitMeaningAndDesc(meaningAndDesc);
- const message = this._createI18nMessage(ast, meaning, description);
+ const {meaning, description, id} = _parseMessageMeta(msgMeta);
+ const message = this._createI18nMessage(ast, meaning, description, id);
this._messages.push(message);
return message;
}
@@ -368,7 +370,7 @@ class _Visitor implements html.Visitor {
attributes.forEach(attr => {
if (attr.name.startsWith(_I18N_ATTR_PREFIX)) {
i18nAttributeMeanings[attr.name.slice(_I18N_ATTR_PREFIX.length)] =
- _splitMeaningAndDesc(attr.value)[0];
+ _parseMessageMeta(attr.value).meaning;
}
});
@@ -382,7 +384,7 @@ class _Visitor implements html.Visitor {
if (attr.value && attr.value != '' && i18nAttributeMeanings.hasOwnProperty(attr.name)) {
const meaning = i18nAttributeMeanings[attr.name];
- const message: i18n.Message = this._createI18nMessage([attr], meaning, '');
+ const message: i18n.Message = this._createI18nMessage([attr], meaning, '', '');
const nodes = this._translations.get(message);
if (nodes) {
if (nodes[0] instanceof html.Text) {
@@ -496,8 +498,15 @@ function _getI18nAttr(p: html.Element): html.Attribute {
return p.attrs.find(attr => attr.name === _I18N_ATTR) || null;
}
-function _splitMeaningAndDesc(i18n: string): [string, string] {
- if (!i18n) return ['', ''];
- const pipeIndex = i18n.indexOf('|');
- return pipeIndex == -1 ? ['', i18n] : [i18n.slice(0, pipeIndex), i18n.slice(pipeIndex + 1)];
+function _parseMessageMeta(i18n: string): {meaning: string, description: string, id: string} {
+ if (!i18n) return {meaning: '', description: '', id: ''};
+
+ const idIndex = i18n.indexOf(ID_SEPARATOR);
+ const descIndex = i18n.indexOf(MEANING_SEPARATOR);
+ const [meaningAndDesc, id] = (idIndex > -1) ? [i18n.slice(0, idIndex), i18n.slice(idIndex + 2)] :
+ [i18n, ''];
+ const [meaning, description] = (descIndex > -1) ? [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] :
+ ['', meaningAndDesc];
+
+ return {meaning, description, id};
}
diff --git a/modules/@angular/compiler/src/i18n/i18n_ast.ts b/modules/@angular/compiler/src/i18n/i18n_ast.ts
index ee3309832494..c3766b625a20 100644
--- a/modules/@angular/compiler/src/i18n/i18n_ast.ts
+++ b/modules/@angular/compiler/src/i18n/i18n_ast.ts
@@ -15,11 +15,12 @@ export class Message {
* @param placeholderToMessage maps placeholder names to messages (used for nested ICU messages)
* @param meaning
* @param description
+ * @param id
*/
constructor(
public nodes: Node[], public placeholders: {[phName: string]: string},
public placeholderToMessage: {[phName: string]: Message}, public meaning: string,
- public description: string) {}
+ public description: string, public id: string) {}
}
export interface Node {
diff --git a/modules/@angular/compiler/src/i18n/i18n_parser.ts b/modules/@angular/compiler/src/i18n/i18n_parser.ts
index 3f2856c32fea..e3af025a5050 100644
--- a/modules/@angular/compiler/src/i18n/i18n_parser.ts
+++ b/modules/@angular/compiler/src/i18n/i18n_parser.ts
@@ -22,11 +22,11 @@ const _expParser = new ExpressionParser(new ExpressionLexer());
* Returns a function converting html nodes to an i18n Message given an interpolationConfig
*/
export function createI18nMessageFactory(interpolationConfig: InterpolationConfig): (
- nodes: html.Node[], meaning: string, description: string) => i18n.Message {
+ nodes: html.Node[], meaning: string, description: string, id: string) => i18n.Message {
const visitor = new _I18nVisitor(_expParser, interpolationConfig);
- return (nodes: html.Node[], meaning: string, description: string) =>
- visitor.toI18nMessage(nodes, meaning, description);
+ return (nodes: html.Node[], meaning: string, description: string, id: string) =>
+ visitor.toI18nMessage(nodes, meaning, description, id);
}
class _I18nVisitor implements html.Visitor {
@@ -40,7 +40,7 @@ class _I18nVisitor implements html.Visitor {
private _expressionParser: ExpressionParser,
private _interpolationConfig: InterpolationConfig) {}
- public toI18nMessage(nodes: html.Node[], meaning: string, description: 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();
@@ -50,7 +50,7 @@ class _I18nVisitor implements html.Visitor {
const i18nodes: i18n.Node[] = html.visitAll(this, nodes, {});
return new i18n.Message(
- i18nodes, this._placeholderToContent, this._placeholderToMessage, meaning, description);
+ i18nodes, this._placeholderToContent, this._placeholderToMessage, meaning, description, id);
}
visitElement(el: html.Element, context: any): i18n.Node {
@@ -115,7 +115,7 @@ class _I18nVisitor implements html.Visitor {
// TODO(vicb): add a html.Node -> i18n.Message cache to avoid having to re-create the msg
const phName = this._placeholderRegistry.getPlaceholderName('ICU', icu.sourceSpan.toString());
const visitor = new _I18nVisitor(this._expressionParser, this._interpolationConfig);
- this._placeholderToMessage[phName] = visitor.toI18nMessage([icu], '', '');
+ this._placeholderToMessage[phName] = visitor.toI18nMessage([icu], '', '', '');
return new i18n.IcuPlaceholder(i18nIcu, phName, icu.sourceSpan);
}
From 03c874fadd5ebd31c62ffbaa543c1af0129633aa Mon Sep 17 00:00:00 2001
From: maxime-allex
Date: Tue, 6 Dec 2016 15:01:43 +0100
Subject: [PATCH 2/3] feat(compiler): digest methods return i18nMessage id if
sets
---
modules/@angular/compiler/src/i18n/digest.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/modules/@angular/compiler/src/i18n/digest.ts b/modules/@angular/compiler/src/i18n/digest.ts
index d00bf803541a..6bc2ff0dd420 100644
--- a/modules/@angular/compiler/src/i18n/digest.ts
+++ b/modules/@angular/compiler/src/i18n/digest.ts
@@ -9,13 +9,13 @@
import * as i18n from './i18n_ast';
export function digest(message: i18n.Message): string {
- return sha1(serializeNodes(message.nodes).join('') + `[${message.meaning}]`);
+ return message.id || sha1(serializeNodes(message.nodes).join('') + `[${message.meaning}]`);
}
export function decimalDigest(message: i18n.Message): string {
const visitor = new _SerializerIgnoreIcuExpVisitor();
const parts = message.nodes.map(a => a.visit(visitor, null));
- return computeMsgId(parts.join(''), message.meaning);
+ return message.id || computeMsgId(parts.join(''), message.meaning);
}
/**
From b868ce28304ac25cf16e43de08cb7032d85abc15 Mon Sep 17 00:00:00 2001
From: maxime-allex
Date: Tue, 6 Dec 2016 15:04:59 +0100
Subject: [PATCH 3/3] test(compiler): test i18n explicit id
---
.../@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 e3af025a5050..cac8435660eb 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 07b7bbe390f6..7297f6cc7613 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 c1754255073c..0e88c7359dfe 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 ade32405ddae..7823c426341e 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 5c8f9af5a331..6d7b3fb7cfbc 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 319370102ef9..ecfe0b151993 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 d6f51e331d37..2aa45331f87c 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"/);
});
});