@vendure/ngx-translate-extract
Version:
Extract strings from projects using ngx-translate
137 lines (136 loc) • 5.96 kB
JavaScript
import { ASTWithSource, Binary, BindingPipe, Conditional, Interpolation, LiteralArray, LiteralMap, LiteralPrimitive, parseTemplate, TmplAstElement as Element, TmplAstTemplate as Template, TmplAstText as Text, TmplAstIfBlock, TmplAstSwitchBlock, TmplAstForLoopBlock, TmplAstDeferredBlock, ParenthesizedExpression, } from '@angular/compiler';
import { getNodesFromSwitchBlockTmpl } from '../utils/ast-helpers.js';
import { TranslationCollection } from '../utils/translation.collection.js';
import { extractComponentInlineTemplate, isPathAngularComponent } from '../utils/utils.js';
export const TRANSLATE_ATTR_NAMES = ['translate', 'marker'];
export class DirectiveParser {
extract(source, filePath) {
let collection = new TranslationCollection();
if (filePath && isPathAngularComponent(filePath)) {
source = extractComponentInlineTemplate(source);
}
const nodes = this.parseTemplate(source, filePath);
const elements = this.getElementsWithTranslateAttribute(nodes);
elements.forEach((element) => {
const attribute = this.getAttribute(element, TRANSLATE_ATTR_NAMES);
if (attribute?.value) {
collection = collection.add(attribute.value, '', filePath);
return;
}
const boundAttribute = this.getBoundAttribute(element, TRANSLATE_ATTR_NAMES);
if (boundAttribute?.value) {
this.getLiteralPrimitives(boundAttribute.value).forEach((literalPrimitive) => {
collection = collection.add(literalPrimitive.value.toString(), '', filePath);
});
return;
}
const textNodes = this.getTextNodes(element);
textNodes.forEach((textNode) => {
collection = collection.add(textNode.value.trim(), '', filePath);
});
});
return collection;
}
getElementsWithTranslateAttribute(nodes) {
let elements = [];
nodes.filter(this.isElementLike).forEach((element) => {
if (this.hasAttributes(element, TRANSLATE_ATTR_NAMES)) {
elements = [...elements, element];
}
if (this.hasBoundAttribute(element, TRANSLATE_ATTR_NAMES)) {
elements = [...elements, element];
}
const childElements = this.getElementsWithTranslateAttribute(element.children);
if (childElements.length) {
elements = [...elements, ...childElements];
}
});
nodes.filter(this.isBlockNode).forEach((node) => elements.push(...this.getElementsWithTranslateAttributeFromBlockNodes(node)));
return elements;
}
getElementsWithTranslateAttributeFromBlockNodes(blockNode) {
let blockChildren = blockNode.children;
if (blockNode instanceof TmplAstIfBlock) {
blockChildren = blockNode.branches.map((branch) => branch.children).flat();
}
if (blockNode instanceof TmplAstSwitchBlock) {
blockChildren = getNodesFromSwitchBlockTmpl(blockNode);
}
if (blockNode instanceof TmplAstForLoopBlock) {
const emptyBlockChildren = blockNode.empty?.children ?? [];
blockChildren.push(...emptyBlockChildren);
}
if (blockNode instanceof TmplAstDeferredBlock) {
const placeholderBlockChildren = blockNode.placeholder?.children ?? [];
const loadingBlockChildren = blockNode.loading?.children ?? [];
const errorBlockChildren = blockNode.error?.children ?? [];
blockChildren.push(...placeholderBlockChildren, ...loadingBlockChildren, ...errorBlockChildren);
}
return this.getElementsWithTranslateAttribute(blockChildren);
}
getTextNodes(element) {
return element.children.filter(this.isText);
}
hasAttributes(element, name) {
return this.getAttribute(element, name) !== undefined;
}
getAttribute(element, names) {
return element.attributes.find((attribute) => names.includes(attribute.name));
}
hasBoundAttribute(element, names) {
return this.getBoundAttribute(element, names) !== undefined;
}
getBoundAttribute(element, names) {
return element.inputs.find((input) => !input.keySpan.details.startsWith('attr.') && names.includes(input.name));
}
getLiteralPrimitives(exp) {
if (exp instanceof LiteralPrimitive) {
return [exp];
}
let visit = [];
if (exp instanceof Interpolation) {
visit = exp.expressions;
}
else if (exp instanceof LiteralArray) {
visit = exp.expressions;
}
else if (exp instanceof LiteralMap) {
visit = exp.values;
}
else if (exp instanceof BindingPipe) {
visit = [exp.exp];
}
else if (exp instanceof Conditional) {
visit = [exp.trueExp, exp.falseExp];
}
else if (exp instanceof Binary) {
visit = [exp.left, exp.right];
}
else if (exp instanceof ASTWithSource) {
visit = [exp.ast];
}
else if (exp instanceof ParenthesizedExpression) {
visit = [exp.expression];
}
let results = [];
visit.forEach((child) => {
results = [...results, ...this.getLiteralPrimitives(child)];
});
return results;
}
isElementLike(node) {
return node instanceof Element || node instanceof Template;
}
isBlockNode(node) {
return (Object.hasOwn(node, 'nameSpan') &&
Object.hasOwn(node, 'sourceSpan') &&
Object.hasOwn(node, 'startSourceSpan') &&
Object.hasOwn(node, 'endSourceSpan'));
}
isText(node) {
return node instanceof Text;
}
parseTemplate(template, path) {
return parseTemplate(template, path).nodes;
}
}