diff --git a/modules/@angular/compiler/src/i18n/serializers/xtb.ts b/modules/@angular/compiler/src/i18n/serializers/xtb.ts
index 8578763525..56234aba56 100644
--- a/modules/@angular/compiler/src/i18n/serializers/xtb.ts
+++ b/modules/@angular/compiler/src/i18n/serializers/xtb.ts
@@ -29,10 +29,19 @@ export class Xtb extends Serializer {
// xml nodes to i18n nodes
const i18nNodesByMsgId: {[msgId: string]: i18n.Node[]} = {};
const converter = new XmlToI18n();
+
+ // Because we should be able to load xtb files that rely on features not supported by angular,
+ // we need to delay the conversion of html to i18n nodes so that non angular messages are not
+ // converted
Object.keys(mlNodesByMsgId).forEach(msgId => {
- const {i18nNodes, errors: e} = converter.convert(mlNodesByMsgId[msgId]);
- errors.push(...e);
- i18nNodesByMsgId[msgId] = i18nNodes;
+ const valueFn = function() {
+ const {i18nNodes, errors} = converter.convert(mlNodesByMsgId[msgId]);
+ if (errors.length) {
+ throw new Error(`xtb parse errors:\n${errors.join('\n')}`);
+ }
+ return i18nNodes;
+ };
+ createLazyProperty(i18nNodesByMsgId, msgId, valueFn);
});
if (errors.length) {
@@ -49,6 +58,19 @@ export class Xtb extends Serializer {
}
}
+function createLazyProperty(messages: any, id: string, valueFn: () => any) {
+ Object.defineProperty(messages, id, {
+ configurable: true,
+ enumerable: true,
+ get: function() {
+ const value = valueFn();
+ Object.defineProperty(messages, id, {enumerable: true, value});
+ return value;
+ },
+ set: _ => { throw new Error('Could not overwrite an XTB translation'); },
+ });
+}
+
// Extract messages as xml nodes from the xtb file
class XtbParser implements ml.Visitor {
private _bundleDepth: number;
diff --git a/modules/@angular/compiler/test/i18n/serializers/xtb_spec.ts b/modules/@angular/compiler/test/i18n/serializers/xtb_spec.ts
index 57c9c52693..b8eb6a8d07 100644
--- a/modules/@angular/compiler/test/i18n/serializers/xtb_spec.ts
+++ b/modules/@angular/compiler/test/i18n/serializers/xtb_spec.ts
@@ -9,8 +9,10 @@
import {escapeRegExp} from '@angular/core/src/facade/lang';
import {serializeNodes} from '../../../src/i18n/digest';
+import * as i18n from '../../../src/i18n/i18n_ast';
import {Xtb} from '../../../src/i18n/serializers/xtb';
+
export function main(): void {
describe('XTB serializer', () => {
const serializer = new Xtb();
@@ -100,6 +102,25 @@ export function main(): void {
});
describe('errors', () => {
+ it('should be able to parse non-angular xtb files without error', () => {
+ const XTB = `
+
+ is great
+ is less great
+`;
+
+ // Invalid messages should not cause the parser to throw
+ let i18nNodesByMsgId: {[id: string]: i18n.Node[]};
+ expect(() => { i18nNodesByMsgId = serializer.load(XTB, 'url'); }).not.toThrow();
+
+ expect(Object.keys(i18nNodesByMsgId).length).toEqual(2);
+ expect(serializeNodes(i18nNodesByMsgId['angular']).join('')).toEqual('is great');
+ // Messages that contain unsupported feature should throw on access
+ expect(() => {
+ const read = i18nNodesByMsgId['non angular'];
+ }).toThrowError(/xtb parse errors/);
+ });
+
it('should throw on nested ', () => {
const XTB =
'';