Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #10004 and #12320 -- Enabled the makemessages management comman…

…d to collect comments for translators that start with the "Translators" keyword. Thanks for the report and patches, martinb and Claude Paroz.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14595 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 17b329ae08f9e3886da2baafc9e53949000480f9 1 parent d7ad02f
Jannis Leidel authored November 17, 2010
9  django/core/management/commands/makemessages.py
@@ -196,7 +196,7 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False,
196 196
                     'xgettext -d %s -L Perl %s --keyword=gettext_noop '
197 197
                     '--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 '
198 198
                     '--keyword=pgettext:1c,2 --keyword=npgettext:1c,2,3 '
199  
-                    '--from-code UTF-8 -o - "%s"' % (
  199
+                    '--from-code UTF-8 --add-comments=Translators -o - "%s"' % (
200 200
                         domain, wrap, os.path.join(dirpath, thefile)
201 201
                     )
202 202
                 )
@@ -240,8 +240,9 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False,
240 240
                     '--keyword=ugettext_noop --keyword=ugettext_lazy '
241 241
                     '--keyword=ungettext_lazy:1,2 --keyword=pgettext:1c,2 '
242 242
                     '--keyword=npgettext:1c,2,3 --keyword=pgettext_lazy:1c,2 '
243  
-                    '--keyword=npgettext_lazy:1c,2,3 --from-code UTF-8 -o - '
244  
-                    '"%s"' % (domain, wrap, os.path.join(dirpath, thefile))
  243
+                    '--keyword=npgettext_lazy:1c,2,3 --from-code UTF-8 '
  244
+                    '--add-comments=Translators -o - "%s"' % (
  245
+                        domain, wrap, os.path.join(dirpath, thefile))
245 246
                 )
246 247
                 msgs, errors = _popen(cmd)
247 248
                 if errors:
@@ -282,6 +283,8 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False,
282 283
                     raise CommandError("errors happened while running msgmerge\n%s" % errors)
283 284
             elif not invoked_for_django:
284 285
                 msgs = copy_plural_forms(msgs, locale, domain, verbosity)
  286
+            msgs = msgs.replace(
  287
+                "#. #-#-#-#-#  %s.pot (PACKAGE VERSION)  #-#-#-#-#\n" % domain, "")
285 288
             f = open(pofile, 'wb')
286 289
             try:
287 290
                 f.write(msgs)
6  django/template/__init__.py
@@ -82,6 +82,7 @@
82 82
 VARIABLE_TAG_END = '}}'
83 83
 COMMENT_TAG_START = '{#'
84 84
 COMMENT_TAG_END = '#}'
  85
+TRANSLATOR_COMMENT_MARK = 'Translators'
85 86
 SINGLE_BRACE_START = '{'
86 87
 SINGLE_BRACE_END = '}'
87 88
 
@@ -237,7 +238,10 @@ def create_token(self, token_string, in_tag):
237 238
             elif token_string.startswith(BLOCK_TAG_START):
238 239
                 token = Token(TOKEN_BLOCK, token_string[len(BLOCK_TAG_START):-len(BLOCK_TAG_END)].strip())
239 240
             elif token_string.startswith(COMMENT_TAG_START):
240  
-                token = Token(TOKEN_COMMENT, '')
  241
+                content = ''
  242
+                if token_string.find(TRANSLATOR_COMMENT_MARK):
  243
+                    content = token_string[len(COMMENT_TAG_START):-len(COMMENT_TAG_END)].strip()
  244
+                token = Token(TOKEN_COMMENT, content)
241 245
         else:
242 246
             token = Token(TOKEN_TEXT, token_string)
243 247
         return token
17  django/utils/translation/trans_real.py
@@ -427,14 +427,23 @@ def templatize(src):
427 427
     does so by translating the Django translation tags into standard gettext
428 428
     function invocations.
429 429
     """
430  
-    from django.template import Lexer, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK
  430
+    from django.template import Lexer, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK, TOKEN_COMMENT
431 431
     out = StringIO()
432 432
     intrans = False
433 433
     inplural = False
434 434
     singular = []
435 435
     plural = []
  436
+    incomment = False
  437
+    comment = []
436 438
     for t in Lexer(src, None).tokenize():
437  
-        if intrans:
  439
+        if incomment:
  440
+            if t.token_type == TOKEN_BLOCK and t.contents == 'endcomment':
  441
+                out.write(' # %s' % ''.join(comment))
  442
+                incomment = False
  443
+                comment = []
  444
+            else:
  445
+                comment.append(t.contents)
  446
+        elif intrans:
438 447
             if t.token_type == TOKEN_BLOCK:
439 448
                 endbmatch = endblock_re.match(t.contents)
440 449
                 pluralmatch = plural_re.match(t.contents)
@@ -488,6 +497,8 @@ def templatize(src):
488 497
                 elif cmatches:
489 498
                     for cmatch in cmatches:
490 499
                         out.write(' _(%s) ' % cmatch)
  500
+                elif t.contents == 'comment':
  501
+                    incomment = True
491 502
                 else:
492 503
                     out.write(blankout(t.contents, 'B'))
493 504
             elif t.token_type == TOKEN_VAR:
@@ -500,6 +511,8 @@ def templatize(src):
500 511
                         out.write(' %s ' % p.split(':',1)[1])
501 512
                     else:
502 513
                         out.write(blankout(p, 'F'))
  514
+            elif t.token_type == TOKEN_COMMENT:
  515
+                out.write(' # %s' % t.contents)
503 516
             else:
504 517
                 out.write(blankout(t.contents, 'X'))
505 518
     return out.getvalue()
16  docs/releases/1.3-alpha-2.txt
@@ -39,6 +39,22 @@ See the :doc:`reference documentation of the app </ref/contrib/staticfiles>`
39 39
 for more details or learn how to :doc:`manage static files
40 40
 </howto/static-files>`.
41 41
 
  42
+Translation comments
  43
+~~~~~~~~~~~~~~~~~~~~
  44
+
  45
+If you would like to give translators hints about a translatable string, you
  46
+can add a comment prefixed with the ``Translators`` keyword on the line
  47
+preceding the string, e.g.::
  48
+
  49
+    def my_view(request):
  50
+        # Translators: This message appears on the home page only
  51
+        output = ugettext("Welcome to my site.")
  52
+
  53
+The comment will appear in the resulting .po file and should also be
  54
+displayed by most translation tools.
  55
+
  56
+For more information, see :ref:`translator-comments`.
  57
+
42 58
 Backwards-incompatible changes in 1.3 alpha 2
43 59
 =============================================
44 60
 
10  docs/releases/1.3.txt
@@ -121,13 +121,17 @@ value, protect, or do nothing.
121 121
 For more information, see the :attr:`~django.db.models.ForeignKey.on_delete`
122 122
 documentation.
123 123
 
124  
-Contextual markers in translatable strings
125  
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  124
+Contextual markers and comments for translatable strings
  125
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
126 126
 
127 127
 For translation strings with ambiguous meaning, you can now
128 128
 use the ``pgettext`` function to specify the context of the string.
129 129
 
130  
-For more information, see :ref:`contextual-markers`
  130
+And if you just want to add some information for translators, you
  131
+can also add special translator comments in the source.
  132
+
  133
+For more information, see :ref:`contextual-markers` and
  134
+:ref:`translator-comments`.
131 135
 
132 136
 Everything else
133 137
 ~~~~~~~~~~~~~~~
24  docs/topics/i18n/internationalization.txt
@@ -100,6 +100,30 @@ instead of positional interpolation (e.g., ``%s`` or ``%d``) whenever you
100 100
 have more than a single parameter. If you used positional interpolation,
101 101
 translations wouldn't be able to reorder placeholder text.
102 102
 
  103
+.. _translator-comments:
  104
+
  105
+Comments for translators
  106
+------------------------
  107
+
  108
+.. versionadded:: 1.3
  109
+
  110
+If you would like to give translators hints about a translatable string, you
  111
+can add a comment prefixed with the ``Translators`` keyword on the line
  112
+preceding the string, e.g.::
  113
+
  114
+    def my_view(request):
  115
+        # Translators: This message appears on the home page only
  116
+        output = ugettext("Welcome to my site.")
  117
+
  118
+This also works in templates with the :ttag:`comment` tag:
  119
+
  120
+.. code-block:: django+html
  121
+
  122
+    {% comment %}Translators: This is a text of the base template {% endcomment %}
  123
+
  124
+The comment will then appear in the resulting .po file and should also be
  125
+displayed by most translation tools.
  126
+
103 127
 Marking strings as no-op
104 128
 ------------------------
105 129
 
8  tests/regressiontests/i18n/commands/__init__.py
... ...
@@ -0,0 +1,8 @@
  1
+from django.utils.translation import ugettext as _
  2
+
  3
+# Translators: This comment should be extracted
  4
+dummy1 = _("This is a translatable string.")
  5
+
  6
+# This comment should not be extracted
  7
+dummy2 = _("This is another translatable string.")
  8
+
13  tests/regressiontests/i18n/commands/extraction.py
@@ -38,7 +38,18 @@ def assertNotMsgId(self, msgid, s, use_quotes=True):
38 38
         return self.assert_(not re.search('^msgid %s' % msgid, s, re.MULTILINE))
39 39
 
40 40
 
41  
-class TemplateExtractorTests(ExtractorTests):
  41
+class BasicExtractorTests(ExtractorTests):
  42
+
  43
+    def test_comments_extractor(self):
  44
+        os.chdir(self.test_dir)
  45
+        management.call_command('makemessages', locale=LOCALE, verbosity=0)
  46
+        self.assert_(os.path.exists(self.PO_FILE))
  47
+        po_contents = open(self.PO_FILE, 'r').read()
  48
+        self.assert_('#. Translators: This comment should be extracted' in po_contents)
  49
+        self.assert_('This comment should not be extracted' not in po_contents)
  50
+        # Comments in templates
  51
+        self.assert_('#. Translators: Django template comment for translators' in po_contents)
  52
+        self.assert_('#. Translators: Django comment block for translators' in po_contents)
42 53
 
43 54
     def test_templatize(self):
44 55
         os.chdir(self.test_dir)
7  tests/regressiontests/i18n/commands/templates/test.html
... ...
@@ -1,5 +1,8 @@
1 1
 {% load i18n %}
  2
+{% comment %}Translators: Django comment block for translators {% endcomment %}
2 3
 {% trans "This literal should be included." %}
3 4
 {% trans "This literal should also be included wrapped or not wrapped depending on the use of the --no-wrap option." %}
4  
-{% blocktrans %}I think that 100% is more that 50% of anything.{% endblocktrans %}
5  
-{% blocktrans with 'txt' as obj %}I think that 100% is more that 50% of {{ obj }}.{% endblocktrans %}
  5
+
  6
+{# Translators: Django template comment for translators #}
  7
+<p>{% blocktrans %}I think that 100% is more that 50% of anything.{% endblocktrans %}</p>
  8
+{% blocktrans with 'txt' as obj %}I think that 100% is more that 50% of {{ obj }}.{% endblocktrans %}

0 notes on commit 17b329a

Please sign in to comment.
Something went wrong with that request. Please try again.