UNPKG

@vendure/ngx-translate-extract

Version:
137 lines (136 loc) 5.96 kB
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; } }