Fixed #30585 -- Added {% translate %} and {% blocktranslate %} template tags.
This commit is contained in:
parent
70d95682b1
commit
d291c72bf2
|
@ -98,7 +98,8 @@ class TranslateNode(Node):
|
||||||
class BlockTranslateNode(Node):
|
class BlockTranslateNode(Node):
|
||||||
|
|
||||||
def __init__(self, extra_context, singular, plural=None, countervar=None,
|
def __init__(self, extra_context, singular, plural=None, countervar=None,
|
||||||
counter=None, message_context=None, trimmed=False, asvar=None):
|
counter=None, message_context=None, trimmed=False, asvar=None,
|
||||||
|
tag_name='blocktranslate'):
|
||||||
self.extra_context = extra_context
|
self.extra_context = extra_context
|
||||||
self.singular = singular
|
self.singular = singular
|
||||||
self.plural = plural
|
self.plural = plural
|
||||||
|
@ -107,6 +108,7 @@ class BlockTranslateNode(Node):
|
||||||
self.message_context = message_context
|
self.message_context = message_context
|
||||||
self.trimmed = trimmed
|
self.trimmed = trimmed
|
||||||
self.asvar = asvar
|
self.asvar = asvar
|
||||||
|
self.tag_name = tag_name
|
||||||
|
|
||||||
def render_token_list(self, tokens):
|
def render_token_list(self, tokens):
|
||||||
result = []
|
result = []
|
||||||
|
@ -163,8 +165,8 @@ class BlockTranslateNode(Node):
|
||||||
if nested:
|
if nested:
|
||||||
# Either string is malformed, or it's a bug
|
# Either string is malformed, or it's a bug
|
||||||
raise TemplateSyntaxError(
|
raise TemplateSyntaxError(
|
||||||
"'blocktrans' is unable to format string returned by gettext: %r using %r"
|
'%r is unable to format string returned by gettext: %r '
|
||||||
% (result, data)
|
'using %r' % (self.tag_name, result, data)
|
||||||
)
|
)
|
||||||
with translation.override(None):
|
with translation.override(None):
|
||||||
result = self.render(context, nested=True)
|
result = self.render(context, nested=True)
|
||||||
|
@ -313,6 +315,7 @@ def do_get_current_language_bidi(parser, token):
|
||||||
return GetCurrentLanguageBidiNode(args[2])
|
return GetCurrentLanguageBidiNode(args[2])
|
||||||
|
|
||||||
|
|
||||||
|
@register.tag("translate")
|
||||||
@register.tag("trans")
|
@register.tag("trans")
|
||||||
def do_translate(parser, token):
|
def do_translate(parser, token):
|
||||||
"""
|
"""
|
||||||
|
@ -406,6 +409,7 @@ def do_translate(parser, token):
|
||||||
return TranslateNode(message_string, noop, asvar, message_context)
|
return TranslateNode(message_string, noop, asvar, message_context)
|
||||||
|
|
||||||
|
|
||||||
|
@register.tag("blocktranslate")
|
||||||
@register.tag("blocktrans")
|
@register.tag("blocktrans")
|
||||||
def do_block_translate(parser, token):
|
def do_block_translate(parser, token):
|
||||||
"""
|
"""
|
||||||
|
@ -513,19 +517,20 @@ def do_block_translate(parser, token):
|
||||||
break
|
break
|
||||||
if countervar and counter:
|
if countervar and counter:
|
||||||
if token.contents.strip() != 'plural':
|
if token.contents.strip() != 'plural':
|
||||||
raise TemplateSyntaxError("'blocktrans' doesn't allow other block tags inside it")
|
raise TemplateSyntaxError("%r doesn't allow other block tags inside it" % bits[0])
|
||||||
while parser.tokens:
|
while parser.tokens:
|
||||||
token = parser.next_token()
|
token = parser.next_token()
|
||||||
if token.token_type in (TokenType.VAR, TokenType.TEXT):
|
if token.token_type in (TokenType.VAR, TokenType.TEXT):
|
||||||
plural.append(token)
|
plural.append(token)
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
if token.contents.strip() != 'endblocktrans':
|
end_tag_name = 'end%s' % bits[0]
|
||||||
raise TemplateSyntaxError("'blocktrans' doesn't allow other block tags (seen %r) inside it" % token.contents)
|
if token.contents.strip() != end_tag_name:
|
||||||
|
raise TemplateSyntaxError("%r doesn't allow other block tags (seen %r) inside it" % (bits[0], token.contents))
|
||||||
|
|
||||||
return BlockTranslateNode(extra_context, singular, plural, countervar,
|
return BlockTranslateNode(extra_context, singular, plural, countervar,
|
||||||
counter, message_context, trimmed=trimmed,
|
counter, message_context, trimmed=trimmed,
|
||||||
asvar=asvar)
|
asvar=asvar, tag_name=bits[0])
|
||||||
|
|
||||||
|
|
||||||
@register.tag
|
@register.tag
|
||||||
|
|
|
@ -19,15 +19,15 @@ def blankout(src, char):
|
||||||
|
|
||||||
context_re = _lazy_re_compile(r"""^\s+.*context\s+((?:"[^"]*?")|(?:'[^']*?'))\s*""")
|
context_re = _lazy_re_compile(r"""^\s+.*context\s+((?:"[^"]*?")|(?:'[^']*?'))\s*""")
|
||||||
inline_re = _lazy_re_compile(
|
inline_re = _lazy_re_compile(
|
||||||
# Match the trans 'some text' part
|
# Match the trans/translate 'some text' part.
|
||||||
r"""^\s*trans\s+((?:"[^"]*?")|(?:'[^']*?'))"""
|
r"""^\s*trans(?:late)?\s+((?:"[^"]*?")|(?:'[^']*?'))"""
|
||||||
# Match and ignore optional filters
|
# Match and ignore optional filters
|
||||||
r"""(?:\s*\|\s*[^\s:]+(?::(?:[^\s'":]+|(?:"[^"]*?")|(?:'[^']*?')))?)*"""
|
r"""(?:\s*\|\s*[^\s:]+(?::(?:[^\s'":]+|(?:"[^"]*?")|(?:'[^']*?')))?)*"""
|
||||||
# Match the optional context part
|
# Match the optional context part
|
||||||
r"""(\s+.*context\s+((?:"[^"]*?")|(?:'[^']*?')))?\s*"""
|
r"""(\s+.*context\s+((?:"[^"]*?")|(?:'[^']*?')))?\s*"""
|
||||||
)
|
)
|
||||||
block_re = _lazy_re_compile(r"""^\s*blocktrans(\s+.*context\s+((?:"[^"]*?")|(?:'[^']*?')))?(?:\s+|$)""")
|
block_re = _lazy_re_compile(r"""^\s*blocktrans(?:late)?(\s+.*context\s+((?:"[^"]*?")|(?:'[^']*?')))?(?:\s+|$)""")
|
||||||
endblock_re = _lazy_re_compile(r"""^\s*endblocktrans$""")
|
endblock_re = _lazy_re_compile(r"""^\s*endblocktrans(?:late)?$""")
|
||||||
plural_re = _lazy_re_compile(r"""^\s*plural$""")
|
plural_re = _lazy_re_compile(r"""^\s*plural$""")
|
||||||
constant_re = _lazy_re_compile(r"""_\(((?:".*?")|(?:'.*?'))\)""")
|
constant_re = _lazy_re_compile(r"""_\(((?:".*?")|(?:'.*?'))\)""")
|
||||||
|
|
||||||
|
|
|
@ -2695,14 +2695,14 @@ Therefore here is our new ``change_form.html`` :
|
||||||
{% load i18n admin_urls %}
|
{% load i18n admin_urls %}
|
||||||
{% block object-tools-items %}
|
{% block object-tools-items %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url opts|admin_urlname:'history' original.pk|admin_urlquote %}" class="historylink">{% trans "History" %}</a>
|
<a href="{% url opts|admin_urlname:'history' original.pk|admin_urlquote %}" class="historylink">{% translate "History" %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="mylink/" class="historylink">My Link</a>
|
<a href="mylink/" class="historylink">My Link</a>
|
||||||
</li>
|
</li>
|
||||||
{% if has_absolute_url %}
|
{% if has_absolute_url %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'admin:view_on_site' content_type_id original.pk %}" class="viewsitelink">{% trans "View on site" %}</a>
|
<a href="{% url 'admin:view_on_site' content_type_id original.pk %}" class="viewsitelink">{% translate "View on site" %}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -814,10 +814,10 @@ This would display as "It is the 4th of September".
|
||||||
|
|
||||||
You can also use the syntax ``{% now "Y" as current_year %}`` to store the
|
You can also use the syntax ``{% now "Y" as current_year %}`` to store the
|
||||||
output (as a string) inside a variable. This is useful if you want to use
|
output (as a string) inside a variable. This is useful if you want to use
|
||||||
``{% now %}`` inside a template tag like :ttag:`blocktrans` for example::
|
``{% now %}`` inside a template tag like :ttag:`blocktranslate` for example::
|
||||||
|
|
||||||
{% now "Y" as current_year %}
|
{% now "Y" as current_year %}
|
||||||
{% blocktrans %}Copyright {{ current_year }}{% endblocktrans %}
|
{% blocktranslate %}Copyright {{ current_year }}{% endblocktranslate %}
|
||||||
|
|
||||||
.. templatetag:: regroup
|
.. templatetag:: regroup
|
||||||
|
|
||||||
|
@ -1200,10 +1200,10 @@ image in the above example will be 88 pixels wide
|
||||||
(because 175/200 = .875; .875 * 100 = 87.5 which is rounded up to 88).
|
(because 175/200 = .875; .875 * 100 = 87.5 which is rounded up to 88).
|
||||||
|
|
||||||
In some cases you might want to capture the result of ``widthratio`` in a
|
In some cases you might want to capture the result of ``widthratio`` in a
|
||||||
variable. It can be useful, for instance, in a :ttag:`blocktrans` like this::
|
variable. It can be useful, for instance, in a :ttag:`blocktranslate` like this::
|
||||||
|
|
||||||
{% widthratio this_value max_value max_width as width %}
|
{% widthratio this_value max_value max_width as width %}
|
||||||
{% blocktrans %}The width is: {{ width }}{% endblocktrans %}
|
{% blocktranslate %}The width is: {{ width }}{% endblocktranslate %}
|
||||||
|
|
||||||
.. templatetag:: with
|
.. templatetag:: with
|
||||||
|
|
||||||
|
@ -2023,7 +2023,7 @@ Example::
|
||||||
|
|
||||||
You have {{ num_cherries }} cherr{{ num_cherries|pluralize:"y,ies" }}.
|
You have {{ num_cherries }} cherr{{ num_cherries|pluralize:"y,ies" }}.
|
||||||
|
|
||||||
.. note:: Use :ttag:`blocktrans` to pluralize translated strings.
|
.. note:: Use :ttag:`blocktranslate` to pluralize translated strings.
|
||||||
|
|
||||||
.. templatefilter:: pprint
|
.. templatefilter:: pprint
|
||||||
|
|
||||||
|
|
|
@ -414,7 +414,7 @@ Here are some tips for working with inheritance:
|
||||||
tag ``as`` syntax can't be used inside the block. For example, this template
|
tag ``as`` syntax can't be used inside the block. For example, this template
|
||||||
doesn't render anything::
|
doesn't render anything::
|
||||||
|
|
||||||
{% trans "Title" as title %}
|
{% translate "Title" as title %}
|
||||||
{% block content %}{{ title }}{% endblock %}
|
{% block content %}{{ title }}{% endblock %}
|
||||||
|
|
||||||
* For extra readability, you can optionally give a *name* to your
|
* For extra readability, you can optionally give a *name* to your
|
||||||
|
|
|
@ -260,7 +260,10 @@ Signals
|
||||||
Templates
|
Templates
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
* ...
|
* The renamed :ttag:`translate` and :ttag:`blocktranslate` template tags are
|
||||||
|
introduced for internationalization in template code. The older :ttag:`trans`
|
||||||
|
and :ttag:`blocktrans` template tags aliases continue to work, and will be
|
||||||
|
retained for the foreseeable future.
|
||||||
|
|
||||||
Tests
|
Tests
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
|
@ -682,7 +682,7 @@ templates to achieve the same result:
|
||||||
{% get_current_language as LANGUAGE_CODE %}
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
|
|
||||||
{% cache 600 welcome LANGUAGE_CODE %}
|
{% cache 600 welcome LANGUAGE_CODE %}
|
||||||
{% trans "Welcome to example.com" %}
|
{% translate "Welcome to example.com" %}
|
||||||
{% endcache %}
|
{% endcache %}
|
||||||
|
|
||||||
The cache timeout can be a template variable, as long as the template variable
|
The cache timeout can be a template variable, as long as the template variable
|
||||||
|
|
|
@ -328,8 +328,8 @@ will appear in the ``.po`` file as:
|
||||||
msgid "May"
|
msgid "May"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
Contextual markers are also supported by the :ttag:`trans` and
|
Contextual markers are also supported by the :ttag:`translate` and
|
||||||
:ttag:`blocktrans` template tags.
|
:ttag:`blocktranslate` template tags.
|
||||||
|
|
||||||
.. _lazy-translations:
|
.. _lazy-translations:
|
||||||
|
|
||||||
|
@ -575,21 +575,22 @@ have already loaded the ``i18n`` tag.
|
||||||
unchanged.
|
unchanged.
|
||||||
|
|
||||||
.. templatetag:: trans
|
.. templatetag:: trans
|
||||||
|
.. templatetag:: translate
|
||||||
|
|
||||||
``trans`` template tag
|
``translate`` template tag
|
||||||
----------------------
|
--------------------------
|
||||||
|
|
||||||
The ``{% trans %}`` template tag translates either a constant string
|
The ``{% translate %}`` template tag translates either a constant string
|
||||||
(enclosed in single or double quotes) or variable content::
|
(enclosed in single or double quotes) or variable content::
|
||||||
|
|
||||||
<title>{% trans "This is the title." %}</title>
|
<title>{% translate "This is the title." %}</title>
|
||||||
<title>{% trans myvar %}</title>
|
<title>{% translate myvar %}</title>
|
||||||
|
|
||||||
If the ``noop`` option is present, variable lookup still takes place but the
|
If the ``noop`` option is present, variable lookup still takes place but the
|
||||||
translation is skipped. This is useful when "stubbing out" content that will
|
translation is skipped. This is useful when "stubbing out" content that will
|
||||||
require translation in the future::
|
require translation in the future::
|
||||||
|
|
||||||
<title>{% trans "myvar" noop %}</title>
|
<title>{% translate "myvar" noop %}</title>
|
||||||
|
|
||||||
Internally, inline translations use an
|
Internally, inline translations use an
|
||||||
:func:`~django.utils.translation.gettext` call.
|
:func:`~django.utils.translation.gettext` call.
|
||||||
|
@ -598,15 +599,14 @@ In case a template var (``myvar`` above) is passed to the tag, the tag will
|
||||||
first resolve such variable to a string at run-time and then look up that
|
first resolve such variable to a string at run-time and then look up that
|
||||||
string in the message catalogs.
|
string in the message catalogs.
|
||||||
|
|
||||||
It's not possible to mix a template variable inside a string within ``{% trans
|
It's not possible to mix a template variable inside a string within
|
||||||
%}``. If your translations require strings with variables (placeholders), use
|
``{% translate %}``. If your translations require strings with variables
|
||||||
:ttag:`{% blocktrans %}<blocktrans>` instead.
|
(placeholders), use :ttag:`{% blocktranslate %}<blocktranslate>` instead.
|
||||||
|
|
||||||
|
|
||||||
If you'd like to retrieve a translated string without displaying it, you can
|
If you'd like to retrieve a translated string without displaying it, you can
|
||||||
use the following syntax::
|
use the following syntax::
|
||||||
|
|
||||||
{% trans "This is the title" as the_title %}
|
{% translate "This is the title" as the_title %}
|
||||||
|
|
||||||
<title>{{ the_title }}</title>
|
<title>{{ the_title }}</title>
|
||||||
<meta name="description" content="{{ the_title }}">
|
<meta name="description" content="{{ the_title }}">
|
||||||
|
@ -615,12 +615,12 @@ In practice you'll use this to get a string you can use in multiple places in a
|
||||||
template or so you can use the output as an argument for other template tags or
|
template or so you can use the output as an argument for other template tags or
|
||||||
filters::
|
filters::
|
||||||
|
|
||||||
{% trans "starting point" as start %}
|
{% translate "starting point" as start %}
|
||||||
{% trans "end point" as end %}
|
{% translate "end point" as end %}
|
||||||
{% trans "La Grande Boucle" as race %}
|
{% translate "La Grande Boucle" as race %}
|
||||||
|
|
||||||
<h1>
|
<h1>
|
||||||
<a href="/" title="{% blocktrans %}Back to '{{ race }}' homepage{% endblocktrans %}">{{ race }}</a>
|
<a href="/" title="{% blocktranslate %}Back to '{{ race }}' homepage{% endblocktranslate %}">{{ race }}</a>
|
||||||
</h1>
|
</h1>
|
||||||
<p>
|
<p>
|
||||||
{% for stage in tour_stages %}
|
{% for stage in tour_stages %}
|
||||||
|
@ -628,50 +628,56 @@ filters::
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
``{% trans %}`` also supports :ref:`contextual markers<contextual-markers>`
|
``{% translate %}`` also supports :ref:`contextual markers<contextual-markers>`
|
||||||
using the ``context`` keyword:
|
using the ``context`` keyword:
|
||||||
|
|
||||||
.. code-block:: html+django
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% trans "May" context "month name" %}
|
{% translate "May" context "month name" %}
|
||||||
|
|
||||||
|
.. versionchanged:: 3.1
|
||||||
|
|
||||||
|
The ``trans`` tag was renamed to ``translate``. The ``trans``
|
||||||
|
tag is still supported as an alias for backwards compatibility.
|
||||||
|
|
||||||
.. templatetag:: blocktrans
|
.. templatetag:: blocktrans
|
||||||
|
.. templatetag:: blocktranslate
|
||||||
|
|
||||||
``blocktrans`` template tag
|
``blocktranslate`` template tag
|
||||||
---------------------------
|
-------------------------------
|
||||||
|
|
||||||
Contrarily to the :ttag:`trans` tag, the ``blocktrans`` tag allows you to mark
|
Contrarily to the :ttag:`translate` tag, the ``blocktranslate`` tag allows you
|
||||||
complex sentences consisting of literals and variable content for translation
|
to mark complex sentences consisting of literals and variable content for
|
||||||
by making use of placeholders::
|
translation by making use of placeholders::
|
||||||
|
|
||||||
{% blocktrans %}This string will have {{ value }} inside.{% endblocktrans %}
|
{% blocktranslate %}This string will have {{ value }} inside.{% endblocktranslate %}
|
||||||
|
|
||||||
To translate a template expression -- say, accessing object attributes or
|
To translate a template expression -- say, accessing object attributes or
|
||||||
using template filters -- you need to bind the expression to a local variable
|
using template filters -- you need to bind the expression to a local variable
|
||||||
for use within the translation block. Examples::
|
for use within the translation block. Examples::
|
||||||
|
|
||||||
{% blocktrans with amount=article.price %}
|
{% blocktranslate with amount=article.price %}
|
||||||
That will cost $ {{ amount }}.
|
That will cost $ {{ amount }}.
|
||||||
{% endblocktrans %}
|
{% endblocktranslate %}
|
||||||
|
|
||||||
{% blocktrans with myvar=value|filter %}
|
{% blocktranslate with myvar=value|filter %}
|
||||||
This will have {{ myvar }} inside.
|
This will have {{ myvar }} inside.
|
||||||
{% endblocktrans %}
|
{% endblocktranslate %}
|
||||||
|
|
||||||
You can use multiple expressions inside a single ``blocktrans`` tag::
|
You can use multiple expressions inside a single ``blocktranslate`` tag::
|
||||||
|
|
||||||
{% blocktrans with book_t=book|title author_t=author|title %}
|
{% blocktranslate with book_t=book|title author_t=author|title %}
|
||||||
This is {{ book_t }} by {{ author_t }}
|
This is {{ book_t }} by {{ author_t }}
|
||||||
{% endblocktrans %}
|
{% endblocktranslate %}
|
||||||
|
|
||||||
.. note:: The previous more verbose format is still supported:
|
.. note:: The previous more verbose format is still supported:
|
||||||
``{% blocktrans with book|title as book_t and author|title as author_t %}``
|
``{% blocktranslate with book|title as book_t and author|title as author_t %}``
|
||||||
|
|
||||||
Other block tags (for example ``{% for %}`` or ``{% if %}``) are not allowed
|
Other block tags (for example ``{% for %}`` or ``{% if %}``) are not allowed
|
||||||
inside a ``blocktrans`` tag.
|
inside a ``blocktranslate`` tag.
|
||||||
|
|
||||||
If resolving one of the block arguments fails, ``blocktrans`` will fall back to
|
If resolving one of the block arguments fails, ``blocktranslate`` will fall
|
||||||
the default language by deactivating the currently active language
|
back to the default language by deactivating the currently active language
|
||||||
temporarily with the :func:`~django.utils.translation.deactivate_all`
|
temporarily with the :func:`~django.utils.translation.deactivate_all`
|
||||||
function.
|
function.
|
||||||
|
|
||||||
|
@ -681,43 +687,43 @@ This tag also provides for pluralization. To use it:
|
||||||
be the one used to select the right plural form.
|
be the one used to select the right plural form.
|
||||||
|
|
||||||
* Specify both the singular and plural forms separating them with the
|
* Specify both the singular and plural forms separating them with the
|
||||||
``{% plural %}`` tag within the ``{% blocktrans %}`` and
|
``{% plural %}`` tag within the ``{% blocktranslate %}`` and
|
||||||
``{% endblocktrans %}`` tags.
|
``{% endblocktranslate %}`` tags.
|
||||||
|
|
||||||
An example::
|
An example::
|
||||||
|
|
||||||
{% blocktrans count counter=list|length %}
|
{% blocktranslate count counter=list|length %}
|
||||||
There is only one {{ name }} object.
|
There is only one {{ name }} object.
|
||||||
{% plural %}
|
{% plural %}
|
||||||
There are {{ counter }} {{ name }} objects.
|
There are {{ counter }} {{ name }} objects.
|
||||||
{% endblocktrans %}
|
{% endblocktranslate %}
|
||||||
|
|
||||||
A more complex example::
|
A more complex example::
|
||||||
|
|
||||||
{% blocktrans with amount=article.price count years=i.length %}
|
{% blocktranslate with amount=article.price count years=i.length %}
|
||||||
That will cost $ {{ amount }} per year.
|
That will cost $ {{ amount }} per year.
|
||||||
{% plural %}
|
{% plural %}
|
||||||
That will cost $ {{ amount }} per {{ years }} years.
|
That will cost $ {{ amount }} per {{ years }} years.
|
||||||
{% endblocktrans %}
|
{% endblocktranslate %}
|
||||||
|
|
||||||
When you use both the pluralization feature and bind values to local variables
|
When you use both the pluralization feature and bind values to local variables
|
||||||
in addition to the counter value, keep in mind that the ``blocktrans``
|
in addition to the counter value, keep in mind that the ``blocktranslate``
|
||||||
construct is internally converted to an ``ngettext`` call. This means the
|
construct is internally converted to an ``ngettext`` call. This means the
|
||||||
same :ref:`notes regarding ngettext variables <pluralization-var-notes>`
|
same :ref:`notes regarding ngettext variables <pluralization-var-notes>`
|
||||||
apply.
|
apply.
|
||||||
|
|
||||||
Reverse URL lookups cannot be carried out within the ``blocktrans`` and should
|
Reverse URL lookups cannot be carried out within the ``blocktranslate`` and
|
||||||
be retrieved (and stored) beforehand::
|
should be retrieved (and stored) beforehand::
|
||||||
|
|
||||||
{% url 'path.to.view' arg arg2 as the_url %}
|
{% url 'path.to.view' arg arg2 as the_url %}
|
||||||
{% blocktrans %}
|
{% blocktranslate %}
|
||||||
This is a URL: {{ the_url }}
|
This is a URL: {{ the_url }}
|
||||||
{% endblocktrans %}
|
{% endblocktranslate %}
|
||||||
|
|
||||||
If you'd like to retrieve a translated string without displaying it, you can
|
If you'd like to retrieve a translated string without displaying it, you can
|
||||||
use the following syntax::
|
use the following syntax::
|
||||||
|
|
||||||
{% blocktrans asvar the_title %}The title is {{ title }}.{% endblocktrans %}
|
{% blocktranslate asvar the_title %}The title is {{ title }}.{% endblocktranslate %}
|
||||||
<title>{{ the_title }}</title>
|
<title>{{ the_title }}</title>
|
||||||
<meta name="description" content="{{ the_title }}">
|
<meta name="description" content="{{ the_title }}">
|
||||||
|
|
||||||
|
@ -725,32 +731,38 @@ In practice you'll use this to get a string you can use in multiple places in a
|
||||||
template or so you can use the output as an argument for other template tags or
|
template or so you can use the output as an argument for other template tags or
|
||||||
filters.
|
filters.
|
||||||
|
|
||||||
``{% blocktrans %}`` also supports :ref:`contextual
|
``{% blocktranslate %}`` also supports :ref:`contextual
|
||||||
markers<contextual-markers>` using the ``context`` keyword:
|
markers<contextual-markers>` using the ``context`` keyword:
|
||||||
|
|
||||||
.. code-block:: html+django
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% blocktrans with name=user.username context "greeting" %}Hi {{ name }}{% endblocktrans %}
|
{% blocktranslate with name=user.username context "greeting" %}Hi {{ name }}{% endblocktranslate %}
|
||||||
|
|
||||||
Another feature ``{% blocktrans %}`` supports is the ``trimmed`` option. This
|
Another feature ``{% blocktranslate %}`` supports is the ``trimmed`` option.
|
||||||
option will remove newline characters from the beginning and the end of the
|
This option will remove newline characters from the beginning and the end of
|
||||||
content of the ``{% blocktrans %}`` tag, replace any whitespace at the beginning
|
the content of the ``{% blocktranslate %}`` tag, replace any whitespace at the
|
||||||
and end of a line and merge all lines into one using a space character to
|
beginning and end of a line and merge all lines into one using a space
|
||||||
separate them. This is quite useful for indenting the content of a ``{%
|
character to separate them. This is quite useful for indenting the content of a
|
||||||
blocktrans %}`` tag without having the indentation characters end up in the
|
``{% blocktranslate %}`` tag without having the indentation characters end up
|
||||||
corresponding entry in the PO file, which makes the translation process easier.
|
in the corresponding entry in the PO file, which makes the translation process
|
||||||
|
easier.
|
||||||
|
|
||||||
For instance, the following ``{% blocktrans %}`` tag::
|
For instance, the following ``{% blocktranslate %}`` tag::
|
||||||
|
|
||||||
{% blocktrans trimmed %}
|
{% blocktranslate trimmed %}
|
||||||
First sentence.
|
First sentence.
|
||||||
Second paragraph.
|
Second paragraph.
|
||||||
{% endblocktrans %}
|
{% endblocktranslate %}
|
||||||
|
|
||||||
will result in the entry ``"First sentence. Second paragraph."`` in the PO file,
|
will result in the entry ``"First sentence. Second paragraph."`` in the PO file,
|
||||||
compared to ``"\n First sentence.\n Second sentence.\n"``, if the ``trimmed``
|
compared to ``"\n First sentence.\n Second sentence.\n"``, if the ``trimmed``
|
||||||
option had not been specified.
|
option had not been specified.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.1
|
||||||
|
|
||||||
|
The ``blocktrans`` tag was renamed to ``blocktranslate``. The ``blocktrans``
|
||||||
|
tag is still supported as an alias for backwards compatibility.
|
||||||
|
|
||||||
String literals passed to tags and filters
|
String literals passed to tags and filters
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
|
@ -782,21 +794,21 @@ tag:
|
||||||
.. code-block:: html+django
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% comment %}Translators: View verb{% endcomment %}
|
{% comment %}Translators: View verb{% endcomment %}
|
||||||
{% trans "View" %}
|
{% translate "View" %}
|
||||||
|
|
||||||
{% comment %}Translators: Short intro blurb{% endcomment %}
|
{% comment %}Translators: Short intro blurb{% endcomment %}
|
||||||
<p>{% blocktrans %}A multiline translatable
|
<p>{% blocktranslate %}A multiline translatable
|
||||||
literal.{% endblocktrans %}</p>
|
literal.{% endblocktranslate %}</p>
|
||||||
|
|
||||||
or with the ``{#`` ... ``#}`` :ref:`one-line comment constructs <template-comments>`:
|
or with the ``{#`` ... ``#}`` :ref:`one-line comment constructs <template-comments>`:
|
||||||
|
|
||||||
.. code-block:: html+django
|
.. code-block:: html+django
|
||||||
|
|
||||||
{# Translators: Label of a button that triggers search #}
|
{# Translators: Label of a button that triggers search #}
|
||||||
<button type="submit">{% trans "Go" %}</button>
|
<button type="submit">{% translate "Go" %}</button>
|
||||||
|
|
||||||
{# Translators: This is a text of the base template #}
|
{# Translators: This is a text of the base template #}
|
||||||
{% blocktrans %}Ambiguous translatable block of text{% endblocktrans %}
|
{% blocktranslate %}Ambiguous translatable block of text{% endblocktranslate %}
|
||||||
|
|
||||||
.. note:: Just for completeness, these are the corresponding fragments of the
|
.. note:: Just for completeness, these are the corresponding fragments of the
|
||||||
resulting ``.po`` file:
|
resulting ``.po`` file:
|
||||||
|
@ -841,12 +853,12 @@ If you want to select a language within a template, you can use the
|
||||||
|
|
||||||
{% get_current_language as LANGUAGE_CODE %}
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
<!-- Current language: {{ LANGUAGE_CODE }} -->
|
<!-- Current language: {{ LANGUAGE_CODE }} -->
|
||||||
<p>{% trans "Welcome to our page" %}</p>
|
<p>{% translate "Welcome to our page" %}</p>
|
||||||
|
|
||||||
{% language 'en' %}
|
{% language 'en' %}
|
||||||
{% get_current_language as LANGUAGE_CODE %}
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
<!-- Current language: {{ LANGUAGE_CODE }} -->
|
<!-- Current language: {{ LANGUAGE_CODE }} -->
|
||||||
<p>{% trans "Welcome to our page" %}</p>
|
<p>{% translate "Welcome to our page" %}</p>
|
||||||
{% endlanguage %}
|
{% endlanguage %}
|
||||||
|
|
||||||
While the first occurrence of "Welcome to our page" uses the current language,
|
While the first occurrence of "Welcome to our page" uses the current language,
|
||||||
|
@ -1450,7 +1462,7 @@ template tag. It enables the given language in the enclosed template section:
|
||||||
|
|
||||||
{% get_available_languages as languages %}
|
{% get_available_languages as languages %}
|
||||||
|
|
||||||
{% trans "View this category in:" %}
|
{% translate "View this category in:" %}
|
||||||
{% for lang_code, lang_name in languages %}
|
{% for lang_code, lang_name in languages %}
|
||||||
{% language lang_code %}
|
{% language lang_code %}
|
||||||
<a href="{% url 'category' slug=category.slug %}">{{ lang_name }}</a>
|
<a href="{% url 'category' slug=category.slug %}">{{ lang_name }}</a>
|
||||||
|
|
|
@ -5,4 +5,4 @@ shouldn't create a .po file with duplicate `Plural-Forms` headers
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
{% blocktrans count number=3 %}{{ number }} Bar{% plural %}{{ number }} Bars{% endblocktrans %}
|
{% blocktrans count number=3 %}{{ number }} Bar{% plural %}{{ number }} Bars{% endblocktrans %}
|
||||||
|
|
||||||
{% trans 'First `trans`, then `blocktrans` with a plural' %}
|
{% translate 'First `translate`, then `blocktranslate` with a plural' %}
|
||||||
|
|
|
@ -85,9 +85,11 @@ continued here.{% endcomment %}
|
||||||
{% blocktrans context 'Special blocktrans context wrapped in single quotes' %}Translatable literal with context wrapped in single quotes{% endblocktrans %}
|
{% blocktrans context 'Special blocktrans context wrapped in single quotes' %}Translatable literal with context wrapped in single quotes{% endblocktrans %}
|
||||||
{% blocktrans context "Special blocktrans context wrapped in double quotes" %}Translatable literal with context wrapped in double quotes{% endblocktrans %}
|
{% blocktrans context "Special blocktrans context wrapped in double quotes" %}Translatable literal with context wrapped in double quotes{% endblocktrans %}
|
||||||
|
|
||||||
|
{% blocktranslate %}blocktranslate text{% endblocktranslate %}
|
||||||
|
{% translate "translate text" %}
|
||||||
|
|
||||||
{# BasicExtractorTests.test_blocktrans_trimmed #}
|
{# BasicExtractorTests.test_blocktranslate_trimmed #}
|
||||||
{% blocktrans %}
|
{% blocktranslate %}
|
||||||
Text with a few
|
Text with a few
|
||||||
line breaks.
|
line breaks.
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
|
@ -98,10 +100,10 @@ continued here.{% endcomment %}
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
{% trans "Get my line number" %}
|
{% trans "Get my line number" %}
|
||||||
|
|
||||||
{% blocktrans trimmed count counter=mylist|length %}
|
{% blocktranslate trimmed count counter=mylist|length %}
|
||||||
First `trans`, then `blocktrans` with a plural
|
First `translate`, then `blocktranslate` with a plural
|
||||||
{% plural %}
|
{% plural %}
|
||||||
Plural for a `trans` and `blocktrans` collision case
|
Plural for a `translate` and `blocktranslate` collision case
|
||||||
{% endblocktrans %}
|
{% endblocktranslate %}
|
||||||
|
|
||||||
{% trans "Non-breaking space :" %}
|
{% trans "Non-breaking space :" %}
|
||||||
|
|
|
@ -8,12 +8,13 @@ by using catalogs created from management commands.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
The string "Two %% Three %%%" renders differently using trans and blocktrans.
|
The string "Two %% Three %%%" renders differently using translate and
|
||||||
This issue is difficult to debug, it could be a problem with extraction,
|
blocktranslate. This issue is difficult to debug, it could be a problem with
|
||||||
interpolation, or both.
|
extraction, interpolation, or both.
|
||||||
|
|
||||||
How this script helps:
|
How this script helps:
|
||||||
* Add {% trans "Two %% Three %%%" %} and blocktrans equivalent to templates.
|
* Add {% translate "Two %% Three %%%" %} and blocktranslate equivalent to
|
||||||
|
templates.
|
||||||
* Run this script.
|
* Run this script.
|
||||||
* Test extraction - verify the new msgid in sampleproject's django.po.
|
* Test extraction - verify the new msgid in sampleproject's django.po.
|
||||||
* Add a translation to sampleproject's django.po.
|
* Add a translation to sampleproject's django.po.
|
||||||
|
|
|
@ -182,7 +182,7 @@ class BasicExtractorTests(ExtractorTests):
|
||||||
po_contents = fp.read()
|
po_contents = fp.read()
|
||||||
self.assertMsgId("Non-breaking space\u00a0:", po_contents)
|
self.assertMsgId("Non-breaking space\u00a0:", po_contents)
|
||||||
|
|
||||||
def test_blocktrans_trimmed(self):
|
def test_blocktranslate_trimmed(self):
|
||||||
management.call_command('makemessages', locale=[LOCALE], verbosity=0)
|
management.call_command('makemessages', locale=[LOCALE], verbosity=0)
|
||||||
self.assertTrue(os.path.exists(self.PO_FILE))
|
self.assertTrue(os.path.exists(self.PO_FILE))
|
||||||
with open(self.PO_FILE) as fp:
|
with open(self.PO_FILE) as fp:
|
||||||
|
@ -256,6 +256,10 @@ class BasicExtractorTests(ExtractorTests):
|
||||||
self.assertIn('msgctxt "Special blocktrans context #4"', po_contents)
|
self.assertIn('msgctxt "Special blocktrans context #4"', po_contents)
|
||||||
self.assertMsgId("Translatable literal #8d %(a)s", po_contents)
|
self.assertMsgId("Translatable literal #8d %(a)s", po_contents)
|
||||||
|
|
||||||
|
# {% translate %} and {% blocktranslate %}
|
||||||
|
self.assertMsgId('translate text', po_contents)
|
||||||
|
self.assertMsgId('blocktranslate text', po_contents)
|
||||||
|
|
||||||
def test_context_in_single_quotes(self):
|
def test_context_in_single_quotes(self):
|
||||||
management.call_command('makemessages', locale=[LOCALE], verbosity=0)
|
management.call_command('makemessages', locale=[LOCALE], verbosity=0)
|
||||||
self.assertTrue(os.path.exists(self.PO_FILE))
|
self.assertTrue(os.path.exists(self.PO_FILE))
|
||||||
|
@ -528,7 +532,7 @@ class CopyPluralFormsExtractorTests(ExtractorTests):
|
||||||
found = re.findall(r'^(?P<value>"Plural-Forms.+?\\n")\s*$', po_contents, re.MULTILINE | re.DOTALL)
|
found = re.findall(r'^(?P<value>"Plural-Forms.+?\\n")\s*$', po_contents, re.MULTILINE | re.DOTALL)
|
||||||
self.assertEqual(1, len(found))
|
self.assertEqual(1, len(found))
|
||||||
|
|
||||||
def test_trans_and_plural_blocktrans_collision(self):
|
def test_translate_and_plural_blocktranslate_collision(self):
|
||||||
"""
|
"""
|
||||||
Ensures a correct workaround for the gettext bug when handling a literal
|
Ensures a correct workaround for the gettext bug when handling a literal
|
||||||
found inside a {% trans %} tag and also in another file inside a
|
found inside a {% trans %} tag and also in another file inside a
|
||||||
|
@ -539,8 +543,8 @@ class CopyPluralFormsExtractorTests(ExtractorTests):
|
||||||
with open(self.PO_FILE) as fp:
|
with open(self.PO_FILE) as fp:
|
||||||
po_contents = fp.read()
|
po_contents = fp.read()
|
||||||
self.assertNotIn("#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\\n", po_contents)
|
self.assertNotIn("#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\\n", po_contents)
|
||||||
self.assertMsgId('First `trans`, then `blocktrans` with a plural', po_contents)
|
self.assertMsgId('First `translate`, then `blocktranslate` with a plural', po_contents)
|
||||||
self.assertMsgIdPlural('Plural for a `trans` and `blocktrans` collision case', po_contents)
|
self.assertMsgIdPlural('Plural for a `translate` and `blocktranslate` collision case', po_contents)
|
||||||
|
|
||||||
|
|
||||||
class NoWrapExtractorTests(ExtractorTests):
|
class NoWrapExtractorTests(ExtractorTests):
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
import inspect
|
||||||
import os
|
import os
|
||||||
|
from functools import partial, wraps
|
||||||
|
|
||||||
from asgiref.local import Local
|
from asgiref.local import Local
|
||||||
|
|
||||||
|
@ -8,10 +10,39 @@ from django.utils import translation
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import trans_real
|
from django.utils.translation import trans_real
|
||||||
|
|
||||||
from ...utils import setup
|
from ...utils import setup as base_setup
|
||||||
from .base import MultipleLocaleActivationTestCase, extended_locale_paths, here
|
from .base import MultipleLocaleActivationTestCase, extended_locale_paths, here
|
||||||
|
|
||||||
|
|
||||||
|
def setup(templates, *args, **kwargs):
|
||||||
|
blocktrans_setup = base_setup(templates, *args, **kwargs)
|
||||||
|
blocktranslate_setup = base_setup({
|
||||||
|
name: template.replace(
|
||||||
|
'{% blocktrans ', '{% blocktranslate '
|
||||||
|
).replace(
|
||||||
|
'{% endblocktrans %}', '{% endblocktranslate %}'
|
||||||
|
)
|
||||||
|
for name, template in templates.items()
|
||||||
|
})
|
||||||
|
|
||||||
|
tags = {
|
||||||
|
'blocktrans': blocktrans_setup,
|
||||||
|
'blocktranslate': blocktranslate_setup,
|
||||||
|
}
|
||||||
|
|
||||||
|
def decorator(func):
|
||||||
|
@wraps(func)
|
||||||
|
def inner(self, *args):
|
||||||
|
signature = inspect.signature(func)
|
||||||
|
for tag_name, setup_func in tags.items():
|
||||||
|
if 'tag_name' in signature.parameters:
|
||||||
|
setup_func(partial(func, tag_name=tag_name))(self)
|
||||||
|
else:
|
||||||
|
setup_func(func)(self)
|
||||||
|
return inner
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
class I18nBlockTransTagTests(SimpleTestCase):
|
class I18nBlockTransTagTests(SimpleTestCase):
|
||||||
libraries = {'i18n': 'django.templatetags.i18n'}
|
libraries = {'i18n': 'django.templatetags.i18n'}
|
||||||
|
|
||||||
|
@ -76,8 +107,8 @@ class I18nBlockTransTagTests(SimpleTestCase):
|
||||||
'{% blocktrans with berta=anton|escape %}{{ berta }}{% endblocktrans %}'})
|
'{% blocktrans with berta=anton|escape %}{{ berta }}{% endblocktrans %}'})
|
||||||
def test_i18n17(self):
|
def test_i18n17(self):
|
||||||
"""
|
"""
|
||||||
Escaping inside blocktrans and trans works as if it was directly in the
|
Escaping inside blocktranslate and translate works as if it was
|
||||||
template.
|
directly in the template.
|
||||||
"""
|
"""
|
||||||
output = self.engine.render_to_string('i18n17', {'anton': 'α & β'})
|
output = self.engine.render_to_string('i18n17', {'anton': 'α & β'})
|
||||||
self.assertEqual(output, 'α & β')
|
self.assertEqual(output, 'α & β')
|
||||||
|
@ -224,8 +255,8 @@ class I18nBlockTransTagTests(SimpleTestCase):
|
||||||
self.assertEqual(output, '>Error: Seite nicht gefunden<')
|
self.assertEqual(output, '>Error: Seite nicht gefunden<')
|
||||||
|
|
||||||
@setup({'template': '{% load i18n %}{% blocktrans asvar %}Yes{% endblocktrans %}'})
|
@setup({'template': '{% load i18n %}{% blocktrans asvar %}Yes{% endblocktrans %}'})
|
||||||
def test_blocktrans_syntax_error_missing_assignment(self):
|
def test_blocktrans_syntax_error_missing_assignment(self, tag_name):
|
||||||
msg = "No argument provided to the 'blocktrans' tag for the asvar option."
|
msg = "No argument provided to the '{}' tag for the asvar option.".format(tag_name)
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
self.engine.render_to_string('template')
|
self.engine.render_to_string('template')
|
||||||
|
|
||||||
|
@ -235,14 +266,14 @@ class I18nBlockTransTagTests(SimpleTestCase):
|
||||||
self.assertEqual(output, '%s')
|
self.assertEqual(output, '%s')
|
||||||
|
|
||||||
@setup({'template': '{% load i18n %}{% blocktrans %}{% block b %} {% endblock %}{% endblocktrans %}'})
|
@setup({'template': '{% load i18n %}{% blocktrans %}{% block b %} {% endblock %}{% endblocktrans %}'})
|
||||||
def test_with_block(self):
|
def test_with_block(self, tag_name):
|
||||||
msg = "'blocktrans' doesn't allow other block tags (seen 'block b') inside it"
|
msg = "'{}' doesn't allow other block tags (seen 'block b') inside it".format(tag_name)
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
self.engine.render_to_string('template')
|
self.engine.render_to_string('template')
|
||||||
|
|
||||||
@setup({'template': '{% load i18n %}{% blocktrans %}{% for b in [1, 2, 3] %} {% endfor %}{% endblocktrans %}'})
|
@setup({'template': '{% load i18n %}{% blocktrans %}{% for b in [1, 2, 3] %} {% endfor %}{% endblocktrans %}'})
|
||||||
def test_with_for(self):
|
def test_with_for(self, tag_name):
|
||||||
msg = "'blocktrans' doesn't allow other block tags (seen 'for b in [1, 2, 3]') inside it"
|
msg = "'{}' doesn't allow other block tags (seen 'for b in [1, 2, 3]') inside it".format(tag_name)
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
self.engine.render_to_string('template')
|
self.engine.render_to_string('template')
|
||||||
|
|
||||||
|
@ -252,14 +283,14 @@ class I18nBlockTransTagTests(SimpleTestCase):
|
||||||
self.engine.render_to_string('template', {'foo': 'bar'})
|
self.engine.render_to_string('template', {'foo': 'bar'})
|
||||||
|
|
||||||
@setup({'template': '{% load i18n %}{% blocktrans with %}{% endblocktrans %}'})
|
@setup({'template': '{% load i18n %}{% blocktrans with %}{% endblocktrans %}'})
|
||||||
def test_no_args_with(self):
|
def test_no_args_with(self, tag_name):
|
||||||
msg = '"with" in \'blocktrans\' tag needs at least one keyword argument.'
|
msg = '"with" in \'{}\' tag needs at least one keyword argument.'.format(tag_name)
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
self.engine.render_to_string('template')
|
self.engine.render_to_string('template')
|
||||||
|
|
||||||
@setup({'template': '{% load i18n %}{% blocktrans count a %}{% endblocktrans %}'})
|
@setup({'template': '{% load i18n %}{% blocktrans count a %}{% endblocktrans %}'})
|
||||||
def test_count(self):
|
def test_count(self, tag_name):
|
||||||
msg = '"count" in \'blocktrans\' tag expected exactly one keyword argument.'
|
msg = '"count" in \'{}\' tag expected exactly one keyword argument.'.format(tag_name)
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
self.engine.render_to_string('template', {'a': [1, 2, 3]})
|
self.engine.render_to_string('template', {'a': [1, 2, 3]})
|
||||||
|
|
||||||
|
@ -268,13 +299,25 @@ class I18nBlockTransTagTests(SimpleTestCase):
|
||||||
'There is {{ count }} object. {% block a %} {% endblock %}'
|
'There is {{ count }} object. {% block a %} {% endblock %}'
|
||||||
'{% endblocktrans %}'
|
'{% endblocktrans %}'
|
||||||
)})
|
)})
|
||||||
def test_plural_bad_syntax(self):
|
def test_plural_bad_syntax(self, tag_name):
|
||||||
msg = "'blocktrans' doesn't allow other block tags inside it"
|
msg = "'{}' doesn't allow other block tags inside it".format(tag_name)
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
self.engine.render_to_string('template', {'var': [1, 2, 3]})
|
self.engine.render_to_string('template', {'var': [1, 2, 3]})
|
||||||
|
|
||||||
|
|
||||||
class TranslationBlockTransTagTests(SimpleTestCase):
|
class TranslationBlockTransTagTests(SimpleTestCase):
|
||||||
|
tag_name = 'blocktrans'
|
||||||
|
|
||||||
|
def get_template(self, template_string):
|
||||||
|
return Template(
|
||||||
|
template_string.replace(
|
||||||
|
'{{% blocktrans ',
|
||||||
|
'{{% {}'.format(self.tag_name)
|
||||||
|
).replace(
|
||||||
|
'{{% endblocktrans %}}',
|
||||||
|
'{{% end{} %}}'.format(self.tag_name)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(LOCALE_PATHS=extended_locale_paths)
|
@override_settings(LOCALE_PATHS=extended_locale_paths)
|
||||||
def test_template_tags_pgettext(self):
|
def test_template_tags_pgettext(self):
|
||||||
|
@ -283,54 +326,58 @@ class TranslationBlockTransTagTests(SimpleTestCase):
|
||||||
trans_real._translations = {}
|
trans_real._translations = {}
|
||||||
with translation.override('de'):
|
with translation.override('de'):
|
||||||
# Nonexistent context
|
# Nonexistent context
|
||||||
t = Template('{% load i18n %}{% blocktrans context "nonexistent" %}May{% endblocktrans %}')
|
t = self.get_template('{% load i18n %}{% blocktrans context "nonexistent" %}May{% endblocktrans %}')
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, 'May')
|
self.assertEqual(rendered, 'May')
|
||||||
|
|
||||||
# Existing context... using a literal
|
# Existing context... using a literal
|
||||||
t = Template('{% load i18n %}{% blocktrans context "month name" %}May{% endblocktrans %}')
|
t = self.get_template('{% load i18n %}{% blocktrans context "month name" %}May{% endblocktrans %}')
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, 'Mai')
|
self.assertEqual(rendered, 'Mai')
|
||||||
t = Template('{% load i18n %}{% blocktrans context "verb" %}May{% endblocktrans %}')
|
t = self.get_template('{% load i18n %}{% blocktrans context "verb" %}May{% endblocktrans %}')
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, 'Kann')
|
self.assertEqual(rendered, 'Kann')
|
||||||
|
|
||||||
# Using a variable
|
# Using a variable
|
||||||
t = Template('{% load i18n %}{% blocktrans context message_context %}May{% endblocktrans %}')
|
t = self.get_template('{% load i18n %}{% blocktrans context message_context %}May{% endblocktrans %}')
|
||||||
rendered = t.render(Context({'message_context': 'month name'}))
|
rendered = t.render(Context({'message_context': 'month name'}))
|
||||||
self.assertEqual(rendered, 'Mai')
|
self.assertEqual(rendered, 'Mai')
|
||||||
t = Template('{% load i18n %}{% blocktrans context message_context %}May{% endblocktrans %}')
|
t = self.get_template('{% load i18n %}{% blocktrans context message_context %}May{% endblocktrans %}')
|
||||||
rendered = t.render(Context({'message_context': 'verb'}))
|
rendered = t.render(Context({'message_context': 'verb'}))
|
||||||
self.assertEqual(rendered, 'Kann')
|
self.assertEqual(rendered, 'Kann')
|
||||||
|
|
||||||
# Using a filter
|
# Using a filter
|
||||||
t = Template('{% load i18n %}{% blocktrans context message_context|lower %}May{% endblocktrans %}')
|
t = self.get_template(
|
||||||
|
'{% load i18n %}{% blocktrans context message_context|lower %}May{% endblocktrans %}'
|
||||||
|
)
|
||||||
rendered = t.render(Context({'message_context': 'MONTH NAME'}))
|
rendered = t.render(Context({'message_context': 'MONTH NAME'}))
|
||||||
self.assertEqual(rendered, 'Mai')
|
self.assertEqual(rendered, 'Mai')
|
||||||
t = Template('{% load i18n %}{% blocktrans context message_context|lower %}May{% endblocktrans %}')
|
t = self.get_template(
|
||||||
|
'{% load i18n %}{% blocktrans context message_context|lower %}May{% endblocktrans %}'
|
||||||
|
)
|
||||||
rendered = t.render(Context({'message_context': 'VERB'}))
|
rendered = t.render(Context({'message_context': 'VERB'}))
|
||||||
self.assertEqual(rendered, 'Kann')
|
self.assertEqual(rendered, 'Kann')
|
||||||
|
|
||||||
# Using 'count'
|
# Using 'count'
|
||||||
t = Template(
|
t = self.get_template(
|
||||||
'{% load i18n %}{% blocktrans count number=1 context "super search" %}'
|
'{% load i18n %}{% blocktrans count number=1 context "super search" %}'
|
||||||
'{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}'
|
'{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}'
|
||||||
)
|
)
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, '1 Super-Ergebnis')
|
self.assertEqual(rendered, '1 Super-Ergebnis')
|
||||||
t = Template(
|
t = self.get_template(
|
||||||
'{% load i18n %}{% blocktrans count number=2 context "super search" %}{{ number }}'
|
'{% load i18n %}{% blocktrans count number=2 context "super search" %}{{ number }}'
|
||||||
' super result{% plural %}{{ number }} super results{% endblocktrans %}'
|
' super result{% plural %}{{ number }} super results{% endblocktrans %}'
|
||||||
)
|
)
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, '2 Super-Ergebnisse')
|
self.assertEqual(rendered, '2 Super-Ergebnisse')
|
||||||
t = Template(
|
t = self.get_template(
|
||||||
'{% load i18n %}{% blocktrans context "other super search" count number=1 %}'
|
'{% load i18n %}{% blocktrans context "other super search" count number=1 %}'
|
||||||
'{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}'
|
'{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}'
|
||||||
)
|
)
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, '1 anderen Super-Ergebnis')
|
self.assertEqual(rendered, '1 anderen Super-Ergebnis')
|
||||||
t = Template(
|
t = self.get_template(
|
||||||
'{% load i18n %}{% blocktrans context "other super search" count number=2 %}'
|
'{% load i18n %}{% blocktrans context "other super search" count number=2 %}'
|
||||||
'{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}'
|
'{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}'
|
||||||
)
|
)
|
||||||
|
@ -338,13 +385,13 @@ class TranslationBlockTransTagTests(SimpleTestCase):
|
||||||
self.assertEqual(rendered, '2 andere Super-Ergebnisse')
|
self.assertEqual(rendered, '2 andere Super-Ergebnisse')
|
||||||
|
|
||||||
# Using 'with'
|
# Using 'with'
|
||||||
t = Template(
|
t = self.get_template(
|
||||||
'{% load i18n %}{% blocktrans with num_comments=5 context "comment count" %}'
|
'{% load i18n %}{% blocktrans with num_comments=5 context "comment count" %}'
|
||||||
'There are {{ num_comments }} comments{% endblocktrans %}'
|
'There are {{ num_comments }} comments{% endblocktrans %}'
|
||||||
)
|
)
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, 'Es gibt 5 Kommentare')
|
self.assertEqual(rendered, 'Es gibt 5 Kommentare')
|
||||||
t = Template(
|
t = self.get_template(
|
||||||
'{% load i18n %}{% blocktrans with num_comments=5 context "other comment count" %}'
|
'{% load i18n %}{% blocktrans with num_comments=5 context "other comment count" %}'
|
||||||
'There are {{ num_comments }} comments{% endblocktrans %}'
|
'There are {{ num_comments }} comments{% endblocktrans %}'
|
||||||
)
|
)
|
||||||
|
@ -352,19 +399,19 @@ class TranslationBlockTransTagTests(SimpleTestCase):
|
||||||
self.assertEqual(rendered, 'Andere: Es gibt 5 Kommentare')
|
self.assertEqual(rendered, 'Andere: Es gibt 5 Kommentare')
|
||||||
|
|
||||||
# Using trimmed
|
# Using trimmed
|
||||||
t = Template(
|
t = self.get_template(
|
||||||
'{% load i18n %}{% blocktrans trimmed %}\n\nThere\n\t are 5 '
|
'{% load i18n %}{% blocktrans trimmed %}\n\nThere\n\t are 5 '
|
||||||
'\n\n comments\n{% endblocktrans %}'
|
'\n\n comments\n{% endblocktrans %}'
|
||||||
)
|
)
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, 'There are 5 comments')
|
self.assertEqual(rendered, 'There are 5 comments')
|
||||||
t = Template(
|
t = self.get_template(
|
||||||
'{% load i18n %}{% blocktrans with num_comments=5 context "comment count" trimmed %}\n\n'
|
'{% load i18n %}{% blocktrans with num_comments=5 context "comment count" trimmed %}\n\n'
|
||||||
'There are \t\n \t {{ num_comments }} comments\n\n{% endblocktrans %}'
|
'There are \t\n \t {{ num_comments }} comments\n\n{% endblocktrans %}'
|
||||||
)
|
)
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, 'Es gibt 5 Kommentare')
|
self.assertEqual(rendered, 'Es gibt 5 Kommentare')
|
||||||
t = Template(
|
t = self.get_template(
|
||||||
'{% load i18n %}{% blocktrans context "other super search" count number=2 trimmed %}\n'
|
'{% load i18n %}{% blocktrans context "other super search" count number=2 trimmed %}\n'
|
||||||
'{{ number }} super \n result{% plural %}{{ number }} super results{% endblocktrans %}'
|
'{{ number }} super \n result{% plural %}{{ number }} super results{% endblocktrans %}'
|
||||||
)
|
)
|
||||||
|
@ -374,12 +421,14 @@ class TranslationBlockTransTagTests(SimpleTestCase):
|
||||||
# Misuses
|
# Misuses
|
||||||
msg = "Unknown argument for 'blocktrans' tag: %r."
|
msg = "Unknown argument for 'blocktrans' tag: %r."
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg % 'month="May"'):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg % 'month="May"'):
|
||||||
Template('{% load i18n %}{% blocktrans context with month="May" %}{{ month }}{% endblocktrans %}')
|
self.get_template(
|
||||||
|
'{% load i18n %}{% blocktrans context with month="May" %}{{ month }}{% endblocktrans %}'
|
||||||
|
)
|
||||||
msg = '"context" in %r tag expected exactly one argument.' % 'blocktrans'
|
msg = '"context" in %r tag expected exactly one argument.' % 'blocktrans'
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
Template('{% load i18n %}{% blocktrans context %}{% endblocktrans %}')
|
self.get_template('{% load i18n %}{% blocktrans context %}{% endblocktrans %}')
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
Template(
|
self.get_template(
|
||||||
'{% load i18n %}{% blocktrans count number=2 context %}'
|
'{% load i18n %}{% blocktrans count number=2 context %}'
|
||||||
'{{ number }} super result{% plural %}{{ number }}'
|
'{{ number }} super result{% plural %}{{ number }}'
|
||||||
' super results{% endblocktrans %}'
|
' super results{% endblocktrans %}'
|
||||||
|
@ -409,7 +458,23 @@ class TranslationBlockTransTagTests(SimpleTestCase):
|
||||||
self.assertEqual(rendered, 'My other name is James.')
|
self.assertEqual(rendered, 'My other name is James.')
|
||||||
|
|
||||||
|
|
||||||
|
class TranslationBlockTranslationTagTests(TranslationBlockTransTagTests):
|
||||||
|
tag_name = 'blocktranslation'
|
||||||
|
|
||||||
|
|
||||||
class MultipleLocaleActivationBlockTransTests(MultipleLocaleActivationTestCase):
|
class MultipleLocaleActivationBlockTransTests(MultipleLocaleActivationTestCase):
|
||||||
|
tag_name = 'blocktrans'
|
||||||
|
|
||||||
|
def get_template(self, template_string):
|
||||||
|
return Template(
|
||||||
|
template_string.replace(
|
||||||
|
'{{% blocktrans ',
|
||||||
|
'{{% {}'.format(self.tag_name)
|
||||||
|
).replace(
|
||||||
|
'{{% endblocktrans %}}',
|
||||||
|
'{{% end{} %}}'.format(self.tag_name)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def test_single_locale_activation(self):
|
def test_single_locale_activation(self):
|
||||||
"""
|
"""
|
||||||
|
@ -418,35 +483,51 @@ class MultipleLocaleActivationBlockTransTests(MultipleLocaleActivationTestCase):
|
||||||
"""
|
"""
|
||||||
with translation.override('fr'):
|
with translation.override('fr'):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
Template("{% load i18n %}{% blocktrans %}Yes{% endblocktrans %}").render(Context({})),
|
self.get_template("{% load i18n %}{% blocktrans %}Yes{% endblocktrans %}").render(Context({})),
|
||||||
'Oui'
|
'Oui'
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_multiple_locale_btrans(self):
|
def test_multiple_locale_btrans(self):
|
||||||
with translation.override('de'):
|
with translation.override('de'):
|
||||||
t = Template("{% load i18n %}{% blocktrans %}No{% endblocktrans %}")
|
t = self.get_template("{% load i18n %}{% blocktrans %}No{% endblocktrans %}")
|
||||||
with translation.override(self._old_language), translation.override('nl'):
|
with translation.override(self._old_language), translation.override('nl'):
|
||||||
self.assertEqual(t.render(Context({})), 'Nee')
|
self.assertEqual(t.render(Context({})), 'Nee')
|
||||||
|
|
||||||
def test_multiple_locale_deactivate_btrans(self):
|
def test_multiple_locale_deactivate_btrans(self):
|
||||||
with translation.override('de', deactivate=True):
|
with translation.override('de', deactivate=True):
|
||||||
t = Template("{% load i18n %}{% blocktrans %}No{% endblocktrans %}")
|
t = self.get_template("{% load i18n %}{% blocktrans %}No{% endblocktrans %}")
|
||||||
with translation.override('nl'):
|
with translation.override('nl'):
|
||||||
self.assertEqual(t.render(Context({})), 'Nee')
|
self.assertEqual(t.render(Context({})), 'Nee')
|
||||||
|
|
||||||
def test_multiple_locale_direct_switch_btrans(self):
|
def test_multiple_locale_direct_switch_btrans(self):
|
||||||
with translation.override('de'):
|
with translation.override('de'):
|
||||||
t = Template("{% load i18n %}{% blocktrans %}No{% endblocktrans %}")
|
t = self.get_template("{% load i18n %}{% blocktrans %}No{% endblocktrans %}")
|
||||||
with translation.override('nl'):
|
with translation.override('nl'):
|
||||||
self.assertEqual(t.render(Context({})), 'Nee')
|
self.assertEqual(t.render(Context({})), 'Nee')
|
||||||
|
|
||||||
|
|
||||||
|
class MultipleLocaleActivationBlockTranslationTests(MultipleLocaleActivationBlockTransTests):
|
||||||
|
tag_name = 'blocktranslation'
|
||||||
|
|
||||||
|
|
||||||
class MiscTests(SimpleTestCase):
|
class MiscTests(SimpleTestCase):
|
||||||
|
tag_name = 'blocktranslate'
|
||||||
|
|
||||||
|
def get_template(self, template_string):
|
||||||
|
return Template(
|
||||||
|
template_string.replace(
|
||||||
|
'{{% blocktrans ',
|
||||||
|
'{{% {}'.format(self.tag_name)
|
||||||
|
).replace(
|
||||||
|
'{{% endblocktrans %}}',
|
||||||
|
'{{% end{} %}}'.format(self.tag_name)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(LOCALE_PATHS=extended_locale_paths)
|
@override_settings(LOCALE_PATHS=extended_locale_paths)
|
||||||
def test_percent_in_translatable_block(self):
|
def test_percent_in_translatable_block(self):
|
||||||
t_sing = Template("{% load i18n %}{% blocktrans %}The result was {{ percent }}%{% endblocktrans %}")
|
t_sing = self.get_template("{% load i18n %}{% blocktrans %}The result was {{ percent }}%{% endblocktrans %}")
|
||||||
t_plur = Template(
|
t_plur = self.get_template(
|
||||||
"{% load i18n %}{% blocktrans count num as number %}"
|
"{% load i18n %}{% blocktrans count num as number %}"
|
||||||
"{{ percent }}% represents {{ num }} object{% plural %}"
|
"{{ percent }}% represents {{ num }} object{% plural %}"
|
||||||
"{{ percent }}% represents {{ num }} objects{% endblocktrans %}"
|
"{{ percent }}% represents {{ num }} objects{% endblocktrans %}"
|
||||||
|
@ -457,13 +538,15 @@ class MiscTests(SimpleTestCase):
|
||||||
self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 4})), '42% stellt 4 Objekte dar')
|
self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 4})), '42% stellt 4 Objekte dar')
|
||||||
|
|
||||||
@override_settings(LOCALE_PATHS=extended_locale_paths)
|
@override_settings(LOCALE_PATHS=extended_locale_paths)
|
||||||
def test_percent_formatting_in_blocktrans(self):
|
def test_percent_formatting_in_blocktranslate(self):
|
||||||
"""
|
"""
|
||||||
Python's %-formatting is properly escaped in blocktrans, singular, or
|
Python's %-formatting is properly escaped in blocktranslate, singular,
|
||||||
plural.
|
or plural.
|
||||||
"""
|
"""
|
||||||
t_sing = Template("{% load i18n %}{% blocktrans %}There are %(num_comments)s comments{% endblocktrans %}")
|
t_sing = self.get_template(
|
||||||
t_plur = Template(
|
"{% load i18n %}{% blocktrans %}There are %(num_comments)s comments{% endblocktrans %}"
|
||||||
|
)
|
||||||
|
t_plur = self.get_template(
|
||||||
"{% load i18n %}{% blocktrans count num as number %}"
|
"{% load i18n %}{% blocktrans count num as number %}"
|
||||||
"%(percent)s% represents {{ num }} object{% plural %}"
|
"%(percent)s% represents {{ num }} object{% plural %}"
|
||||||
"%(percent)s% represents {{ num }} objects{% endblocktrans %}"
|
"%(percent)s% represents {{ num }} objects{% endblocktrans %}"
|
||||||
|
@ -473,3 +556,7 @@ class MiscTests(SimpleTestCase):
|
||||||
self.assertEqual(t_sing.render(Context({'num_comments': 42})), 'There are %(num_comments)s comments')
|
self.assertEqual(t_sing.render(Context({'num_comments': 42})), 'There are %(num_comments)s comments')
|
||||||
self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 1})), '%(percent)s% represents 1 object')
|
self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 1})), '%(percent)s% represents 1 object')
|
||||||
self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 4})), '%(percent)s% represents 4 objects')
|
self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 4})), '%(percent)s% represents 4 objects')
|
||||||
|
|
||||||
|
|
||||||
|
class MiscBlockTranslationTests(MiscTests):
|
||||||
|
tag_name = 'blocktrans'
|
|
@ -1,3 +1,6 @@
|
||||||
|
import inspect
|
||||||
|
from functools import partial, wraps
|
||||||
|
|
||||||
from asgiref.local import Local
|
from asgiref.local import Local
|
||||||
|
|
||||||
from django.template import Context, Template, TemplateSyntaxError
|
from django.template import Context, Template, TemplateSyntaxError
|
||||||
|
@ -7,10 +10,35 @@ from django.utils import translation
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import trans_real
|
from django.utils.translation import trans_real
|
||||||
|
|
||||||
from ...utils import setup
|
from ...utils import setup as base_setup
|
||||||
from .base import MultipleLocaleActivationTestCase, extended_locale_paths
|
from .base import MultipleLocaleActivationTestCase, extended_locale_paths
|
||||||
|
|
||||||
|
|
||||||
|
def setup(templates, *args, **kwargs):
|
||||||
|
trans_setup = base_setup(templates, *args, **kwargs)
|
||||||
|
translate_setup = base_setup({
|
||||||
|
name: template.replace('{% trans ', '{% translate ')
|
||||||
|
for name, template in templates.items()
|
||||||
|
})
|
||||||
|
|
||||||
|
tags = {
|
||||||
|
'trans': trans_setup,
|
||||||
|
'translate': translate_setup,
|
||||||
|
}
|
||||||
|
|
||||||
|
def decorator(func):
|
||||||
|
@wraps(func)
|
||||||
|
def inner(self, *args):
|
||||||
|
signature = inspect.signature(func)
|
||||||
|
for tag_name, setup_func in tags.items():
|
||||||
|
if 'tag_name' in signature.parameters:
|
||||||
|
setup_func(partial(func, tag_name=tag_name))(self)
|
||||||
|
else:
|
||||||
|
setup_func(func)(self)
|
||||||
|
return inner
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
class I18nTransTagTests(SimpleTestCase):
|
class I18nTransTagTests(SimpleTestCase):
|
||||||
libraries = {'i18n': 'django.templatetags.i18n'}
|
libraries = {'i18n': 'django.templatetags.i18n'}
|
||||||
|
|
||||||
|
@ -84,38 +112,38 @@ class I18nTransTagTests(SimpleTestCase):
|
||||||
self.assertEqual(output, 'Page not found')
|
self.assertEqual(output, 'Page not found')
|
||||||
|
|
||||||
@setup({'template': '{% load i18n %}{% trans %}A}'})
|
@setup({'template': '{% load i18n %}{% trans %}A}'})
|
||||||
def test_syntax_error_no_arguments(self):
|
def test_syntax_error_no_arguments(self, tag_name):
|
||||||
msg = "'trans' takes at least one argument"
|
msg = "'{}' takes at least one argument".format(tag_name)
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
self.engine.render_to_string('template')
|
self.engine.render_to_string('template')
|
||||||
|
|
||||||
@setup({'template': '{% load i18n %}{% trans "Yes" badoption %}'})
|
@setup({'template': '{% load i18n %}{% trans "Yes" badoption %}'})
|
||||||
def test_syntax_error_bad_option(self):
|
def test_syntax_error_bad_option(self, tag_name):
|
||||||
msg = "Unknown argument for 'trans' tag: 'badoption'"
|
msg = "Unknown argument for '{}' tag: 'badoption'".format(tag_name)
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
self.engine.render_to_string('template')
|
self.engine.render_to_string('template')
|
||||||
|
|
||||||
@setup({'template': '{% load i18n %}{% trans "Yes" as %}'})
|
@setup({'template': '{% load i18n %}{% trans "Yes" as %}'})
|
||||||
def test_syntax_error_missing_assignment(self):
|
def test_syntax_error_missing_assignment(self, tag_name):
|
||||||
msg = "No argument provided to the 'trans' tag for the as option."
|
msg = "No argument provided to the '{}' tag for the as option.".format(tag_name)
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
self.engine.render_to_string('template')
|
self.engine.render_to_string('template')
|
||||||
|
|
||||||
@setup({'template': '{% load i18n %}{% trans "Yes" as var context %}'})
|
@setup({'template': '{% load i18n %}{% trans "Yes" as var context %}'})
|
||||||
def test_syntax_error_missing_context(self):
|
def test_syntax_error_missing_context(self, tag_name):
|
||||||
msg = "No argument provided to the 'trans' tag for the context option."
|
msg = "No argument provided to the '{}' tag for the context option.".format(tag_name)
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
self.engine.render_to_string('template')
|
self.engine.render_to_string('template')
|
||||||
|
|
||||||
@setup({'template': '{% load i18n %}{% trans "Yes" context as var %}'})
|
@setup({'template': '{% load i18n %}{% trans "Yes" context as var %}'})
|
||||||
def test_syntax_error_context_as(self):
|
def test_syntax_error_context_as(self, tag_name):
|
||||||
msg = "Invalid argument 'as' provided to the 'trans' tag for the context option"
|
msg = "Invalid argument 'as' provided to the '{}' tag for the context option".format(tag_name)
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
self.engine.render_to_string('template')
|
self.engine.render_to_string('template')
|
||||||
|
|
||||||
@setup({'template': '{% load i18n %}{% trans "Yes" context noop %}'})
|
@setup({'template': '{% load i18n %}{% trans "Yes" context noop %}'})
|
||||||
def test_syntax_error_context_noop(self):
|
def test_syntax_error_context_noop(self, tag_name):
|
||||||
msg = "Invalid argument 'noop' provided to the 'trans' tag for the context option"
|
msg = "Invalid argument 'noop' provided to the '{}' tag for the context option".format(tag_name)
|
||||||
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
with self.assertRaisesMessage(TemplateSyntaxError, msg):
|
||||||
self.engine.render_to_string('template')
|
self.engine.render_to_string('template')
|
||||||
|
|
||||||
|
@ -132,6 +160,15 @@ class I18nTransTagTests(SimpleTestCase):
|
||||||
|
|
||||||
|
|
||||||
class TranslationTransTagTests(SimpleTestCase):
|
class TranslationTransTagTests(SimpleTestCase):
|
||||||
|
tag_name = 'trans'
|
||||||
|
|
||||||
|
def get_template(self, template_string):
|
||||||
|
return Template(
|
||||||
|
template_string.replace(
|
||||||
|
'{{% trans ',
|
||||||
|
'{{% {}'.format(self.tag_name)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(LOCALE_PATHS=extended_locale_paths)
|
@override_settings(LOCALE_PATHS=extended_locale_paths)
|
||||||
def test_template_tags_pgettext(self):
|
def test_template_tags_pgettext(self):
|
||||||
|
@ -140,44 +177,57 @@ class TranslationTransTagTests(SimpleTestCase):
|
||||||
trans_real._translations = {}
|
trans_real._translations = {}
|
||||||
with translation.override('de'):
|
with translation.override('de'):
|
||||||
# Nonexistent context...
|
# Nonexistent context...
|
||||||
t = Template('{% load i18n %}{% trans "May" context "nonexistent" %}')
|
t = self.get_template('{% load i18n %}{% trans "May" context "nonexistent" %}')
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, 'May')
|
self.assertEqual(rendered, 'May')
|
||||||
|
|
||||||
# Existing context... using a literal
|
# Existing context... using a literal
|
||||||
t = Template('{% load i18n %}{% trans "May" context "month name" %}')
|
t = self.get_template('{% load i18n %}{% trans "May" context "month name" %}')
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, 'Mai')
|
self.assertEqual(rendered, 'Mai')
|
||||||
t = Template('{% load i18n %}{% trans "May" context "verb" %}')
|
t = self.get_template('{% load i18n %}{% trans "May" context "verb" %}')
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, 'Kann')
|
self.assertEqual(rendered, 'Kann')
|
||||||
|
|
||||||
# Using a variable
|
# Using a variable
|
||||||
t = Template('{% load i18n %}{% trans "May" context message_context %}')
|
t = self.get_template('{% load i18n %}{% trans "May" context message_context %}')
|
||||||
rendered = t.render(Context({'message_context': 'month name'}))
|
rendered = t.render(Context({'message_context': 'month name'}))
|
||||||
self.assertEqual(rendered, 'Mai')
|
self.assertEqual(rendered, 'Mai')
|
||||||
t = Template('{% load i18n %}{% trans "May" context message_context %}')
|
t = self.get_template('{% load i18n %}{% trans "May" context message_context %}')
|
||||||
rendered = t.render(Context({'message_context': 'verb'}))
|
rendered = t.render(Context({'message_context': 'verb'}))
|
||||||
self.assertEqual(rendered, 'Kann')
|
self.assertEqual(rendered, 'Kann')
|
||||||
|
|
||||||
# Using a filter
|
# Using a filter
|
||||||
t = Template('{% load i18n %}{% trans "May" context message_context|lower %}')
|
t = self.get_template('{% load i18n %}{% trans "May" context message_context|lower %}')
|
||||||
rendered = t.render(Context({'message_context': 'MONTH NAME'}))
|
rendered = t.render(Context({'message_context': 'MONTH NAME'}))
|
||||||
self.assertEqual(rendered, 'Mai')
|
self.assertEqual(rendered, 'Mai')
|
||||||
t = Template('{% load i18n %}{% trans "May" context message_context|lower %}')
|
t = self.get_template('{% load i18n %}{% trans "May" context message_context|lower %}')
|
||||||
rendered = t.render(Context({'message_context': 'VERB'}))
|
rendered = t.render(Context({'message_context': 'VERB'}))
|
||||||
self.assertEqual(rendered, 'Kann')
|
self.assertEqual(rendered, 'Kann')
|
||||||
|
|
||||||
# Using 'as'
|
# Using 'as'
|
||||||
t = Template('{% load i18n %}{% trans "May" context "month name" as var %}Value: {{ var }}')
|
t = self.get_template('{% load i18n %}{% trans "May" context "month name" as var %}Value: {{ var }}')
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, 'Value: Mai')
|
self.assertEqual(rendered, 'Value: Mai')
|
||||||
t = Template('{% load i18n %}{% trans "May" as var context "verb" %}Value: {{ var }}')
|
t = self.get_template('{% load i18n %}{% trans "May" as var context "verb" %}Value: {{ var }}')
|
||||||
rendered = t.render(Context())
|
rendered = t.render(Context())
|
||||||
self.assertEqual(rendered, 'Value: Kann')
|
self.assertEqual(rendered, 'Value: Kann')
|
||||||
|
|
||||||
|
|
||||||
|
class TranslationTranslateTagTests(TranslationTransTagTests):
|
||||||
|
tag_name = 'translate'
|
||||||
|
|
||||||
|
|
||||||
class MultipleLocaleActivationTransTagTests(MultipleLocaleActivationTestCase):
|
class MultipleLocaleActivationTransTagTests(MultipleLocaleActivationTestCase):
|
||||||
|
tag_name = 'trans'
|
||||||
|
|
||||||
|
def get_template(self, template_string):
|
||||||
|
return Template(
|
||||||
|
template_string.replace(
|
||||||
|
'{{% trans ',
|
||||||
|
'{{% {}'.format(self.tag_name)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def test_single_locale_activation(self):
|
def test_single_locale_activation(self):
|
||||||
"""
|
"""
|
||||||
|
@ -185,27 +235,34 @@ class MultipleLocaleActivationTransTagTests(MultipleLocaleActivationTestCase):
|
||||||
constructs.
|
constructs.
|
||||||
"""
|
"""
|
||||||
with translation.override('fr'):
|
with translation.override('fr'):
|
||||||
self.assertEqual(Template("{% load i18n %}{% trans 'Yes' %}").render(Context({})), 'Oui')
|
self.assertEqual(
|
||||||
|
self.get_template("{% load i18n %}{% trans 'Yes' %}").render(Context({})),
|
||||||
|
'Oui'
|
||||||
|
)
|
||||||
|
|
||||||
def test_multiple_locale_trans(self):
|
def test_multiple_locale_trans(self):
|
||||||
with translation.override('de'):
|
with translation.override('de'):
|
||||||
t = Template("{% load i18n %}{% trans 'No' %}")
|
t = self.get_template("{% load i18n %}{% trans 'No' %}")
|
||||||
with translation.override(self._old_language), translation.override('nl'):
|
with translation.override(self._old_language), translation.override('nl'):
|
||||||
self.assertEqual(t.render(Context({})), 'Nee')
|
self.assertEqual(t.render(Context({})), 'Nee')
|
||||||
|
|
||||||
def test_multiple_locale_deactivate_trans(self):
|
def test_multiple_locale_deactivate_trans(self):
|
||||||
with translation.override('de', deactivate=True):
|
with translation.override('de', deactivate=True):
|
||||||
t = Template("{% load i18n %}{% trans 'No' %}")
|
t = self.get_template("{% load i18n %}{% trans 'No' %}")
|
||||||
with translation.override('nl'):
|
with translation.override('nl'):
|
||||||
self.assertEqual(t.render(Context({})), 'Nee')
|
self.assertEqual(t.render(Context({})), 'Nee')
|
||||||
|
|
||||||
def test_multiple_locale_direct_switch_trans(self):
|
def test_multiple_locale_direct_switch_trans(self):
|
||||||
with translation.override('de'):
|
with translation.override('de'):
|
||||||
t = Template("{% load i18n %}{% trans 'No' %}")
|
t = self.get_template("{% load i18n %}{% trans 'No' %}")
|
||||||
with translation.override('nl'):
|
with translation.override('nl'):
|
||||||
self.assertEqual(t.render(Context({})), 'Nee')
|
self.assertEqual(t.render(Context({})), 'Nee')
|
||||||
|
|
||||||
|
|
||||||
|
class MultipleLocaleActivationTranslateTagTests(MultipleLocaleActivationTransTagTests):
|
||||||
|
tag_name = 'translate'
|
||||||
|
|
||||||
|
|
||||||
class LocalizeNodeTests(SimpleTestCase):
|
class LocalizeNodeTests(SimpleTestCase):
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
node = LocalizeNode(nodelist=[], use_l10n=True)
|
node = LocalizeNode(nodelist=[], use_l10n=True)
|
Loading…
Reference in New Issue