feat(i18n): support implicit tags/attributes
This commit is contained in:
parent
75e6dfb9ab
commit
3e5716ec16
@ -1,5 +1,5 @@
|
|||||||
import {StringWrapper, NumberWrapper, isPresent, isBlank, serializeEnum} from '../src/facade/lang';
|
import {StringWrapper, NumberWrapper, isPresent, isBlank} from './facade/lang';
|
||||||
import {ListWrapper} from '../src/facade/collection';
|
import {ListWrapper} from './facade/collection';
|
||||||
import {ParseLocation, ParseError, ParseSourceFile, ParseSourceSpan} from './parse_util';
|
import {ParseLocation, ParseError, ParseSourceFile, ParseSourceSpan} from './parse_util';
|
||||||
import {getHtmlTagDefinition, HtmlTagContentType, NAMED_ENTITIES} from './html_tags';
|
import {getHtmlTagDefinition, HtmlTagContentType, NAMED_ENTITIES} from './html_tags';
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {HtmlParser, HtmlParseTreeResult} from '../html_parser';
|
import {HtmlParser, HtmlParseTreeResult} from "../html_parser";
|
||||||
import {ParseSourceSpan, ParseError} from '../parse_util';
|
import {ParseSourceSpan, ParseError} from "../parse_util";
|
||||||
import {
|
import {
|
||||||
HtmlAst,
|
HtmlAst,
|
||||||
HtmlAstVisitor,
|
HtmlAstVisitor,
|
||||||
@ -10,31 +10,28 @@ import {
|
|||||||
HtmlExpansionAst,
|
HtmlExpansionAst,
|
||||||
HtmlExpansionCaseAst,
|
HtmlExpansionCaseAst,
|
||||||
htmlVisitAll
|
htmlVisitAll
|
||||||
} from '../html_ast';
|
} from "../html_ast";
|
||||||
import {ListWrapper, StringMapWrapper} from '../../src/facade/collection';
|
import {ListWrapper, StringMapWrapper} from "../facade/collection";
|
||||||
import {RegExpWrapper, NumberWrapper, isPresent} from '../../src/facade/lang';
|
import {RegExpWrapper, NumberWrapper, isPresent} from "../facade/lang";
|
||||||
import {BaseException} from '../../src/facade/exceptions';
|
import {BaseException} from "../facade/exceptions";
|
||||||
import {Parser} from '../expression_parser/parser';
|
import {Parser} from "../expression_parser/parser";
|
||||||
import {id} from './message';
|
import {id} from "./message";
|
||||||
import {expandNodes} from './expander';
|
import {expandNodes} from "./expander";
|
||||||
import {
|
import {
|
||||||
messageFromAttribute,
|
messageFromI18nAttribute,
|
||||||
I18nError,
|
I18nError,
|
||||||
I18N_ATTR_PREFIX,
|
I18N_ATTR_PREFIX,
|
||||||
I18N_ATTR,
|
I18N_ATTR,
|
||||||
partition,
|
partition,
|
||||||
Part,
|
Part,
|
||||||
stringifyNodes,
|
|
||||||
meaning,
|
|
||||||
getPhNameFromBinding,
|
getPhNameFromBinding,
|
||||||
dedupePhName
|
dedupePhName,
|
||||||
} from './shared';
|
messageFromAttribute
|
||||||
|
} from "./shared";
|
||||||
|
|
||||||
const _I18N_ATTR = "i18n";
|
|
||||||
const _PLACEHOLDER_ELEMENT = "ph";
|
const _PLACEHOLDER_ELEMENT = "ph";
|
||||||
const _NAME_ATTR = "name";
|
const _NAME_ATTR = "name";
|
||||||
const _I18N_ATTR_PREFIX = "i18n-";
|
let _PLACEHOLDER_EXPANDED_REGEXP = /<ph(\s)+name=("(\w)+")><\/ph>/gi;
|
||||||
let _PLACEHOLDER_EXPANDED_REGEXP = RegExpWrapper.create(`\\<ph(\\s)+name=("(\\w)+")\\>\\<\\/ph\\>`);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an i18n-ed version of the parsed template.
|
* Creates an i18n-ed version of the parsed template.
|
||||||
@ -120,13 +117,15 @@ export class I18nHtmlParser implements HtmlParser {
|
|||||||
errors: ParseError[];
|
errors: ParseError[];
|
||||||
|
|
||||||
constructor(private _htmlParser: HtmlParser, private _parser: Parser,
|
constructor(private _htmlParser: HtmlParser, private _parser: Parser,
|
||||||
private _messagesContent: string, private _messages: {[key: string]: HtmlAst[]}) {}
|
private _messagesContent: string, private _messages: {[key: string]: HtmlAst[]},
|
||||||
|
private _implicitTags: string[], private _implicitAttrs: {[k: string]: string[]}) {}
|
||||||
|
|
||||||
parse(sourceContent: string, sourceUrl: string,
|
parse(sourceContent: string, sourceUrl: string,
|
||||||
parseExpansionForms: boolean = false): HtmlParseTreeResult {
|
parseExpansionForms: boolean = false): HtmlParseTreeResult {
|
||||||
this.errors = [];
|
this.errors = [];
|
||||||
|
|
||||||
let res = this._htmlParser.parse(sourceContent, sourceUrl, true);
|
let res = this._htmlParser.parse(sourceContent, sourceUrl, true);
|
||||||
|
|
||||||
if (res.errors.length > 0) {
|
if (res.errors.length > 0) {
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
@ -184,7 +183,7 @@ export class I18nHtmlParser implements HtmlParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _recurse(nodes: HtmlAst[]): HtmlAst[] {
|
private _recurse(nodes: HtmlAst[]): HtmlAst[] {
|
||||||
let ps = partition(nodes, this.errors);
|
let ps = partition(nodes, this.errors, this._implicitTags);
|
||||||
return ListWrapper.flatten(ps.map(p => this._processI18nPart(p)));
|
return ListWrapper.flatten(ps.map(p => this._processI18nPart(p)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,17 +280,26 @@ export class I18nHtmlParser implements HtmlParser {
|
|||||||
|
|
||||||
private _i18nAttributes(el: HtmlElementAst): HtmlAttrAst[] {
|
private _i18nAttributes(el: HtmlElementAst): HtmlAttrAst[] {
|
||||||
let res = [];
|
let res = [];
|
||||||
|
let implicitAttrs: string[] =
|
||||||
|
isPresent(this._implicitAttrs[el.name]) ? this._implicitAttrs[el.name] : [];
|
||||||
|
|
||||||
el.attrs.forEach(attr => {
|
el.attrs.forEach(attr => {
|
||||||
if (attr.name.startsWith(I18N_ATTR_PREFIX) || attr.name == I18N_ATTR) return;
|
if (attr.name.startsWith(I18N_ATTR_PREFIX) || attr.name == I18N_ATTR) return;
|
||||||
|
|
||||||
let i18ns = el.attrs.filter(a => a.name == `i18n-${attr.name}`);
|
let message;
|
||||||
|
|
||||||
|
let i18ns = el.attrs.filter(a => a.name == `${I18N_ATTR_PREFIX}${attr.name}`);
|
||||||
|
|
||||||
if (i18ns.length == 0) {
|
if (i18ns.length == 0) {
|
||||||
res.push(attr);
|
if (implicitAttrs.indexOf(attr.name) == -1) {
|
||||||
return;
|
res.push(attr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
message = messageFromAttribute(this._parser, attr);
|
||||||
|
} else {
|
||||||
|
message = messageFromI18nAttribute(this._parser, el, i18ns[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let i18n = i18ns[0];
|
|
||||||
let message = messageFromAttribute(this._parser, el, i18n);
|
|
||||||
let messageId = id(message);
|
let messageId = id(message);
|
||||||
|
|
||||||
if (StringMapWrapper.contains(this._messages, messageId)) {
|
if (StringMapWrapper.contains(this._messages, messageId)) {
|
||||||
|
@ -1,29 +1,19 @@
|
|||||||
import {HtmlParser} from '../html_parser';
|
import {HtmlParser} from "../html_parser";
|
||||||
import {ParseSourceSpan, ParseError} from '../parse_util';
|
import {ParseError} from "../parse_util";
|
||||||
import {
|
import {HtmlAst, HtmlElementAst} from "../html_ast";
|
||||||
HtmlAst,
|
import {isPresent} from "../facade/lang";
|
||||||
HtmlAstVisitor,
|
import {StringMapWrapper} from "../facade/collection";
|
||||||
HtmlElementAst,
|
import {Parser} from "../expression_parser/parser";
|
||||||
HtmlAttrAst,
|
import {Message, id} from "./message";
|
||||||
HtmlTextAst,
|
import {expandNodes} from "./expander";
|
||||||
HtmlCommentAst,
|
|
||||||
htmlVisitAll
|
|
||||||
} from '../html_ast';
|
|
||||||
import {isPresent} from '../../src/facade/lang';
|
|
||||||
import {StringMapWrapper} from '../../src/facade/collection';
|
|
||||||
import {Parser} from '../expression_parser/parser';
|
|
||||||
import {Message, id} from './message';
|
|
||||||
import {expandNodes} from './expander';
|
|
||||||
import {
|
import {
|
||||||
I18nError,
|
I18nError,
|
||||||
Part,
|
Part,
|
||||||
I18N_ATTR_PREFIX,
|
I18N_ATTR_PREFIX,
|
||||||
partition,
|
partition,
|
||||||
meaning,
|
messageFromI18nAttribute,
|
||||||
description,
|
|
||||||
stringifyNodes,
|
|
||||||
messageFromAttribute
|
messageFromAttribute
|
||||||
} from './shared';
|
} from "./shared";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All messages extracted from a template.
|
* All messages extracted from a template.
|
||||||
@ -116,7 +106,8 @@ export class MessageExtractor {
|
|||||||
messages: Message[];
|
messages: Message[];
|
||||||
errors: ParseError[];
|
errors: ParseError[];
|
||||||
|
|
||||||
constructor(private _htmlParser: HtmlParser, private _parser: Parser) {}
|
constructor(private _htmlParser: HtmlParser, private _parser: Parser,
|
||||||
|
private _implicitTags: string[], private _implicitAttrs: {[k: string]: string[]}) {}
|
||||||
|
|
||||||
extract(template: string, sourceUrl: string): ExtractionResult {
|
extract(template: string, sourceUrl: string): ExtractionResult {
|
||||||
this.messages = [];
|
this.messages = [];
|
||||||
@ -146,7 +137,7 @@ export class MessageExtractor {
|
|||||||
|
|
||||||
private _recurse(nodes: HtmlAst[]): void {
|
private _recurse(nodes: HtmlAst[]): void {
|
||||||
if (isPresent(nodes)) {
|
if (isPresent(nodes)) {
|
||||||
let ps = partition(nodes, this.errors);
|
let ps = partition(nodes, this.errors, this._implicitTags);
|
||||||
ps.forEach(p => this._extractMessagesFromPart(p));
|
ps.forEach(p => this._extractMessagesFromPart(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,10 +152,15 @@ export class MessageExtractor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _extractMessagesFromAttributes(p: HtmlElementAst): void {
|
private _extractMessagesFromAttributes(p: HtmlElementAst): void {
|
||||||
|
let transAttrs: string[] =
|
||||||
|
isPresent(this._implicitAttrs[p.name]) ? this._implicitAttrs[p.name] : [];
|
||||||
|
let explicitAttrs: string[] = [];
|
||||||
|
|
||||||
p.attrs.forEach(attr => {
|
p.attrs.forEach(attr => {
|
||||||
if (attr.name.startsWith(I18N_ATTR_PREFIX)) {
|
if (attr.name.startsWith(I18N_ATTR_PREFIX)) {
|
||||||
try {
|
try {
|
||||||
this.messages.push(messageFromAttribute(this._parser, p, attr));
|
explicitAttrs.push(attr.name.substring(I18N_ATTR_PREFIX.length));
|
||||||
|
this.messages.push(messageFromI18nAttribute(this._parser, p, attr));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof I18nError) {
|
if (e instanceof I18nError) {
|
||||||
this.errors.push(e);
|
this.errors.push(e);
|
||||||
@ -174,5 +170,10 @@ export class MessageExtractor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
p.attrs.filter(attr => !attr.name.startsWith(I18N_ATTR_PREFIX))
|
||||||
|
.filter(attr => explicitAttrs.indexOf(attr.name) == -1)
|
||||||
|
.filter(attr => transAttrs.indexOf(attr.name) > -1)
|
||||||
|
.forEach(attr => this.messages.push(messageFromAttribute(this._parser, attr)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ export class I18nError extends ParseError {
|
|||||||
|
|
||||||
|
|
||||||
// Man, this is so ugly!
|
// Man, this is so ugly!
|
||||||
export function partition(nodes: HtmlAst[], errors: ParseError[]): Part[] {
|
export function partition(nodes: HtmlAst[], errors: ParseError[], implicitTags: string[]): Part[] {
|
||||||
let res = [];
|
let res = [];
|
||||||
|
|
||||||
for (let i = 0; i < nodes.length; ++i) {
|
for (let i = 0; i < nodes.length; ++i) {
|
||||||
@ -47,7 +47,8 @@ export function partition(nodes: HtmlAst[], errors: ParseError[]): Part[] {
|
|||||||
|
|
||||||
} else if (n instanceof HtmlElementAst) {
|
} else if (n instanceof HtmlElementAst) {
|
||||||
let i18n = _findI18nAttr(n);
|
let i18n = _findI18nAttr(n);
|
||||||
res.push(new Part(n, null, n.children, isPresent(i18n) ? i18n.value : null, isPresent(i18n)));
|
let hasI18n: boolean = isPresent(i18n) || implicitTags.indexOf(n.name) > -1;
|
||||||
|
res.push(new Part(n, null, n.children, isPresent(i18n) ? i18n.value : null, hasI18n));
|
||||||
} else if (n instanceof HtmlTextAst) {
|
} else if (n instanceof HtmlTextAst) {
|
||||||
res.push(new Part(null, n, null, null, false));
|
res.push(new Part(null, n, null, null, false));
|
||||||
}
|
}
|
||||||
@ -99,17 +100,28 @@ export function description(i18n: string): string {
|
|||||||
return parts.length > 1 ? parts[1] : null;
|
return parts.length > 1 ? parts[1] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function messageFromAttribute(parser: Parser, p: HtmlElementAst,
|
/**
|
||||||
attr: HtmlAttrAst): Message {
|
* Extract a translation string given an `i18n-` prefixed attribute.
|
||||||
let expectedName = attr.name.substring(5);
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function messageFromI18nAttribute(parser: Parser, p: HtmlElementAst,
|
||||||
|
i18nAttr: HtmlAttrAst): Message {
|
||||||
|
let expectedName = i18nAttr.name.substring(5);
|
||||||
let matching = p.attrs.filter(a => a.name == expectedName);
|
let matching = p.attrs.filter(a => a.name == expectedName);
|
||||||
|
|
||||||
if (matching.length > 0) {
|
if (matching.length > 0) {
|
||||||
let value = removeInterpolation(matching[0].value, matching[0].sourceSpan, parser);
|
return messageFromAttribute(parser, matching[0], meaning(i18nAttr.value),
|
||||||
return new Message(value, meaning(attr.value), description(attr.value));
|
description(i18nAttr.value));
|
||||||
} else {
|
|
||||||
throw new I18nError(p.sourceSpan, `Missing attribute '${expectedName}'.`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new I18nError(p.sourceSpan, `Missing attribute '${expectedName}'.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function messageFromAttribute(parser: Parser, attr: HtmlAttrAst, meaning: string = null,
|
||||||
|
description: string = null): Message {
|
||||||
|
let value = removeInterpolation(attr.value, attr.sourceSpan, parser);
|
||||||
|
return new Message(value, meaning, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeInterpolation(value: string, source: ParseSourceSpan,
|
export function removeInterpolation(value: string, source: ParseSourceSpan,
|
||||||
|
@ -1,38 +1,19 @@
|
|||||||
import {
|
import {describe, expect, it, iit, ddescribe} from "@angular/core/testing/testing_internal";
|
||||||
beforeEach,
|
import {I18nHtmlParser} from "@angular/compiler/src/i18n/i18n_html_parser";
|
||||||
ddescribe,
|
import {Message, id} from "@angular/compiler/src/i18n/message";
|
||||||
describe,
|
import {Parser} from "@angular/compiler/src/expression_parser/parser";
|
||||||
expect,
|
import {Lexer} from "@angular/compiler/src/expression_parser/lexer";
|
||||||
iit,
|
import {StringMapWrapper} from "../../src/facade/collection";
|
||||||
inject,
|
import {HtmlParser, HtmlParseTreeResult} from "@angular/compiler/src/html_parser";
|
||||||
it,
|
import {HtmlElementAst, HtmlAttrAst, HtmlTextAst} from "@angular/compiler/src/html_ast";
|
||||||
xdescribe,
|
import {deserializeXmb} from "@angular/compiler/src/i18n/xmb_serializer";
|
||||||
xit
|
import {ParseError} from "@angular/compiler/src/parse_util";
|
||||||
} from '@angular/core/testing/testing_internal';
|
import {humanizeDom} from "@angular/compiler/test/html_ast_spec_utils";
|
||||||
|
|
||||||
import {I18nHtmlParser} from '@angular/compiler/src/i18n/i18n_html_parser';
|
|
||||||
import {Message, id} from '@angular/compiler/src/i18n/message';
|
|
||||||
import {Parser} from '@angular/compiler/src/expression_parser/parser';
|
|
||||||
import {Lexer} from '@angular/compiler/src/expression_parser/lexer';
|
|
||||||
|
|
||||||
import {StringMapWrapper} from '../../src/facade/collection';
|
|
||||||
import {HtmlParser, HtmlParseTreeResult} from '@angular/compiler/src/html_parser';
|
|
||||||
import {
|
|
||||||
HtmlAst,
|
|
||||||
HtmlAstVisitor,
|
|
||||||
HtmlElementAst,
|
|
||||||
HtmlAttrAst,
|
|
||||||
HtmlTextAst,
|
|
||||||
HtmlCommentAst,
|
|
||||||
htmlVisitAll
|
|
||||||
} from '@angular/compiler/src/html_ast';
|
|
||||||
import {serializeXmb, deserializeXmb} from '@angular/compiler/src/i18n/xmb_serializer';
|
|
||||||
import {ParseError, ParseLocation} from '@angular/compiler/src/parse_util';
|
|
||||||
import {humanizeDom} from '@angular/compiler/test/html_ast_spec_utils';
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('I18nHtmlParser', () => {
|
describe('I18nHtmlParser', () => {
|
||||||
function parse(template: string, messages: {[key: string]: string}): HtmlParseTreeResult {
|
function parse(template: string, messages: {[key: string]: string}, implicitTags: string[] = [],
|
||||||
|
implicitAttrs: {[k: string]: string[]} = {}): HtmlParseTreeResult {
|
||||||
var parser = new Parser(new Lexer());
|
var parser = new Parser(new Lexer());
|
||||||
let htmlParser = new HtmlParser();
|
let htmlParser = new HtmlParser();
|
||||||
|
|
||||||
@ -40,7 +21,8 @@ export function main() {
|
|||||||
StringMapWrapper.forEach(messages, (v, k) => msgs += `<msg id="${k}">${v}</msg>`);
|
StringMapWrapper.forEach(messages, (v, k) => msgs += `<msg id="${k}">${v}</msg>`);
|
||||||
let res = deserializeXmb(`<message-bundle>${msgs}</message-bundle>`, 'someUrl');
|
let res = deserializeXmb(`<message-bundle>${msgs}</message-bundle>`, 'someUrl');
|
||||||
|
|
||||||
return new I18nHtmlParser(htmlParser, parser, res.content, res.messages)
|
return new I18nHtmlParser(htmlParser, parser, res.content, res.messages, implicitTags,
|
||||||
|
implicitAttrs)
|
||||||
.parse(template, "someurl", true);
|
.parse(template, "someurl", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,6 +313,44 @@ export function main() {
|
|||||||
.toEqual(["Invalid interpolation name '99'"]);
|
.toEqual(["Invalid interpolation name '99'"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('implicit translation', () => {
|
||||||
|
it("should support attributes", () => {
|
||||||
|
let translations: {[key: string]: string} = {};
|
||||||
|
translations[id(new Message("some message", null, null))] = "another message";
|
||||||
|
|
||||||
|
expect(humanizeDom(parse("<i18n-el value='some message'></i18n-el>", translations, [],
|
||||||
|
{'i18n-el': ['value']})))
|
||||||
|
.toEqual([[HtmlElementAst, 'i18n-el', 0], [HtmlAttrAst, 'value', 'another message']]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should support attributes with meaning and description", () => {
|
||||||
|
let translations: {[key: string]: string} = {};
|
||||||
|
translations[id(new Message("some message", "meaning", "description"))] =
|
||||||
|
"another message";
|
||||||
|
|
||||||
|
expect(humanizeDom(parse(
|
||||||
|
"<i18n-el value='some message' i18n-value='meaning|description'></i18n-el>",
|
||||||
|
translations, [], {'i18n-el': ['value']})))
|
||||||
|
.toEqual([[HtmlElementAst, 'i18n-el', 0], [HtmlAttrAst, 'value', 'another message']]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should support elements", () => {
|
||||||
|
let translations: {[key: string]: string} = {};
|
||||||
|
translations[id(new Message("message", null, null))] = "another message";
|
||||||
|
|
||||||
|
expect(humanizeDom(parse("<i18n-el>message</i18n-el>", translations, ['i18n-el'])))
|
||||||
|
.toEqual([[HtmlElementAst, 'i18n-el', 0], [HtmlTextAst, 'another message', 1]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should support elements with meaning and description", () => {
|
||||||
|
let translations: {[key: string]: string} = {};
|
||||||
|
translations[id(new Message("message", "meaning", "description"))] = "another message";
|
||||||
|
|
||||||
|
expect(humanizeDom(parse("<i18n-el i18n='meaning|description'>message</i18n-el>",
|
||||||
|
translations, ['i18n-el'])))
|
||||||
|
.toEqual([[HtmlElementAst, 'i18n-el', 0], [HtmlTextAst, 'another message', 1]]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ export function main() {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
let htmlParser = new HtmlParser();
|
let htmlParser = new HtmlParser();
|
||||||
var parser = new Parser(new Lexer());
|
var parser = new Parser(new Lexer());
|
||||||
extractor = new MessageExtractor(htmlParser, parser);
|
extractor = new MessageExtractor(htmlParser, parser, ['i18n-tag'], {'i18n-el': ['trans']});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should extract from elements with the i18n attr', () => {
|
it('should extract from elements with the i18n attr', () => {
|
||||||
@ -205,6 +205,30 @@ export function main() {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('implicit translation', () => {
|
||||||
|
it('should extract from elements', () => {
|
||||||
|
let res = extractor.extract("<i18n-tag>message</i18n-tag>", "someurl");
|
||||||
|
expect(res.messages).toEqual([new Message("message", null, null)]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should extract meaning and description from elements when present', () => {
|
||||||
|
let res =
|
||||||
|
extractor.extract("<i18n-tag i18n='meaning|description'>message</i18n-tag>", "someurl");
|
||||||
|
expect(res.messages).toEqual([new Message("message", "meaning", "description")]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should extract from attributes', () => {
|
||||||
|
let res = extractor.extract(`<i18n-el trans='message'></i18n-el>`, "someurl");
|
||||||
|
expect(res.messages).toEqual([new Message("message", null, null)]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should extract meaning and description from attributes when present', () => {
|
||||||
|
let res = extractor.extract(`<i18n-el trans='message' i18n-trans="meaning|desc"></i18n-el>`,
|
||||||
|
"someurl");
|
||||||
|
expect(res.messages).toEqual([new Message("message", "meaning", "desc")]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("errors", () => {
|
describe("errors", () => {
|
||||||
it('should error on i18n attributes without matching "real" attributes', () => {
|
it('should error on i18n attributes without matching "real" attributes', () => {
|
||||||
let res = extractor.extract(`
|
let res = extractor.extract(`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user