diff --git a/packages/localize/src/tools/src/translate/main.ts b/packages/localize/src/tools/src/translate/main.ts index e0af21ff7d4ac..1c075a9db74b4 100644 --- a/packages/localize/src/tools/src/translate/main.ts +++ b/packages/localize/src/tools/src/translate/main.ts @@ -15,9 +15,9 @@ import {getOutputPathFn, OutputPathFn} from './output_path'; import {SourceFileTranslationHandler} from './source_files/source_file_translation_handler'; import {MissingTranslationStrategy} from './source_files/source_file_utils'; import {TranslationLoader} from './translation_files/translation_loader'; -import {SimpleJsonTranslationParser} from './translation_files/translation_parsers/simple_json/simple_json_translation_parser'; -import {Xliff1TranslationParser} from './translation_files/translation_parsers/xliff1/xliff1_translation_parser'; -import {Xliff2TranslationParser} from './translation_files/translation_parsers/xliff2/xliff2_translation_parser'; +import {SimpleJsonTranslationParser} from './translation_files/translation_parsers/simple_json_translation_parser'; +import {Xliff1TranslationParser} from './translation_files/translation_parsers/xliff1_translation_parser'; +import {Xliff2TranslationParser} from './translation_files/translation_parsers/xliff2_translation_parser'; import {Translator} from './translator'; import {Diagnostics} from '../diagnostics'; diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/base_visitor.ts b/packages/localize/src/tools/src/translate/translation_files/base_visitor.ts similarity index 100% rename from packages/localize/src/tools/src/translate/translation_files/translation_parsers/base_visitor.ts rename to packages/localize/src/tools/src/translate/translation_files/base_visitor.ts diff --git a/packages/localize/src/tools/src/translate/message_renderers/message_renderer.ts b/packages/localize/src/tools/src/translate/translation_files/message_serialization/message_renderer.ts similarity index 100% rename from packages/localize/src/tools/src/translate/message_renderers/message_renderer.ts rename to packages/localize/src/tools/src/translate/translation_files/message_serialization/message_renderer.ts diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2/xliff2_message_serializer.ts b/packages/localize/src/tools/src/translate/translation_files/message_serialization/message_serializer.ts similarity index 54% rename from packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2/xliff2_message_serializer.ts rename to packages/localize/src/tools/src/translate/translation_files/message_serialization/message_serializer.ts index 0545cf2f795ce..bea939fe4153b 100644 --- a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2/xliff2_message_serializer.ts +++ b/packages/localize/src/tools/src/translate/translation_files/message_serialization/message_serializer.ts @@ -6,15 +6,28 @@ * found in the LICENSE file at https://angular.io/license */ import {Element, Expansion, ExpansionCase, Node, Text, visitAll} from '@angular/compiler'; -import {MessageRenderer} from '../../../message_renderers/message_renderer'; + import {BaseVisitor} from '../base_visitor'; -import {TranslationParseError} from '../translation_parse_error'; -import {getAttrOrThrow, getAttribute} from '../translation_utils'; +import {TranslationParseError} from '../translation_parsers/translation_parse_error'; +import {getAttrOrThrow, getAttribute} from '../translation_parsers/translation_utils'; + +import {MessageRenderer} from './message_renderer'; -const INLINE_ELEMENTS = ['cp', 'sc', 'ec', 'mrk', 'sm', 'em']; +interface MessageSerializerConfig { + inlineElements: string[]; + placeholder?: {elementName: string; nameAttribute: string; bodyAttribute?: string;}; + placeholderContainer?: {elementName: string; startAttribute: string; endAttribute: string;}; +} -export class Xliff2MessageSerializer extends BaseVisitor { - constructor(private renderer: MessageRenderer) { super(); } +/** + * This visitor will walk over a set of XML nodes, which represent an i18n message, and serialize + * them into a message object of type `T`. + * The type of the serialized message is controlled by the + */ +export class MessageSerializer extends BaseVisitor { + constructor(private renderer: MessageRenderer, private config: MessageSerializerConfig) { + super(); + } serialize(nodes: Node[]): T { this.renderer.startRender(); @@ -24,13 +37,18 @@ export class Xliff2MessageSerializer extends BaseVisitor { } visitElement(element: Element): void { - if (element.name === 'ph') { - this.visitPlaceholder(getAttrOrThrow(element, 'equiv'), getAttribute(element, 'disp')); - } else if (element.name === 'pc') { - this.visitPlaceholderContainer( - getAttrOrThrow(element, 'equivStart'), element.children, - getAttrOrThrow(element, 'equivEnd')); - } else if (INLINE_ELEMENTS.indexOf(element.name) !== -1) { + if (this.config.placeholder && element.name === this.config.placeholder.elementName) { + const name = getAttrOrThrow(element, this.config.placeholder.nameAttribute); + const body = this.config.placeholder.bodyAttribute && + getAttribute(element, this.config.placeholder.bodyAttribute); + this.visitPlaceholder(name, body); + } else if ( + this.config.placeholderContainer && + element.name === this.config.placeholderContainer.elementName) { + const start = getAttrOrThrow(element, this.config.placeholderContainer.startAttribute); + const end = getAttrOrThrow(element, this.config.placeholderContainer.endAttribute); + this.visitPlaceholderContainer(start, element.children, end); + } else if (this.config.inlineElements.indexOf(element.name) !== -1) { visitAll(this, element.children); } else { throw new TranslationParseError(element.sourceSpan, `Invalid element found in message.`); @@ -58,11 +76,11 @@ export class Xliff2MessageSerializer extends BaseVisitor { const length = nodes.length; let index = 0; while (index < length) { - if (!isPlaceholderContainer(nodes[index])) { + if (!this.isPlaceholderContainer(nodes[index])) { const startOfContainedNodes = index; while (index < length - 1) { index++; - if (isPlaceholderContainer(nodes[index])) { + if (this.isPlaceholderContainer(nodes[index])) { break; } } @@ -89,8 +107,8 @@ export class Xliff2MessageSerializer extends BaseVisitor { this.visitContainedNodes(children); this.renderer.closePlaceholder(closeName); } -} -function isPlaceholderContainer(node: Node): boolean { - return node instanceof Element && node.name === 'pc'; + private isPlaceholderContainer(node: Node): boolean { + return node instanceof Element && node.name === this.config.placeholderContainer !.elementName; + } } diff --git a/packages/localize/src/tools/src/translate/message_renderers/target_message_renderer.ts b/packages/localize/src/tools/src/translate/translation_files/message_serialization/target_message_renderer.ts similarity index 100% rename from packages/localize/src/tools/src/translate/message_renderers/target_message_renderer.ts rename to packages/localize/src/tools/src/translate/translation_files/message_serialization/target_message_renderer.ts diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/simple_json/simple_json_translation_parser.ts b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/simple_json_translation_parser.ts similarity index 93% rename from packages/localize/src/tools/src/translate/translation_files/translation_parsers/simple_json/simple_json_translation_parser.ts rename to packages/localize/src/tools/src/translate/translation_files/translation_parsers/simple_json_translation_parser.ts index 4e9f6d576e78b..0421529e96e13 100644 --- a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/simple_json/simple_json_translation_parser.ts +++ b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/simple_json_translation_parser.ts @@ -7,7 +7,7 @@ */ import {ɵMessageId, ɵParsedTranslation, ɵparseTranslation} from '@angular/localize'; import {extname} from 'path'; -import {ParsedTranslationBundle, TranslationParser} from '../translation_parser'; +import {ParsedTranslationBundle, TranslationParser} from './translation_parser'; /** * A translation parser that can parse JSON that has the form: diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1/xliff1_message_serializer.ts b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1/xliff1_message_serializer.ts deleted file mode 100644 index 2824c7808179a..0000000000000 --- a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1/xliff1_message_serializer.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import {Element, Expansion, ExpansionCase, Node, Text, visitAll} from '@angular/compiler'; -import {MessageRenderer} from '../../../message_renderers/message_renderer'; -import {BaseVisitor} from '../base_visitor'; -import {TranslationParseError} from '../translation_parse_error'; -import {getAttrOrThrow} from '../translation_utils'; - -const INLINE_ELEMENTS = ['g', 'bx', 'ex', 'bpt', 'ept', 'ph', 'it', 'mrk']; - -export class Xliff1MessageSerializer extends BaseVisitor { - constructor(private renderer: MessageRenderer) { super(); } - - serialize(nodes: Node[]): T { - this.renderer.startRender(); - visitAll(this, nodes); - this.renderer.endRender(); - return this.renderer.message; - } - - visitElement(element: Element): void { - if (element.name === 'x') { - this.visitPlaceholder(getAttrOrThrow(element, 'id'), ''); - } else if (INLINE_ELEMENTS.indexOf(element.name) !== -1) { - visitAll(this, element.children); - } else { - throw new TranslationParseError(element.sourceSpan, `Invalid element found in message.`); - } - } - - visitText(text: Text): void { this.renderer.text(text.value); } - - visitExpansion(expansion: Expansion): void { - this.renderer.startIcu(); - this.renderer.text(`${expansion.switchValue}, ${expansion.type},`); - visitAll(this, expansion.cases); - this.renderer.endIcu(); - } - - visitExpansionCase(expansionCase: ExpansionCase): void { - this.renderer.text(` ${expansionCase.value} {`); - this.renderer.startContainer(); - visitAll(this, expansionCase.expression); - this.renderer.closeContainer(); - this.renderer.text(`}`); - } - - visitPlaceholder(name: string, body: string|undefined): void { - this.renderer.placeholder(name, body); - } -} diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1/xliff1_translation_parser.ts b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1_translation_parser.ts similarity index 83% rename from packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1/xliff1_translation_parser.ts rename to packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1_translation_parser.ts index 34e18da458bfb..1301d5ecda9b2 100644 --- a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1/xliff1_translation_parser.ts +++ b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1_translation_parser.ts @@ -8,12 +8,14 @@ import {Element, Node, XmlParser, visitAll} from '@angular/compiler'; import {ɵMessageId, ɵParsedTranslation} from '@angular/localize'; import {extname} from 'path'; -import {TargetMessageRenderer} from '../../../message_renderers/target_message_renderer'; + import {BaseVisitor} from '../base_visitor'; -import {TranslationParseError} from '../translation_parse_error'; -import {ParsedTranslationBundle, TranslationParser} from '../translation_parser'; -import {getAttrOrThrow, getAttribute, parseInnerRange} from '../translation_utils'; -import {Xliff1MessageSerializer} from './xliff1_message_serializer'; +import {MessageSerializer} from '../message_serialization/message_serializer'; +import {TargetMessageRenderer} from '../message_serialization/target_message_renderer'; + +import {TranslationParseError} from './translation_parse_error'; +import {ParsedTranslationBundle, TranslationParser} from './translation_parser'; +import {getAttrOrThrow, getAttribute, parseInnerRange} from './translation_utils'; const XLIFF_1_2_NS_REGEX = /xmlns="urn:oasis:names:tc:xliff:document:1.2"/; @@ -90,7 +92,10 @@ class XliffTranslationVisitor extends BaseVisitor { } function serializeTargetMessage(source: Element): ɵParsedTranslation { - const serializer = new Xliff1MessageSerializer(new TargetMessageRenderer()); + const serializer = new MessageSerializer(new TargetMessageRenderer(), { + inlineElements: ['g', 'bx', 'ex', 'bpt', 'ept', 'ph', 'it', 'mrk'], + placeholder: {elementName: 'x', nameAttribute: 'id'} + }); return serializer.serialize(parseInnerRange(source)); } diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2/xliff2_translation_parser.ts b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2_translation_parser.ts similarity index 83% rename from packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2/xliff2_translation_parser.ts rename to packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2_translation_parser.ts index 57d9c402ec325..3530150ea893f 100644 --- a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2/xliff2_translation_parser.ts +++ b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2_translation_parser.ts @@ -8,12 +8,14 @@ import {Element, Node, XmlParser, visitAll} from '@angular/compiler'; import {ɵMessageId, ɵParsedTranslation} from '@angular/localize'; import {extname} from 'path'; -import {TargetMessageRenderer} from '../../../message_renderers/target_message_renderer'; + import {BaseVisitor} from '../base_visitor'; -import {TranslationParseError} from '../translation_parse_error'; -import {ParsedTranslationBundle, TranslationParser} from '../translation_parser'; -import {getAttrOrThrow, getAttribute, parseInnerRange} from '../translation_utils'; -import {Xliff2MessageSerializer} from './xliff2_message_serializer'; +import {MessageSerializer} from '../message_serialization/message_serializer'; +import {TargetMessageRenderer} from '../message_serialization/target_message_renderer'; + +import {TranslationParseError} from './translation_parse_error'; +import {ParsedTranslationBundle, TranslationParser} from './translation_parser'; +import {getAttrOrThrow, getAttribute, parseInnerRange} from './translation_utils'; const XLIFF_2_0_NS_REGEX = /xmlns="urn:oasis:names:tc:xliff:document:2.0"/; @@ -105,7 +107,12 @@ function assertTranslationUnit(segment: Element, context: any) { } function serializeTargetMessage(source: Element): ɵParsedTranslation { - const serializer = new Xliff2MessageSerializer(new TargetMessageRenderer()); + const serializer = new MessageSerializer(new TargetMessageRenderer(), { + inlineElements: ['cp', 'sc', 'ec', 'mrk', 'sm', 'em'], + placeholder: {elementName: 'ph', nameAttribute: 'equiv', bodyAttribute: 'disp'}, + placeholderContainer: + {elementName: 'pc', startAttribute: 'equivStart', endAttribute: 'equivEnd'} + }); return serializer.serialize(parseInnerRange(source)); } diff --git a/packages/localize/src/tools/test/translate/translation_files/translation_parsers/simple_json/simple_json_spec.ts b/packages/localize/src/tools/test/translate/translation_files/translation_parsers/simple_json_spec.ts similarity index 90% rename from packages/localize/src/tools/test/translate/translation_files/translation_parsers/simple_json/simple_json_spec.ts rename to packages/localize/src/tools/test/translate/translation_files/translation_parsers/simple_json_spec.ts index d4fbff595f48e..3607fb413b869 100644 --- a/packages/localize/src/tools/test/translate/translation_files/translation_parsers/simple_json/simple_json_spec.ts +++ b/packages/localize/src/tools/test/translate/translation_files/translation_parsers/simple_json_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {ɵmakeTemplateObject} from '@angular/localize'; -import {SimpleJsonTranslationParser} from '../../../../../src/translate/translation_files/translation_parsers/simple_json/simple_json_translation_parser'; +import {SimpleJsonTranslationParser} from '../../../../src/translate/translation_files/translation_parsers/simple_json_translation_parser'; describe('SimpleJsonTranslationParser', () => { describe('canParse()', () => { diff --git a/packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff1/xliff1_translation_parser_spec.ts b/packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff1_translation_parser_spec.ts similarity index 99% rename from packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff1/xliff1_translation_parser_spec.ts rename to packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff1_translation_parser_spec.ts index f8a25dc3fdc8c..e0fa2a443c236 100644 --- a/packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff1/xliff1_translation_parser_spec.ts +++ b/packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff1_translation_parser_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {ɵcomputeMsgId, ɵmakeParsedTranslation} from '@angular/localize'; -import {Xliff1TranslationParser} from '../../../../../src/translate/translation_files/translation_parsers/xliff1/xliff1_translation_parser'; +import {Xliff1TranslationParser} from '../../../../src/translate/translation_files/translation_parsers/xliff1_translation_parser'; describe('Xliff1TranslationParser', () => { describe('canParse()', () => { diff --git a/packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff2/xliff2_translation_parser_spec.ts b/packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff2_translation_parser_spec.ts similarity index 99% rename from packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff2/xliff2_translation_parser_spec.ts rename to packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff2_translation_parser_spec.ts index 94bb19e45b8a0..10381a3b2bcd4 100644 --- a/packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff2/xliff2_translation_parser_spec.ts +++ b/packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff2_translation_parser_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {ɵcomputeMsgId, ɵmakeParsedTranslation} from '@angular/localize'; -import {Xliff2TranslationParser} from '../../../../../src/translate/translation_files/translation_parsers/xliff2/xliff2_translation_parser'; +import {Xliff2TranslationParser} from '../../../../src/translate/translation_files/translation_parsers/xliff2_translation_parser'; describe('Xliff2TranslationParser', () => { describe('canParse()', () => {