feat(compiler): add id property to i18nMessage

This commit is contained in:
maxime-allex 2016-12-06 15:00:25 +01:00 committed by Victor Berchet
parent 72361fb68f
commit 6dd5201765
3 changed files with 27 additions and 17 deletions

View File

@ -18,6 +18,8 @@ import {TranslationBundle} from './translation_bundle';
const _I18N_ATTR = 'i18n'; const _I18N_ATTR = 'i18n';
const _I18N_ATTR_PREFIX = 'i18n-'; const _I18N_ATTR_PREFIX = 'i18n-';
const _I18N_COMMENT_PREFIX_REGEXP = /^i18n:?/; const _I18N_COMMENT_PREFIX_REGEXP = /^i18n:?/;
const MEANING_SEPARATOR = '|';
const ID_SEPARATOR = '@@';
/** /**
* Extract translatable messages from an html AST * Extract translatable messages from an html AST
@ -77,7 +79,7 @@ class _Visitor implements html.Visitor {
// _VisitorMode.Merge only // _VisitorMode.Merge only
private _translations: TranslationBundle; private _translations: TranslationBundle;
private _createI18nMessage: 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[]}) {} constructor(private _implicitTags: string[], private _implicitAttrs: {[k: string]: string[]}) {}
@ -330,15 +332,15 @@ class _Visitor implements html.Visitor {
} }
// add a translatable message // 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 || if (ast.length == 0 ||
ast.length == 1 && ast[0] instanceof html.Attribute && !(<html.Attribute>ast[0]).value) { ast.length == 1 && ast[0] instanceof html.Attribute && !(<html.Attribute>ast[0]).value) {
// Do not create empty messages // Do not create empty messages
return; return;
} }
const [meaning, description] = _splitMeaningAndDesc(meaningAndDesc); const {meaning, description, id} = _parseMessageMeta(msgMeta);
const message = this._createI18nMessage(ast, meaning, description); const message = this._createI18nMessage(ast, meaning, description, id);
this._messages.push(message); this._messages.push(message);
return message; return message;
} }
@ -368,7 +370,7 @@ class _Visitor implements html.Visitor {
attributes.forEach(attr => { attributes.forEach(attr => {
if (attr.name.startsWith(_I18N_ATTR_PREFIX)) { if (attr.name.startsWith(_I18N_ATTR_PREFIX)) {
i18nAttributeMeanings[attr.name.slice(_I18N_ATTR_PREFIX.length)] = 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)) { if (attr.value && attr.value != '' && i18nAttributeMeanings.hasOwnProperty(attr.name)) {
const meaning = i18nAttributeMeanings[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); const nodes = this._translations.get(message);
if (nodes) { if (nodes) {
if (nodes[0] instanceof html.Text) { 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; return p.attrs.find(attr => attr.name === _I18N_ATTR) || null;
} }
function _splitMeaningAndDesc(i18n: string): [string, string] { function _parseMessageMeta(i18n: string): {meaning: string, description: string, id: string} {
if (!i18n) return ['', '']; if (!i18n) return {meaning: '', description: '', id: ''};
const pipeIndex = i18n.indexOf('|');
return pipeIndex == -1 ? ['', i18n] : [i18n.slice(0, pipeIndex), i18n.slice(pipeIndex + 1)]; 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};
} }

View File

@ -15,11 +15,12 @@ export class Message {
* @param placeholderToMessage maps placeholder names to messages (used for nested ICU messages) * @param placeholderToMessage maps placeholder names to messages (used for nested ICU messages)
* @param meaning * @param meaning
* @param description * @param description
* @param id
*/ */
constructor( constructor(
public nodes: Node[], public placeholders: {[phName: string]: string}, public nodes: Node[], public placeholders: {[phName: string]: string},
public placeholderToMessage: {[phName: string]: Message}, public meaning: string, public placeholderToMessage: {[phName: string]: Message}, public meaning: string,
public description: string) {} public description: string, public id: string) {}
} }
export interface Node { export interface Node {

View File

@ -22,11 +22,11 @@ const _expParser = new ExpressionParser(new ExpressionLexer());
* Returns a function converting html nodes to an i18n Message given an interpolationConfig * Returns a function converting html nodes to an i18n Message given an interpolationConfig
*/ */
export function createI18nMessageFactory(interpolationConfig: 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); const visitor = new _I18nVisitor(_expParser, interpolationConfig);
return (nodes: html.Node[], meaning: string, description: string) => return (nodes: html.Node[], meaning: string, description: string, id: string) =>
visitor.toI18nMessage(nodes, meaning, description); visitor.toI18nMessage(nodes, meaning, description, id);
} }
class _I18nVisitor implements html.Visitor { class _I18nVisitor implements html.Visitor {
@ -40,7 +40,7 @@ class _I18nVisitor implements html.Visitor {
private _expressionParser: ExpressionParser, private _expressionParser: ExpressionParser,
private _interpolationConfig: InterpolationConfig) {} 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._isIcu = nodes.length == 1 && nodes[0] instanceof html.Expansion;
this._icuDepth = 0; this._icuDepth = 0;
this._placeholderRegistry = new PlaceholderRegistry(); this._placeholderRegistry = new PlaceholderRegistry();
@ -50,7 +50,7 @@ class _I18nVisitor implements html.Visitor {
const i18nodes: i18n.Node[] = html.visitAll(this, nodes, {}); const i18nodes: i18n.Node[] = html.visitAll(this, nodes, {});
return new i18n.Message( 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 { 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 // 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 phName = this._placeholderRegistry.getPlaceholderName('ICU', icu.sourceSpan.toString());
const visitor = new _I18nVisitor(this._expressionParser, this._interpolationConfig); 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); return new i18n.IcuPlaceholder(i18nIcu, phName, icu.sourceSpan);
} }