Skip to content

Commit

Permalink
refactor(ivy): i18n - share MessageSerializer across `TranslationPa…
Browse files Browse the repository at this point in the history
…rsers` (angular#33444)

Each of the XML based `TranslationParsers` was providing its own
`MessageSerializer`, but they are all very similar. So these have been
consolidated into a single more generic `MessageSerializer.

As a result of this, the extra layers of folders in the project seemed
unnecessary, so they have been flattened.

PR Close angular#33444
  • Loading branch information
petebacondarwin authored and mohaxspb committed Nov 7, 2019
1 parent 7223596 commit 9d62024
Show file tree
Hide file tree
Showing 12 changed files with 67 additions and 93 deletions.
6 changes: 3 additions & 3 deletions packages/localize/src/tools/src/translate/main.ts
Expand Up @@ -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';

Expand Down
Expand Up @@ -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<T> extends BaseVisitor {
constructor(private renderer: MessageRenderer<T>) { 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<T> extends BaseVisitor {
constructor(private renderer: MessageRenderer<T>, private config: MessageSerializerConfig) {
super();
}

serialize(nodes: Node[]): T {
this.renderer.startRender();
Expand All @@ -24,13 +37,18 @@ export class Xliff2MessageSerializer<T> 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.`);
Expand Down Expand Up @@ -58,11 +76,11 @@ export class Xliff2MessageSerializer<T> 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;
}
}
Expand All @@ -89,8 +107,8 @@ export class Xliff2MessageSerializer<T> 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;
}
}
Expand Up @@ -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:
Expand Down

This file was deleted.

Expand Up @@ -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"/;

Expand Down Expand Up @@ -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));
}

Expand Down
Expand Up @@ -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"/;

Expand Down Expand Up @@ -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));
}

Expand Down
Expand Up @@ -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()', () => {
Expand Down
Expand Up @@ -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()', () => {
Expand Down
Expand Up @@ -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()', () => {
Expand Down

0 comments on commit 9d62024

Please sign in to comment.