diff --git a/docs/changes.rst b/docs/changes.rst index f3f7900afcb2..264520191453 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -13,6 +13,7 @@ Not yet released. * :envvar:`WEBLATE_REGISTRATION_CAPTCHA` is now available in Docker container. * :guilabel:`Synchronize` on shared repository now operates on all its components. * :ref:`check-punctuation-spacing` ignores markup such as Markdown or reStructuredText. +* :ref:`autofix-punctuation-spacing` does not alter reStructuredText markup. **Bug fixes** diff --git a/weblate/trans/autofixes/chars.py b/weblate/trans/autofixes/chars.py index 56757f259a1d..62371fc406e4 100644 --- a/weblate/trans/autofixes/chars.py +++ b/weblate/trans/autofixes/chars.py @@ -16,6 +16,7 @@ PunctuationSpacingCheck, ZeroWidthSpaceCheck, ) +from weblate.checks.same import RST_MATCH from weblate.formats.helpers import CONTROLCHARS_TRANS from weblate.trans.autofixes.base import AutoFix @@ -106,13 +107,24 @@ def get_related_checks(): def fix_single_target( self, target: str, source: str, unit: Unit ) -> tuple[str, bool]: + def spacing_replace(matchobj: re.Match) -> str: + if "rst-text" in unit.all_flags: + offset = matchobj.start(2) + rst_position = RST_MATCH.search(target, offset) + if rst_position is not None and rst_position.start(0) == offset: + # Skip escaping inside rst tag + return matchobj.group(0) + return f"\u00a0{matchobj.group(2)}" + if ( unit.translation.language.is_base(("fr", "br")) and unit.translation.language.code != "fr_CA" and "ignore-punctuation-spacing" not in unit.all_flags ): # Fix existing - new_target = re.sub(FRENCH_PUNCTUATION_FIXUP_RE_NBSP, "\u00a0\\2", target) + new_target = re.sub( + FRENCH_PUNCTUATION_FIXUP_RE_NBSP, spacing_replace, target + ) new_target = re.sub( FRENCH_PUNCTUATION_FIXUP_RE_NNBSP, "\u202f\\2", new_target ) diff --git a/weblate/trans/tests/test_autofix.py b/weblate/trans/tests/test_autofix.py index d8c25d2e42ce..4c5476e9f21e 100644 --- a/weblate/trans/tests/test_autofix.py +++ b/weblate/trans/tests/test_autofix.py @@ -182,3 +182,14 @@ def test_punctuation_spacing(self) -> None: self.assertEqual(fix.fix_target(["Bar:"], fr_unit), (["Bar:"], False)) self.assertEqual(fix.fix_target(["Bar:"], fr_ca_unit), (["Bar:"], False)) self.assertEqual(fix.fix_target(["Bar:"], cs_unit), (["Bar:"], False)) + + def test_punctuation_spacing_rst(self) -> None: + fix = PunctuationSpacing() + fr_rst_unit = MockUnit(source="This :ref:`doc`", code="fr", flags="rst-text") + self.assertEqual( + fix.fix_target(["This :ref:`doc`"], fr_rst_unit), + (["This :ref:`doc`"], False), + ) + self.assertEqual( + fix.fix_target(["This :"], fr_rst_unit), (["This\u00a0:"], True) + )