
committed by
Misko Hevery

parent
a4934a74b6
commit
92e80af875
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import {ParsedEvent, ParsedProperty, ParsedVariable} from '../expression_parser/ast';
|
||||
import * as i18n from '../i18n/i18n_ast';
|
||||
import * as html from '../ml_parser/ast';
|
||||
import {replaceNgsp} from '../ml_parser/html_whitespaces';
|
||||
import {isNgTemplate} from '../ml_parser/tags';
|
||||
@ -17,7 +18,7 @@ import {PreparsedElementType, preparseElement} from '../template_parser/template
|
||||
import {syntaxError} from '../util';
|
||||
|
||||
import * as t from './r3_ast';
|
||||
|
||||
import {I18N_ICU_VAR_PREFIX} from './view/i18n/util';
|
||||
|
||||
const BIND_NAME_REGEXP =
|
||||
/^(?:(?:(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.+))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/;
|
||||
@ -112,6 +113,7 @@ class HtmlAstToIvyAst implements html.Visitor {
|
||||
const variables: t.Variable[] = [];
|
||||
const references: t.Reference[] = [];
|
||||
const attributes: t.TextAttribute[] = [];
|
||||
const i18nAttrsMeta: {[key: string]: i18n.AST} = {};
|
||||
|
||||
const templateParsedProperties: ParsedProperty[] = [];
|
||||
const templateVariables: t.Variable[] = [];
|
||||
@ -126,6 +128,10 @@ class HtmlAstToIvyAst implements html.Visitor {
|
||||
// `*attr` defines template bindings
|
||||
let isTemplateBinding = false;
|
||||
|
||||
if (attribute.i18n) {
|
||||
i18nAttrsMeta[attribute.name] = attribute.i18n;
|
||||
}
|
||||
|
||||
if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX)) {
|
||||
// *-attributes
|
||||
if (elementHasInlineTemplate) {
|
||||
@ -175,61 +181,83 @@ class HtmlAstToIvyAst implements html.Visitor {
|
||||
|
||||
const selectorIndex =
|
||||
selector === DEFAULT_CONTENT_SELECTOR ? 0 : this.ngContentSelectors.push(selector);
|
||||
parsedElement = new t.Content(selectorIndex, attributes, element.sourceSpan);
|
||||
parsedElement = new t.Content(selectorIndex, attributes, element.sourceSpan, element.i18n);
|
||||
} else if (isTemplateElement) {
|
||||
// `<ng-template>`
|
||||
const attrs = this.extractAttributes(element.name, parsedProperties);
|
||||
const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta);
|
||||
|
||||
parsedElement = new t.Template(
|
||||
attributes, attrs.bound, boundEvents, children, references, variables, element.sourceSpan,
|
||||
element.startSourceSpan, element.endSourceSpan);
|
||||
element.startSourceSpan, element.endSourceSpan, element.i18n);
|
||||
} else {
|
||||
const attrs = this.extractAttributes(element.name, parsedProperties);
|
||||
|
||||
const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta);
|
||||
parsedElement = new t.Element(
|
||||
element.name, attributes, attrs.bound, boundEvents, children, references,
|
||||
element.sourceSpan, element.startSourceSpan, element.endSourceSpan);
|
||||
element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
||||
}
|
||||
|
||||
if (elementHasInlineTemplate) {
|
||||
const attrs = this.extractAttributes('ng-template', templateParsedProperties);
|
||||
const attrs = this.extractAttributes('ng-template', templateParsedProperties, i18nAttrsMeta);
|
||||
// TODO(pk): test for this case
|
||||
parsedElement = new t.Template(
|
||||
attrs.literal, attrs.bound, [], [parsedElement], [], templateVariables,
|
||||
element.sourceSpan, element.startSourceSpan, element.endSourceSpan);
|
||||
element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
||||
}
|
||||
return parsedElement;
|
||||
}
|
||||
|
||||
visitAttribute(attribute: html.Attribute): t.TextAttribute {
|
||||
return new t.TextAttribute(
|
||||
attribute.name, attribute.value, attribute.sourceSpan, attribute.valueSpan);
|
||||
attribute.name, attribute.value, attribute.sourceSpan, attribute.valueSpan, attribute.i18n);
|
||||
}
|
||||
|
||||
visitText(text: html.Text): t.Node {
|
||||
const valueNoNgsp = replaceNgsp(text.value);
|
||||
const expr = this.bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan);
|
||||
return expr ? new t.BoundText(expr, text.sourceSpan) : new t.Text(valueNoNgsp, text.sourceSpan);
|
||||
return this._visitTextWithInterpolation(text.value, text.sourceSpan, text.i18n);
|
||||
}
|
||||
|
||||
visitComment(comment: html.Comment): null { return null; }
|
||||
|
||||
visitExpansion(expansion: html.Expansion): null { return null; }
|
||||
visitExpansion(expansion: html.Expansion): t.Icu|null {
|
||||
const meta = expansion.i18n as i18n.Message;
|
||||
// do not generate Icu in case it was created
|
||||
// outside of i18n block in a template
|
||||
if (!meta) {
|
||||
return null;
|
||||
}
|
||||
const vars: {[name: string]: t.BoundText} = {};
|
||||
const placeholders: {[name: string]: t.Text | t.BoundText} = {};
|
||||
// extract VARs from ICUs - we process them separately while
|
||||
// assembling resulting message via goog.getMsg function, since
|
||||
// we need to pass them to top-level goog.getMsg call
|
||||
Object.keys(meta.placeholders).forEach(key => {
|
||||
const value = meta.placeholders[key];
|
||||
if (key.startsWith(I18N_ICU_VAR_PREFIX)) {
|
||||
vars[key] =
|
||||
this._visitTextWithInterpolation(`{{${value}}}`, expansion.sourceSpan) as t.BoundText;
|
||||
} else {
|
||||
placeholders[key] = this._visitTextWithInterpolation(value, expansion.sourceSpan);
|
||||
}
|
||||
});
|
||||
return new t.Icu(vars, placeholders, expansion.sourceSpan, meta);
|
||||
}
|
||||
|
||||
visitExpansionCase(expansionCase: html.ExpansionCase): null { return null; }
|
||||
|
||||
visitComment(comment: html.Comment): null { return null; }
|
||||
|
||||
// convert view engine `ParsedProperty` to a format suitable for IVY
|
||||
private extractAttributes(elementName: string, properties: ParsedProperty[]):
|
||||
private extractAttributes(
|
||||
elementName: string, properties: ParsedProperty[], i18nPropsMeta: {[key: string]: i18n.AST}):
|
||||
{bound: t.BoundAttribute[], literal: t.TextAttribute[]} {
|
||||
const bound: t.BoundAttribute[] = [];
|
||||
const literal: t.TextAttribute[] = [];
|
||||
|
||||
properties.forEach(prop => {
|
||||
const i18n = i18nPropsMeta[prop.name];
|
||||
if (prop.isLiteral) {
|
||||
literal.push(new t.TextAttribute(prop.name, prop.expression.source || '', prop.sourceSpan));
|
||||
literal.push(new t.TextAttribute(
|
||||
prop.name, prop.expression.source || '', prop.sourceSpan, undefined, i18n));
|
||||
} else {
|
||||
const bep = this.bindingParser.createBoundElementProperty(elementName, prop);
|
||||
bound.push(t.BoundAttribute.fromBoundElementProperty(bep));
|
||||
bound.push(t.BoundAttribute.fromBoundElementProperty(bep, i18n));
|
||||
}
|
||||
});
|
||||
|
||||
@ -305,6 +333,13 @@ class HtmlAstToIvyAst implements html.Visitor {
|
||||
return hasBinding;
|
||||
}
|
||||
|
||||
private _visitTextWithInterpolation(value: string, sourceSpan: ParseSourceSpan, i18n?: i18n.AST):
|
||||
t.Text|t.BoundText {
|
||||
const valueNoNgsp = replaceNgsp(value);
|
||||
const expr = this.bindingParser.parseInterpolation(valueNoNgsp, sourceSpan);
|
||||
return expr ? new t.BoundText(expr, sourceSpan, i18n) : new t.Text(valueNoNgsp, sourceSpan);
|
||||
}
|
||||
|
||||
private parseVariable(
|
||||
identifier: string, value: string, sourceSpan: ParseSourceSpan, variables: t.Variable[]) {
|
||||
if (identifier.indexOf('-') > -1) {
|
||||
@ -360,7 +395,8 @@ class NonBindableVisitor implements html.Visitor {
|
||||
visitComment(comment: html.Comment): any { return null; }
|
||||
|
||||
visitAttribute(attribute: html.Attribute): t.TextAttribute {
|
||||
return new t.TextAttribute(attribute.name, attribute.value, attribute.sourceSpan);
|
||||
return new t.TextAttribute(
|
||||
attribute.name, attribute.value, attribute.sourceSpan, undefined, attribute.i18n);
|
||||
}
|
||||
|
||||
visitText(text: html.Text): t.Text { return new t.Text(text.value, text.sourceSpan); }
|
||||
|
Reference in New Issue
Block a user