Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 45 additions & 14 deletions src/parser/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export function doTree(
}

// The arguments are the last child
const argsNode = node.lastChild;
const argsNode = node.childForFieldName("arguments");
if (
argsNode === null ||
argsNode.childCount === 0 ||
Expand All @@ -164,12 +164,8 @@ export function doTree(
return;
}

// Get the whole gettext translation string
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_fn, raw] = node.children;

// Safety check: verify we actually have an arguments node
if (!raw) return;
if (!argsNode) return;

const translation: Partial<{
msgctxt: string;
Expand All @@ -186,23 +182,58 @@ export function doTree(
const translationKeys =
i18nFunctions[functionName as keyof typeof i18nFunctions];

// Slice the children to skip the opening and closing parentheses/brackets
const children = raw.children.slice(1, -1);
// Slice the children to skip the opening and closing parentheses/brackets or process them directly
// We iterate over all children and handle them based on type
const children = argsNode.children;
let translationKeyIndex = 0;

// Get the translation from the arguments
for (const child of children) {
let node = child;

// Skip parentheses and commas
if (
node.type === "(" ||
node.type === ")" ||
node.type === "," ||
node.type === "[" ||
node.type === "]"
) {
continue;
}

// Skip comments
if (node.type === "comment") {
continue;
}

// unwrap the argument node, which is used in PHP.
if (child.type === "argument") {
if (child.children.length === 0) continue;
node = child.children[0];
}

if (node?.type === ",") {
// skip the comma between arguments
continue;
// Check if this is a named argument
const nameNode = child.childForFieldName("name");

// Iterate over children to find the value
// The value is the child that is NOT the name node, not a comment, and not punctuation.
let foundValue = false;
for (const argChild of child.children) {
if (argChild.id === nameNode?.id) {
continue; // Skip the name label
}
if (argChild.type === "comment" || argChild.type === ":") {
continue; // Skip comments and colon
}
// Found the value!
node = argChild;
foundValue = true;
break;
}

// If we didn't find a value (e.g. only comments?), skip this argument
if (!foundValue) {
continue;
}
}

// Stop if we have more arguments than keys defined
Expand All @@ -213,7 +244,7 @@ export function doTree(
// the translation key (eg. msgid)
const currentKey = translationKeys[
translationKeyIndex
] as keyof typeof translation;
] as keyof typeof translation;

// Resolve the value using our new function (handles quotes and escapes)
let nodeValue: string = resolveStringValue(node);
Expand Down