Commit b7508896 authored by Doug Beck's avatar Doug Beck Committed by Tim Graham
Browse files

Fixed #24257 -- Corrected i18n handling of percent signs.

Refactored tests to use a sample project.

Updated extraction:
* Removed special handling of single percent signs.
* When extracting messages from template text, doubled all percent signs
  so they are not interpreted by gettext as string format flags. All
  strings extracted by gettext, if containing a percent sign, will now
  be labeled "#, python-format".

Updated translation:
* Used "%%" for "%" in template text before calling gettext.
* Updated {% trans %} rendering to restore "%" from "%%".
parent d772d812
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -825,10 +825,13 @@ class Variable(object):
            # We're dealing with a literal, so it's already been "resolved"
            value = self.literal
        if self.translate:
            is_safe = isinstance(value, SafeData)
            msgid = value.replace('%', '%%')
            msgid = mark_safe(msgid) if is_safe else msgid
            if self.message_context:
                return pgettext_lazy(self.message_context, value)
                return pgettext_lazy(self.message_context, msgid)
            else:
                return ugettext_lazy(value)
                return ugettext_lazy(msgid)
        return value

    def __repr__(self):
+6 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ from django.template import Library, Node, TemplateSyntaxError, Variable
from django.template.base import TOKEN_TEXT, TOKEN_VAR, render_value_in_context
from django.template.defaulttags import token_kwargs
from django.utils import six, translation
from django.utils.safestring import SafeData, mark_safe

register = Library()

@@ -86,6 +87,11 @@ class TranslateNode(Node):
                self.message_context.resolve(context))
        output = self.filter_expression.resolve(context)
        value = render_value_in_context(output, context)
        # Restore percent signs. Percent signs in template text are doubled
        # so they are not interpreted as string format flags.
        is_safe = isinstance(value, SafeData)
        value = value.replace('%%', '%')
        value = mark_safe(value) if is_safe else value
        if self.asvar:
            context[self.asvar] = value
            return ''
+2 −3
Original line number Diff line number Diff line
@@ -534,7 +534,6 @@ block_re = re.compile(r"""^\s*blocktrans(\s+.*context\s+((?:"[^"]*?")|(?:'[^']*?
endblock_re = re.compile(r"""^\s*endblocktrans$""")
plural_re = re.compile(r"""^\s*plural$""")
constant_re = re.compile(r"""_\(((?:".*?")|(?:'.*?'))\)""")
one_percent_re = re.compile(r"""(?<!%)%(?!%)""")


def templatize(src, origin=None):
@@ -631,7 +630,7 @@ def templatize(src, origin=None):
                else:
                    singular.append('%%(%s)s' % t.contents)
            elif t.token_type == TOKEN_TEXT:
                contents = one_percent_re.sub('%%', t.contents)
                contents = t.contents.replace('%', '%%')
                if inplural:
                    plural.append(contents)
                else:
@@ -667,7 +666,7 @@ def templatize(src, origin=None):
                        g = g.strip('"')
                    elif g[0] == "'":
                        g = g.strip("'")
                    g = one_percent_re.sub('%%', g)
                    g = g.replace('%', '%%')
                    if imatch.group(2):
                        # A context is provided
                        context_match = context_re.match(imatch.group(2))
+5 −0
Original line number Diff line number Diff line
@@ -940,6 +940,11 @@ Miscellaneous
  whitespace by default. This can be disabled by setting the new
  :attr:`~django.forms.CharField.strip` argument to ``False``.

* Template text that is translated and uses two or more consecutive percent
  signs, e.g. ``"%%"``, may have a new `msgid` after ``makemessages`` is run
  (most likely the translation will be marked fuzzy). The new ``msgid`` will be
  marked ``"#, python-format"``.

* If neither :attr:`request.current_app <django.http.HttpRequest.current_app>`
  nor :class:`Context.current_app <django.template.Context>` are set, the
  :ttag:`url` template tag will now use the namespace of the current request.
+2 −52
Original line number Diff line number Diff line
@@ -17,55 +17,5 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"

#. Translators: Django template comment for translators
#: templates/test.html:9
#, python-format
msgid "I think that 100%% is more that 50%% of anything."
msgstr ""

#: templates/test.html:10
#, python-format
msgid "I think that 100%% is more that 50%% of %(obj)s."
msgstr ""

#: templates/test.html:70
#, python-format
msgid "Literal with a percent symbol at the end %%"
msgstr ""

#: templates/test.html:71
#, python-format
msgid "Literal with a percent %% symbol in the middle"
msgstr ""

#: templates/test.html:72
#, python-format
msgid "Completed 50%% of all the tasks"
msgstr ""

#: templates/test.html:73
#, python-format
msgctxt "ctx0"
msgid "Completed 99%% of all the tasks"
msgstr ""

#: templates/test.html:74
#, python-format
msgid "Shouldn't double escape this sequence: %% (two percent signs)"
msgstr ""

#: templates/test.html:75
#, python-format
msgctxt "ctx1"
msgid "Shouldn't double escape this sequence %% either"
msgstr ""

#: templates/test.html:76
#, python-format
msgid "Looks like a str fmt spec %%s but shouldn't be interpreted as such"
msgstr "Translation of the above string"

#: templates/test.html:77
#, python-format
msgid "Looks like a str fmt spec %% o but shouldn't be interpreted as such"
msgstr "Translation contains %% for the above string"
msgid "year"
msgstr "année"
Loading