From 6dd52017652f0faab6ecb21fc4107c5fb669fb9b Mon Sep 17 00:00:00 2001 From: maxime-allex Date: Tue, 6 Dec 2016 15:00:25 +0100 Subject: [PATCH] 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 ab73961294..97015e8d8b 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 ee33098324..c3766b625a 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 3f2856c32f..e3af025a50 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); }