@vendure/ngx-translate-extract
Version:
Extract strings from projects using ngx-translate
154 lines (153 loc) • 6.33 kB
JavaScript
import { parseTemplate, BindingPipe, LiteralPrimitive, Conditional, Binary, LiteralMap, LiteralArray, Interpolation, Call, TmplAstIfBlock, TmplAstSwitchBlock, TmplAstDeferredBlock, TmplAstForLoopBlock, KeyedRead, ASTWithSource, ParenthesizedExpression, } from '@angular/compiler';
import { getNodesFromSwitchBlockTmpl } from '../utils/ast-helpers.js';
import { TranslationCollection } from '../utils/translation.collection.js';
import { isPathAngularComponent, extractComponentInlineTemplate } from '../utils/utils.js';
export const TRANSLATE_PIPE_NAMES = ['translate', 'marker'];
function traverseAstNodes(nodes, visitor, accumulator = []) {
for (const node of nodes) {
if (node) {
traverseAstNode(node, visitor, accumulator);
}
}
return accumulator;
}
function traverseAstNode(node, visitor, accumulator = []) {
accumulator.push(...visitor(node));
const children = [];
if ('children' in node && node.children) {
children.push(...node.children);
}
if (node instanceof TmplAstForLoopBlock) {
children.push(node.empty);
}
if (node instanceof TmplAstDeferredBlock) {
children.push(node.error);
children.push(node.loading);
children.push(node.placeholder);
}
if (node instanceof TmplAstIfBlock) {
children.push(...node.branches.flatMap((inner) => inner.children));
}
if (node instanceof TmplAstSwitchBlock) {
const blockChildren = getNodesFromSwitchBlockTmpl(node);
children.push(...blockChildren);
}
return traverseAstNodes(children, visitor, accumulator);
}
export class PipeParser {
extract(source, filePath) {
if (filePath && isPathAngularComponent(filePath)) {
source = extractComponentInlineTemplate(source);
}
let collection = new TranslationCollection();
const nodes = this.parseTemplate(source, filePath);
const pipes = traverseAstNodes(nodes, (node) => this.findPipesInNode(node));
pipes.forEach((pipe) => {
this.parseTranslationKeysFromPipe(pipe).forEach((key) => {
if (key === '') {
return;
}
collection = collection.add(key, '', filePath);
});
});
return collection;
}
findPipesInNode(node) {
const ret = [];
if ('value' in node && node.value instanceof ASTWithSource) {
ret.push(...this.getTranslatablesFromAst(node.value.ast));
}
if ('attributes' in node && Array.isArray(node.attributes)) {
const translatableAttributes = node.attributes.filter((attr) => TRANSLATE_PIPE_NAMES.includes(attr.name));
ret.push(...ret, ...translatableAttributes);
}
if ('inputs' in node && Array.isArray(node.inputs)) {
node.inputs.forEach((input) => {
if (input.value instanceof ASTWithSource) {
ret.push(...this.getTranslatablesFromAst(input.value.ast));
}
});
}
if ('templateAttrs' in node && Array.isArray(node.templateAttrs)) {
node.templateAttrs.forEach((attr) => {
if (attr.value instanceof ASTWithSource) {
ret.push(...this.getTranslatablesFromAst(attr.value.ast));
}
});
}
return ret;
}
parseTranslationKeysFromPipe(pipeContent) {
const ret = [];
if (pipeContent instanceof LiteralPrimitive) {
ret.push(`${pipeContent.value}`);
}
else if (pipeContent instanceof Conditional) {
ret.push(...this.parseTranslationKeysFromPipe(pipeContent.trueExp));
ret.push(...this.parseTranslationKeysFromPipe(pipeContent.falseExp));
}
else if (pipeContent instanceof BindingPipe) {
ret.push(...this.parseTranslationKeysFromPipe(pipeContent.exp));
}
else if (pipeContent instanceof ParenthesizedExpression) {
ret.push(...this.parseTranslationKeysFromPipe(pipeContent.expression));
}
else if (this.isLogicalOrNullishCoalescingExpression(pipeContent)) {
if (pipeContent.left instanceof LiteralPrimitive) {
ret.push(`${pipeContent.left.value}`);
}
if (pipeContent.right instanceof LiteralPrimitive) {
ret.push(`${pipeContent.right.value}`);
}
}
return ret;
}
getTranslatablesFromAst(ast) {
if (ast instanceof BindingPipe) {
if (TRANSLATE_PIPE_NAMES.includes(ast.name)) {
return [ast, ...this.getTranslatablesFromAsts(ast.args)];
}
return this.getTranslatablesFromAsts([ast.exp, ...ast.args]);
}
if (ast instanceof Interpolation) {
return this.getTranslatablesFromAsts(ast.expressions);
}
if (ast instanceof Conditional) {
return this.getTranslatablesFromAsts([ast.trueExp, ast.falseExp]);
}
if (ast instanceof Binary) {
if (ast?.left && ast?.right) {
return this.getTranslatablesFromAsts([ast.left, ast.right]);
}
}
if (ast instanceof LiteralMap) {
return this.getTranslatablesFromAsts(ast.values);
}
if (ast instanceof LiteralArray) {
return this.getTranslatablesFromAsts(ast.expressions);
}
if (ast instanceof Call) {
return this.getTranslatablesFromAsts(ast.args);
}
if (ast instanceof KeyedRead) {
return this.getTranslatablesFromAsts([ast.receiver, ast.key]);
}
if (ast instanceof ParenthesizedExpression) {
return this.getTranslatablesFromAsts([ast.expression]);
}
return [];
}
getTranslatablesFromAsts(asts) {
return this.flatten(asts.map((ast) => this.getTranslatablesFromAst(ast)));
}
flatten(array) {
return [].concat(...array);
}
parseTemplate(template, path) {
return parseTemplate(template, path).nodes;
}
isLogicalOrNullishCoalescingExpression(expr) {
return (expr instanceof Binary &&
(expr.operation === '&&' || expr.operation === '||' || expr.operation === '??'));
}
}