Files
ngx-translate-extract/src/parsers/directive.parser.ts
2020-03-31 12:24:57 +02:00

88 lines
2.8 KiB
TypeScript

import { ParserInterface } from './parser.interface';
import { TranslationCollection } from '../utils/translation.collection';
import { isPathAngularComponent, extractComponentInlineTemplate } from '../utils/utils';
import { parseTemplate, TmplAstNode, TmplAstElement, TmplAstTextAttribute } from '@angular/compiler';
export class DirectiveParser implements ParserInterface {
public extract(source: string, filePath: string): TranslationCollection | null {
if (filePath && isPathAngularComponent(filePath)) {
source = extractComponentInlineTemplate(source);
}
let collection: TranslationCollection = new TranslationCollection();
const nodes: TmplAstNode[] = this.parseTemplate(source, filePath);
this.getTranslatableElements(nodes).forEach((element) => {
const key = this.getElementTranslateAttrValue(element) || this.getElementContent(element);
collection = collection.add(key);
});
return collection;
}
protected getTranslatableElements(nodes: TmplAstNode[]): TmplAstElement[] {
return nodes
.filter((element) => this.isElement(element))
.reduce((result: TmplAstElement[], element: TmplAstElement) => {
return result.concat(this.findChildrenElements(element));
}, [])
.filter((element) => this.isTranslatable(element));
}
protected findChildrenElements(node: TmplAstNode): TmplAstElement[] {
if (!this.isElement(node)) {
return [];
}
// If element has translate attribute all its content is translatable
// so we don't need to traverse any deeper
if (this.isTranslatable(node)) {
return [node];
}
return node.children.reduce(
(result: TmplAstElement[], childNode: TmplAstNode) => {
if (this.isElement(childNode)) {
const children = this.findChildrenElements(childNode);
return result.concat(children);
}
return result;
},
[node]
);
}
protected parseTemplate(template: string, path: string): TmplAstNode[] {
return parseTemplate(template, path).nodes;
}
protected isElement(node: any): node is TmplAstElement {
return node?.attributes && node?.children;
}
protected isTranslatable(node: TmplAstNode): boolean {
if (this.isElement(node) && node.attributes.some((attribute) => attribute.name === 'translate')) {
return true;
}
return false;
}
protected getElementTranslateAttrValue(element: TmplAstElement): string {
const attr: TmplAstTextAttribute = element.attributes.find((attribute) => attribute.name === 'translate');
return attr?.value ?? '';
}
protected getElementContent(element: TmplAstElement): string {
const content = element.sourceSpan.start.file.content;
const start = element.startSourceSpan.end.offset;
const end = element.endSourceSpan.start.offset;
const val = content.substring(start, end);
return this.cleanKey(val);
}
protected cleanKey(val: string): string {
return val.replace(/\r?\n|\r|\t/g, '').trim();
}
}