diff --git a/modules/@angular/compiler/src/i18n/extractor_merger.ts b/modules/@angular/compiler/src/i18n/extractor_merger.ts
index 1d58fed826..99de2bd10a 100644
--- a/modules/@angular/compiler/src/i18n/extractor_merger.ts
+++ b/modules/@angular/compiler/src/i18n/extractor_merger.ts
@@ -327,6 +327,7 @@ class _Visitor implements html.Visitor {
}
// Translates the given message given the `TranslationBundle`
+ // This is used for translating elements / blocks - see `_translateAttributes` for attributes
// no-op when called in extraction mode (returns [])
private _translateMessage(el: html.Node, message: i18n.Message): html.Node[] {
if (message && this._mode === _VisitorMode.Merge) {
@@ -368,7 +369,9 @@ class _Visitor implements html.Visitor {
const message: i18n.Message = this._createI18nMessage([attr], meaning, '', '');
const nodes = this._translations.get(message);
if (nodes) {
- if (nodes[0] instanceof html.Text) {
+ if (nodes.length == 0) {
+ translatedAttributes.push(new html.Attribute(attr.name, '', attr.sourceSpan));
+ } else if (nodes[0] instanceof html.Text) {
const value = (nodes[0] as html.Text).value;
translatedAttributes.push(new html.Attribute(attr.name, value, attr.sourceSpan));
} else {
diff --git a/modules/@angular/compiler/test/i18n/extractor_merger_spec.ts b/modules/@angular/compiler/test/i18n/extractor_merger_spec.ts
index 0e88c7359d..e7f607c3d4 100644
--- a/modules/@angular/compiler/test/i18n/extractor_merger_spec.ts
+++ b/modules/@angular/compiler/test/i18n/extractor_merger_spec.ts
@@ -383,6 +383,24 @@ export function main() {
const HTML = `
`;
expect(fakeTranslate(HTML)).toEqual('');
});
+
+ it('should merge empty messages', () => {
+ const HTML = `some element
`;
+ const htmlNodes: html.Node[] = parseHtml(HTML);
+ const messages: i18n.Message[] =
+ extractMessages(htmlNodes, DEFAULT_INTERPOLATION_CONFIG, [], {}).messages;
+
+ expect(messages.length).toEqual(1);
+ const i18nMsgMap: {[id: string]: i18n.Node[]} = {};
+ i18nMsgMap[digest(messages[0])] = [];
+ const translations = new TranslationBundle(i18nMsgMap, digest);
+
+ const output =
+ mergeTranslations(htmlNodes, translations, DEFAULT_INTERPOLATION_CONFIG, [], {});
+ expect(output.errors).toEqual([]);
+
+ expect(serializeHtmlNodes(output.rootNodes).join('')).toEqual(``);
+ });
});
describe('blocks', () => {
@@ -422,6 +440,25 @@ export function main() {
const HTML = ``;
expect(fakeTranslate(HTML)).toEqual('');
});
+
+ it('should merge empty attributes', () => {
+ const HTML = `some element
`;
+ const htmlNodes: html.Node[] = parseHtml(HTML);
+ const messages: i18n.Message[] =
+ extractMessages(htmlNodes, DEFAULT_INTERPOLATION_CONFIG, [], {}).messages;
+
+ expect(messages.length).toEqual(1);
+ const i18nMsgMap: {[id: string]: i18n.Node[]} = {};
+ i18nMsgMap[digest(messages[0])] = [];
+ const translations = new TranslationBundle(i18nMsgMap, digest);
+
+ const output =
+ mergeTranslations(htmlNodes, translations, DEFAULT_INTERPOLATION_CONFIG, [], {});
+ expect(output.errors).toEqual([]);
+
+ expect(serializeHtmlNodes(output.rootNodes).join(''))
+ .toEqual(`some element
`);
+ });
});
});
}
@@ -453,12 +490,11 @@ function fakeTranslate(
const translations = new TranslationBundle(i18nMsgMap, digest);
- const translatedNodes =
- mergeTranslations(
- htmlNodes, translations, DEFAULT_INTERPOLATION_CONFIG, implicitTags, implicitAttrs)
- .rootNodes;
+ const output = mergeTranslations(
+ htmlNodes, translations, DEFAULT_INTERPOLATION_CONFIG, implicitTags, implicitAttrs);
+ expect(output.errors).toEqual([]);
- return serializeHtmlNodes(translatedNodes).join('');
+ return serializeHtmlNodes(output.rootNodes).join('');
}
function extract(
diff --git a/modules/@angular/compiler/test/i18n/serializers/xliff_spec.ts b/modules/@angular/compiler/test/i18n/serializers/xliff_spec.ts
index 6d7b3fb7cf..e2fb4fc207 100644
--- a/modules/@angular/compiler/test/i18n/serializers/xliff_spec.ts
+++ b/modules/@angular/compiler/test/i18n/serializers/xliff_spec.ts
@@ -94,6 +94,11 @@ const LOAD_XLIFF = `
ph names
+
+
+
+ ph names
+