Skip to content

Commit 9598107

Browse files
committed
fix(machinery): do not interpret replacement string for placeholders
Avoid interpreting escape characters in the replacement string. Fixes #17048
1 parent 7dfa726 commit 9598107

File tree

3 files changed

+61
-1
lines changed

3 files changed

+61
-1
lines changed

weblate/machinery/base.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,9 +368,16 @@ def cleanup_text(self, text: str, unit: Unit) -> tuple[str, dict[str, str]]:
368368

369369
return "".join(parts), replacements
370370

371+
def uncleanup_text_item(self, text: str, source: str, target: str) -> str:
372+
def replace_target(_match: re.Match) -> str:
373+
return target
374+
375+
# Use callable for replacement to avoid interpreting escape sequences
376+
return re.sub(self.make_re_placeholder(source), replace_target, text)
377+
371378
def uncleanup_text(self, replacements: dict[str, str], text: str) -> str:
372379
for source, target in replacements.items():
373-
text = re.sub(self.make_re_placeholder(source), target, text)
380+
text = self.uncleanup_text_item(text, source, target)
374381
return self.unescape_text(text)
375382

376383
def uncleanup_results(

weblate/machinery/dummy.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ def download_translations(
7171
"service": "Dummy",
7272
"source": text,
7373
}
74+
if source_language == "en" and text.strip() == r"Hello, [X7X] C:\Windows!":
75+
yield {
76+
"text": r"Nazdar [X7X ] C:\Windows!",
77+
"quality": self.max_score,
78+
"service": "Dummy",
79+
"source": text,
80+
}
7481

7582

7683
class DummyGlossaryTranslation(DummyTranslation, GlossaryMachineTranslationMixin):

weblate/machinery/tests.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,52 @@ def test_placeholders(self) -> None:
446446
],
447447
)
448448

449+
def test_placeholders_backslash(self) -> None:
450+
machine_translation = self.get_machine()
451+
unit = MockUnit(code="cs", source=r"Hello, %s C:\Windows!", flags="c-format")
452+
self.assertEqual(
453+
machine_translation.cleanup_text(unit.source, unit),
454+
(r"Hello, [X7X] C:\Windows!", {"[X7X]": "%s"}),
455+
)
456+
self.assertEqual(
457+
machine_translation.translate(unit),
458+
[
459+
[
460+
{
461+
"quality": 100,
462+
"service": "Dummy",
463+
"source": r"Hello, %s C:\Windows!",
464+
"original_source": r"Hello, %s C:\Windows!",
465+
"text": r"Nazdar %s C:\Windows!",
466+
}
467+
]
468+
],
469+
)
470+
471+
def test_placeholders_rst(self) -> None:
472+
machine_translation = self.get_machine()
473+
unit = MockUnit(
474+
code="cs", source=r"Hello, :file:`C:\Windows\System.exe`!", flags="rst-text"
475+
)
476+
self.assertEqual(
477+
machine_translation.cleanup_text(unit.source, unit),
478+
("Hello, [X7X]!", {"[X7X]": r":file:`C:\Windows\System.exe`"}),
479+
)
480+
self.assertEqual(
481+
machine_translation.translate(unit),
482+
[
483+
[
484+
{
485+
"quality": 100,
486+
"service": "Dummy",
487+
"source": r"Hello, :file:`C:\Windows\System.exe`!",
488+
"original_source": r"Hello, :file:`C:\Windows\System.exe`!",
489+
"text": r"Nazdar :file:`C:\Windows\System.exe`!",
490+
}
491+
]
492+
],
493+
)
494+
449495
def test_batch(self) -> None:
450496
machine_translation = self.get_machine()
451497
units = [

0 commit comments

Comments
 (0)