diff --git a/babel/util.py b/babel/util.py index 605695b1f..bff9bd6dd 100644 --- a/babel/util.py +++ b/babel/util.py @@ -16,6 +16,7 @@ import re import textwrap from collections.abc import Generator, Iterable +from itertools import chain from typing import IO, Any, TypeVar from babel import dates, localtime @@ -205,6 +206,24 @@ class TextWrapper(textwrap.TextWrapper): r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))', # em-dash ) + # e.g. '\u2068foo bar.py\u2069:42' + _enclosed_filename_re = re.compile(r'(\u2068[^\u2068]+?\u2069(?::-?\d+)?)') + + def _split(self, text): + """Splits the text into indivisible chunks while ensuring that file names + containing spaces are not broken up. + """ + enclosed_filename_start = '\u2068' + if enclosed_filename_start not in text: + # There are no file names which contain spaces, fallback to the default implementation + return super()._split(text) + + super_ = super() # Python 3.9 fix, super() does not work in list comprehension + chunks = re.split(self._enclosed_filename_re, text) + chunks = [[c] if c.startswith(enclosed_filename_start) else super_._split(c) for c in chunks] + chunks = [c for c in chain.from_iterable(chunks) if c] + return chunks + def wraptext(text: str, width: int = 70, initial_indent: str = '', subsequent_indent: str = '') -> list[str]: """Simple wrapper around the ``textwrap.wrap`` function in the standard diff --git a/tests/messages/test_pofile.py b/tests/messages/test_pofile.py index c0ded1296..74728ec66 100644 --- a/tests/messages/test_pofile.py +++ b/tests/messages/test_pofile.py @@ -896,6 +896,19 @@ def test_tab_in_location_already_enclosed(self): msgstr ""''' + def test_wrap_with_enclosed_file_locations(self): + # Ensure that file names containing white space are not wrapped regardless of the --width parameter + catalog = Catalog() + catalog.add('foo', locations=[('\u2068test utils.py\u2069', 1)]) + catalog.add('foo', locations=[('\u2068test utils.py\u2069', 3)]) + buf = BytesIO() + pofile.write_po(buf, catalog, omit_header=True, include_lineno=True, width=1) + assert buf.getvalue().strip() == b'''#: \xe2\x81\xa8test utils.py\xe2\x81\xa9:1 +#: \xe2\x81\xa8test utils.py\xe2\x81\xa9:3 +msgid "foo" +msgstr ""''' + + class RoundtripPoTestCase(unittest.TestCase): def test_enclosed_filenames_in_location_comment(self):