Fixed #10004 and #12320 -- Enabled the makemessages management command 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
This commit is contained in:
Jannis Leidel 2010-11-17 15:37:33 +00:00
parent d7ad02ff72
commit 17b329ae08
9 changed files with 98 additions and 12 deletions

View File

@ -196,7 +196,7 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False,
'xgettext -d %s -L Perl %s --keyword=gettext_noop ' 'xgettext -d %s -L Perl %s --keyword=gettext_noop '
'--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 ' '--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 '
'--keyword=pgettext:1c,2 --keyword=npgettext:1c,2,3 ' '--keyword=pgettext:1c,2 --keyword=npgettext:1c,2,3 '
'--from-code UTF-8 -o - "%s"' % ( '--from-code UTF-8 --add-comments=Translators -o - "%s"' % (
domain, wrap, os.path.join(dirpath, thefile) domain, wrap, os.path.join(dirpath, thefile)
) )
) )
@ -240,8 +240,9 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False,
'--keyword=ugettext_noop --keyword=ugettext_lazy ' '--keyword=ugettext_noop --keyword=ugettext_lazy '
'--keyword=ungettext_lazy:1,2 --keyword=pgettext:1c,2 ' '--keyword=ungettext_lazy:1,2 --keyword=pgettext:1c,2 '
'--keyword=npgettext:1c,2,3 --keyword=pgettext_lazy:1c,2 ' '--keyword=npgettext:1c,2,3 --keyword=pgettext_lazy:1c,2 '
'--keyword=npgettext_lazy:1c,2,3 --from-code UTF-8 -o - ' '--keyword=npgettext_lazy:1c,2,3 --from-code UTF-8 '
'"%s"' % (domain, wrap, os.path.join(dirpath, thefile)) '--add-comments=Translators -o - "%s"' % (
domain, wrap, os.path.join(dirpath, thefile))
) )
msgs, errors = _popen(cmd) msgs, errors = _popen(cmd)
if errors: if errors:
@ -282,6 +283,8 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False,
raise CommandError("errors happened while running msgmerge\n%s" % errors) raise CommandError("errors happened while running msgmerge\n%s" % errors)
elif not invoked_for_django: elif not invoked_for_django:
msgs = copy_plural_forms(msgs, locale, domain, verbosity) msgs = copy_plural_forms(msgs, locale, domain, verbosity)
msgs = msgs.replace(
"#. #-#-#-#-# %s.pot (PACKAGE VERSION) #-#-#-#-#\n" % domain, "")
f = open(pofile, 'wb') f = open(pofile, 'wb')
try: try:
f.write(msgs) f.write(msgs)

View File

@ -82,6 +82,7 @@ VARIABLE_TAG_START = '{{'
VARIABLE_TAG_END = '}}' VARIABLE_TAG_END = '}}'
COMMENT_TAG_START = '{#' COMMENT_TAG_START = '{#'
COMMENT_TAG_END = '#}' COMMENT_TAG_END = '#}'
TRANSLATOR_COMMENT_MARK = 'Translators'
SINGLE_BRACE_START = '{' SINGLE_BRACE_START = '{'
SINGLE_BRACE_END = '}' SINGLE_BRACE_END = '}'
@ -237,7 +238,10 @@ class Lexer(object):
elif token_string.startswith(BLOCK_TAG_START): elif token_string.startswith(BLOCK_TAG_START):
token = Token(TOKEN_BLOCK, token_string[len(BLOCK_TAG_START):-len(BLOCK_TAG_END)].strip()) token = Token(TOKEN_BLOCK, token_string[len(BLOCK_TAG_START):-len(BLOCK_TAG_END)].strip())
elif token_string.startswith(COMMENT_TAG_START): elif token_string.startswith(COMMENT_TAG_START):
token = Token(TOKEN_COMMENT, '') content = ''
if token_string.find(TRANSLATOR_COMMENT_MARK):
content = token_string[len(COMMENT_TAG_START):-len(COMMENT_TAG_END)].strip()
token = Token(TOKEN_COMMENT, content)
else: else:
token = Token(TOKEN_TEXT, token_string) token = Token(TOKEN_TEXT, token_string)
return token return token

View File

@ -427,14 +427,23 @@ def templatize(src):
does so by translating the Django translation tags into standard gettext does so by translating the Django translation tags into standard gettext
function invocations. function invocations.
""" """
from django.template import Lexer, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK from django.template import Lexer, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK, TOKEN_COMMENT
out = StringIO() out = StringIO()
intrans = False intrans = False
inplural = False inplural = False
singular = [] singular = []
plural = [] plural = []
incomment = False
comment = []
for t in Lexer(src, None).tokenize(): for t in Lexer(src, None).tokenize():
if intrans: if incomment:
if t.token_type == TOKEN_BLOCK and t.contents == 'endcomment':
out.write(' # %s' % ''.join(comment))
incomment = False
comment = []
else:
comment.append(t.contents)
elif intrans:
if t.token_type == TOKEN_BLOCK: if t.token_type == TOKEN_BLOCK:
endbmatch = endblock_re.match(t.contents) endbmatch = endblock_re.match(t.contents)
pluralmatch = plural_re.match(t.contents) pluralmatch = plural_re.match(t.contents)
@ -488,6 +497,8 @@ def templatize(src):
elif cmatches: elif cmatches:
for cmatch in cmatches: for cmatch in cmatches:
out.write(' _(%s) ' % cmatch) out.write(' _(%s) ' % cmatch)
elif t.contents == 'comment':
incomment = True
else: else:
out.write(blankout(t.contents, 'B')) out.write(blankout(t.contents, 'B'))
elif t.token_type == TOKEN_VAR: elif t.token_type == TOKEN_VAR:
@ -500,6 +511,8 @@ def templatize(src):
out.write(' %s ' % p.split(':',1)[1]) out.write(' %s ' % p.split(':',1)[1])
else: else:
out.write(blankout(p, 'F')) out.write(blankout(p, 'F'))
elif t.token_type == TOKEN_COMMENT:
out.write(' # %s' % t.contents)
else: else:
out.write(blankout(t.contents, 'X')) out.write(blankout(t.contents, 'X'))
return out.getvalue() return out.getvalue()

View File

@ -39,6 +39,22 @@ See the :doc:`reference documentation of the app </ref/contrib/staticfiles>`
for more details or learn how to :doc:`manage static files for more details or learn how to :doc:`manage static files
</howto/static-files>`. </howto/static-files>`.
Translation comments
~~~~~~~~~~~~~~~~~~~~
If you would like to give translators hints about a translatable string, you
can add a comment prefixed with the ``Translators`` keyword on the line
preceding the string, e.g.::
def my_view(request):
# Translators: This message appears on the home page only
output = ugettext("Welcome to my site.")
The comment will appear in the resulting .po file and should also be
displayed by most translation tools.
For more information, see :ref:`translator-comments`.
Backwards-incompatible changes in 1.3 alpha 2 Backwards-incompatible changes in 1.3 alpha 2
============================================= =============================================

View File

@ -121,13 +121,17 @@ value, protect, or do nothing.
For more information, see the :attr:`~django.db.models.ForeignKey.on_delete` For more information, see the :attr:`~django.db.models.ForeignKey.on_delete`
documentation. documentation.
Contextual markers in translatable strings Contextual markers and comments for translatable strings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For translation strings with ambiguous meaning, you can now For translation strings with ambiguous meaning, you can now
use the ``pgettext`` function to specify the context of the string. use the ``pgettext`` function to specify the context of the string.
For more information, see :ref:`contextual-markers` And if you just want to add some information for translators, you
can also add special translator comments in the source.
For more information, see :ref:`contextual-markers` and
:ref:`translator-comments`.
Everything else Everything else
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~

View File

@ -100,6 +100,30 @@ instead of positional interpolation (e.g., ``%s`` or ``%d``) whenever you
have more than a single parameter. If you used positional interpolation, have more than a single parameter. If you used positional interpolation,
translations wouldn't be able to reorder placeholder text. translations wouldn't be able to reorder placeholder text.
.. _translator-comments:
Comments for translators
------------------------
.. versionadded:: 1.3
If you would like to give translators hints about a translatable string, you
can add a comment prefixed with the ``Translators`` keyword on the line
preceding the string, e.g.::
def my_view(request):
# Translators: This message appears on the home page only
output = ugettext("Welcome to my site.")
This also works in templates with the :ttag:`comment` tag:
.. code-block:: django+html
{% comment %}Translators: This is a text of the base template {% endcomment %}
The comment will then appear in the resulting .po file and should also be
displayed by most translation tools.
Marking strings as no-op Marking strings as no-op
------------------------ ------------------------

View File

@ -0,0 +1,8 @@
from django.utils.translation import ugettext as _
# Translators: This comment should be extracted
dummy1 = _("This is a translatable string.")
# This comment should not be extracted
dummy2 = _("This is another translatable string.")

View File

@ -38,7 +38,18 @@ class ExtractorTests(TestCase):
return self.assert_(not re.search('^msgid %s' % msgid, s, re.MULTILINE)) return self.assert_(not re.search('^msgid %s' % msgid, s, re.MULTILINE))
class TemplateExtractorTests(ExtractorTests): class BasicExtractorTests(ExtractorTests):
def test_comments_extractor(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=LOCALE, verbosity=0)
self.assert_(os.path.exists(self.PO_FILE))
po_contents = open(self.PO_FILE, 'r').read()
self.assert_('#. Translators: This comment should be extracted' in po_contents)
self.assert_('This comment should not be extracted' not in po_contents)
# Comments in templates
self.assert_('#. Translators: Django template comment for translators' in po_contents)
self.assert_('#. Translators: Django comment block for translators' in po_contents)
def test_templatize(self): def test_templatize(self):
os.chdir(self.test_dir) os.chdir(self.test_dir)

View File

@ -1,5 +1,8 @@
{% load i18n %} {% load i18n %}
{% comment %}Translators: Django comment block for translators {% endcomment %}
{% trans "This literal should be included." %} {% trans "This literal should be included." %}
{% trans "This literal should also be included wrapped or not wrapped depending on the use of the --no-wrap option." %} {% trans "This literal should also be included wrapped or not wrapped depending on the use of the --no-wrap option." %}
{% blocktrans %}I think that 100% is more that 50% of anything.{% endblocktrans %}
{% blocktrans with 'txt' as obj %}I think that 100% is more that 50% of {{ obj }}.{% endblocktrans %} {# Translators: Django template comment for translators #}
<p>{% blocktrans %}I think that 100% is more that 50% of anything.{% endblocktrans %}</p>
{% blocktrans with 'txt' as obj %}I think that 100% is more that 50% of {{ obj }}.{% endblocktrans %}