From 9f135fcd3b10b66a4a84cb0d0968b1abffa4eb45 Mon Sep 17 00:00:00 2001 From: Zuri Klaschka Date: Tue, 25 Nov 2025 01:07:30 +0100 Subject: [PATCH 1/3] Fix incomplete string escaping Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- lib/common/escapeKey.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/common/escapeKey.ts b/lib/common/escapeKey.ts index 9ec7dc3..9b1591b 100644 --- a/lib/common/escapeKey.ts +++ b/lib/common/escapeKey.ts @@ -1,3 +1,6 @@ export function escapeKey(key: string): string { - return key.replaceAll(/{/g, "\\{"); + // Escape all backslashes first + key = key.replace(/\\/g, "\\\\"); + // Then escape curly braces + return key.replace(/[{]/g, "\\{"); } From 5fac8984976b542068160803a23a86996ef1c218 Mon Sep 17 00:00:00 2001 From: Zuri Klaschka Date: Tue, 25 Nov 2025 01:11:37 +0100 Subject: [PATCH 2/3] Fix escaping and unescaping strings with backslashes --- example/locales/de.json | 6 ++++-- example/locales/en.json | 6 ++++-- lib/common/unescapeKey.ts | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/example/locales/de.json b/example/locales/de.json index 41f071c..ef48982 100644 --- a/example/locales/de.json +++ b/example/locales/de.json @@ -1,6 +1,8 @@ { "Hello world!": "Hallo Welt!", "Lazy term": "Fauler Begriff", - "This text contains {0} \\{} curly braces and \\\\{\\{}}\\{0}.": "Dieser Text enthält {0} \\{} geschweifte Klammern und \\\\{\\{}}\\{0}.", - "Untranslated text": "" + "Untranslated text": "", + "Unknown Error": "", + "An unexpected error occurred while processing your request.": "", + "This text contains {0} \\{} curly braces and \\\\\\{\\{}}\\{0}.": "Dieser Text enthält {0} \\{} geschweifte Klammern und \\\\\\{\\{}}\\{0}." } diff --git a/example/locales/en.json b/example/locales/en.json index 0074bde..fce2376 100644 --- a/example/locales/en.json +++ b/example/locales/en.json @@ -1,6 +1,8 @@ { "Hello world!": "Hello world!", "Lazy term": "Lazy term", - "This text contains {0} \\{} curly braces and \\\\{\\{}}\\{0}.": "This text contains {0} \\{} curly braces and \\\\{\\{}}\\{0}.", - "Untranslated text": "Untranslated text" + "Untranslated text": "Untranslated text", + "Unknown Error": "Unknown Error", + "An unexpected error occurred while processing your request.": "An unexpected error occurred while processing your request.", + "This text contains {0} \\{} curly braces and \\\\\\{\\{}}\\{0}.": "This text contains {0} \\{} curly braces and \\\\\\{\\{}}\\{0}." } diff --git a/lib/common/unescapeKey.ts b/lib/common/unescapeKey.ts index 0946dca..c51a795 100644 --- a/lib/common/unescapeKey.ts +++ b/lib/common/unescapeKey.ts @@ -1,3 +1,3 @@ export function unescapeKey(key: string): string { - return key.replaceAll(/\\{/g, "{"); + return key.replaceAll(/\\{/g, "{").replaceAll(/\\\\/g, "\\"); } From 64980842c79b29575fb3f472d46bedec4e9c5006 Mon Sep 17 00:00:00 2001 From: Zuri Klaschka Date: Tue, 25 Nov 2025 01:18:10 +0100 Subject: [PATCH 3/3] Apply code quality suggesitions --- lib/extract/TypeScriptSourceFile.ts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/extract/TypeScriptSourceFile.ts b/lib/extract/TypeScriptSourceFile.ts index 6bb7bb4..46c65a3 100644 --- a/lib/extract/TypeScriptSourceFile.ts +++ b/lib/extract/TypeScriptSourceFile.ts @@ -64,7 +64,7 @@ export class TypeScriptSourceFile { this.processNode(this.getSourceFile(), extractions); } - private processNode(node: ts.Node, extractions = this.extractions) { + private processNode(node: ts.Node, extractions: Extractions) { if (TypeScriptSourceFile.isTemplateString(node)) { this.processTemplateString(node, this.getSourceFile(), extractions); } @@ -84,18 +84,17 @@ export class TypeScriptSourceFile { sourceFile: ts.SourceFile, extractions: Extractions, ) { - let templateString: string; - const tpl = node.template; - if (ts.isNoSubstitutionTemplateLiteral(tpl)) { - templateString = escapeKey(tpl.text); - } else if (ts.isTemplateExpression(tpl)) { - let templateParts = escapeKey(tpl.head.text); - tpl.templateSpans.forEach((span, index) => { - templateParts += "{" + index + "}" + escapeKey(span.literal.text); + let templateString = ""; + const template = node.template; + if (ts.isNoSubstitutionTemplateLiteral(template)) { + templateString = escapeKey(template.text); + } else if (ts.isTemplateExpression(template)) { + let combinedTemplateParts = escapeKey(template.head.text); + template.templateSpans.forEach((span, index) => { + combinedTemplateParts += "{" + index + "}" + + escapeKey(span.literal.text); }); - templateString = templateParts; - } else { - templateString = ""; + templateString = combinedTemplateParts; } const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); extractions.addExtraction(templateString, this.fileName, line + 1);