Procházet zdrojové kódy

Fixed 21406 -- Made blocktrans 'trimmed' option preserve line numbers.

Thanks Bouke Haarsma for report, fix and initial patch.
Bouke Haarsma před 11 roky
rodič
revize
91c38ce4b2

+ 18 - 13
django/utils/translation/trans_real.py

@@ -564,6 +564,12 @@ def templatize(src, origin=None):
     lineno_comment_map = {}
     comment_lineno_cache = None
 
+    def join_tokens(tokens, trim=False):
+        message = ''.join(tokens)
+        if trim:
+            message = trim_whitespace(message)
+        return message
+
     for t in Lexer(src, origin).tokenize():
         if incomment:
             if t.token_type == TOKEN_BLOCK and t.contents == 'endcomment':
@@ -586,29 +592,28 @@ def templatize(src, origin=None):
                 endbmatch = endblock_re.match(t.contents)
                 pluralmatch = plural_re.match(t.contents)
                 if endbmatch:
-                    if trimmed:
-                        singular = trim_whitespace(''.join(singular))
-                    else:
-                        singular = ''.join(singular)
-
                     if inplural:
-                        if trimmed:
-                            plural = trim_whitespace(''.join(plural))
-                        else:
-                            plural = ''.join(plural)
                         if message_context:
-                            out.write(' npgettext(%r, %r, %r,count) ' % (message_context, singular, plural))
+                            out.write(' npgettext(%r, %r, %r,count) ' % (
+                                message_context,
+                                join_tokens(singular, trimmed),
+                                join_tokens(plural, trimmed)))
                         else:
-                            out.write(' ngettext(%r, %r, count) ' % (singular, plural))
+                            out.write(' ngettext(%r, %r, count) ' % (
+                                join_tokens(singular, trimmed),
+                                join_tokens(plural, trimmed)))
                         for part in singular:
                             out.write(blankout(part, 'S'))
                         for part in plural:
                             out.write(blankout(part, 'P'))
                     else:
                         if message_context:
-                            out.write(' pgettext(%r, %r) ' % (message_context, singular))
+                            out.write(' pgettext(%r, %r) ' % (
+                                message_context,
+                                join_tokens(singular, trimmed)))
                         else:
-                            out.write(' gettext(%r) ' % singular)
+                            out.write(' gettext(%r) ' % join_tokens(singular,
+                                                                    trimmed))
                         for part in singular:
                             out.write(blankout(part, 'S'))
                     message_context = None

+ 1 - 0
tests/i18n/commands/templates/test.html

@@ -94,3 +94,4 @@ continued here.{% endcomment %}
   line breaks, this time
   should be trimmed.
 {% endblocktrans %}
+{% trans "I'm on line 97" %}

+ 46 - 20
tests/i18n/test_extraction.py

@@ -66,6 +66,43 @@ class ExtractorTests(SimpleTestCase):
         msgid = re.escape(msgid)
         return self.assertTrue(not re.search('^msgid %s' % msgid, s, re.MULTILINE))
 
+    def _assertPoLocComment(self, assert_presence, po_filename, line_number, *comment_parts):
+        with open(po_filename, 'r') as fp:
+            po_contents = force_text(fp.read())
+        if os.name == 'nt':
+            # #: .\path\to\file.html:123
+            cwd_prefix = '%s%s' % (os.curdir, os.sep)
+        else:
+            # #: path/to/file.html:123
+            cwd_prefix = ''
+        parts = ['#: ']
+        parts.append(os.path.join(cwd_prefix, *comment_parts))
+        if line_number is not None:
+            parts.append(':%d' % line_number)
+        needle = ''.join(parts)
+        if assert_presence:
+            return self.assertTrue(needle in po_contents, '"%s" not found in final .po file.' % needle)
+        else:
+            return self.assertFalse(needle in po_contents, '"%s" shouldn\'t be in final .po file.' % needle)
+
+    def assertLocationCommentPresent(self, po_filename, line_number, *comment_parts):
+        """
+        self.assertLocationCommentPresent('django.po', 42, 'dirA', 'dirB', 'foo.py')
+
+        verifies that the django.po file has a gettext-style location comment of the form
+
+        `#: dirA/dirB/foo.py:42`
+
+        (or `#: .\dirA\dirB\foo.py:42` on Windows)
+
+        None can be passed for the line_number argument to skip checking of the :42 suffix part.
+        """
+        return self._assertPoLocComment(True, po_filename, line_number, *comment_parts)
+
+    def assertLocationCommentNotPresent(self, po_filename, line_number, *comment_parts):
+        """Check the oposite of assertLocationComment()"""
+        return self._assertPoLocComment(False, po_filename, line_number, *comment_parts)
+
 
 class BasicExtractorTests(ExtractorTests):
 
@@ -133,6 +170,9 @@ class BasicExtractorTests(ExtractorTests):
             self.assertNotMsgId('Text with a few line breaks.', po_contents)
             # should be trimmed
             self.assertMsgId("Again some text with a few line breaks, this time should be trimmed.", po_contents)
+        # #21406 -- Should adjust for eaten line numbers
+        self.assertMsgId("I'm on line 97", po_contents)
+        self.assertLocationCommentPresent(self.PO_FILE, 97, 'templates', 'test.html')
 
     def test_force_en_us_locale(self):
         """Value of locale-munging option used by the command is the right one"""
@@ -418,32 +458,18 @@ class LocationCommentsTests(ExtractorTests):
         os.chdir(self.test_dir)
         management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_location=True)
         self.assertTrue(os.path.exists(self.PO_FILE))
-        with open(self.PO_FILE, 'r') as fp:
-            po_contents = force_text(fp.read())
-            needle = os.sep.join(['#: templates', 'test.html:55'])
-            self.assertFalse(needle in po_contents, '"%s" shouldn\'t be in final .po file.' % needle)
+        self.assertLocationCommentNotPresent(self.PO_FILE, 55, 'templates', 'test.html.py')
 
     def test_no_location_disabled(self):
         """Behavior is correct if --no-location switch isn't specified."""
         os.chdir(self.test_dir)
         management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_location=False)
         self.assertTrue(os.path.exists(self.PO_FILE))
-        with open(self.PO_FILE, 'r') as fp:
-            # Standard comment with source file relative path should be present -- #16903
-            po_contents = force_text(fp.read())
-            if os.name == 'nt':
-                # #: .\path\to\file.html:123
-                cwd_prefix = '%s%s' % (os.curdir, os.sep)
-            else:
-                # #: path/to/file.html:123
-                cwd_prefix = ''
-            needle = os.sep.join(['#: %stemplates' % cwd_prefix, 'test.html:55'])
-            self.assertTrue(needle in po_contents, '"%s" not found in final .po file.' % needle)
-
-            # #21208 -- Leaky paths in comments on Windows e.g. #: path\to\file.html.py:123
-            bad_suffix = '.py'
-            bad_string = 'templates%stest.html%s' % (os.sep, bad_suffix)
-            self.assertFalse(bad_string in po_contents, '"%s" shouldn\'t be in final .po file.' % bad_string)
+        # #16903 -- Standard comment with source file relative path should be present
+        self.assertLocationCommentPresent(self.PO_FILE, 55, 'templates', 'test.html')
+
+        # #21208 -- Leaky paths in comments on Windows e.g. #: path\to\file.html.py:123
+        self.assertLocationCommentNotPresent(self.PO_FILE, None, 'templates', 'test.html.py')
 
 
 class KeepPotFileExtractorTests(ExtractorTests):