Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #16332 -- Added language template tag that switches the activat…

…e language for the enclosed template section, e.g. to allow translation of URLs as added in r16405. Many thanks to Florian Apolloner and Orne Brocaar.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16501 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 286a1cad8839da3219dc3901540fb9422686e5ab 1 parent a34e670
@jezdez jezdez authored
View
53 django/templatetags/i18n.py
@@ -1,15 +1,16 @@
+from __future__ import with_statement
import re
-from django.template import Node, Variable, VariableNode
-from django.template import TemplateSyntaxError, TokenParser, Library
-from django.template import TOKEN_TEXT, TOKEN_VAR
+from django.template import (Node, Variable, TemplateSyntaxError,
+ TokenParser, Library, TOKEN_TEXT, TOKEN_VAR)
from django.template.base import _render_value_in_context
-from django.utils import translation
-from django.utils.encoding import force_unicode
from django.template.defaulttags import token_kwargs
+from django.utils import translation
+
register = Library()
+
class GetAvailableLanguagesNode(Node):
def __init__(self, variable):
self.variable = variable
@@ -19,6 +20,7 @@ def render(self, context):
context[self.variable] = [(k, translation.ugettext(v)) for k, v in settings.LANGUAGES]
return ''
+
class GetLanguageInfoNode(Node):
def __init__(self, lang_code, variable):
self.lang_code = Variable(lang_code)
@@ -29,6 +31,7 @@ def render(self, context):
context[self.variable] = translation.get_language_info(lang_code)
return ''
+
class GetLanguageInfoListNode(Node):
def __init__(self, languages, variable):
self.languages = Variable(languages)
@@ -47,6 +50,7 @@ def render(self, context):
context[self.variable] = [self.get_language_info(lang) for lang in langs]
return ''
+
class GetCurrentLanguageNode(Node):
def __init__(self, variable):
self.variable = variable
@@ -55,6 +59,7 @@ def render(self, context):
context[self.variable] = translation.get_language()
return ''
+
class GetCurrentLanguageBidiNode(Node):
def __init__(self, variable):
self.variable = variable
@@ -63,6 +68,7 @@ def render(self, context):
context[self.variable] = translation.get_language_bidi()
return ''
+
class TranslateNode(Node):
def __init__(self, filter_expression, noop):
self.noop = noop
@@ -75,6 +81,7 @@ def render(self, context):
output = self.filter_expression.resolve(context)
return _render_value_in_context(output, context)
+
class BlockTranslateNode(Node):
def __init__(self, extra_context, singular, plural=None, countervar=None,
counter=None):
@@ -117,6 +124,18 @@ def render(self, context):
context.pop()
return result % data
+
+class LanguageNode(Node):
+ def __init__(self, nodelist, language):
+ self.nodelist = nodelist
+ self.language = language
+
+ def render(self, context):
+ with translation.override(self.language.resolve(context)):
+ output = self.nodelist.render(context)
+ return output
+
+
@register.tag("get_available_languages")
def do_get_available_languages(parser, token):
"""
@@ -271,9 +290,9 @@ def top(self):
# where single quote use is supported.
if value[0] == "'":
pos = None
- m = re.match("^'([^']+)'(\|.*$)",value)
+ m = re.match("^'([^']+)'(\|.*$)", value)
if m:
- value = '"%s"%s' % (m.group(1).replace('"','\\"'),m.group(2))
+ value = '"%s"%s' % (m.group(1).replace('"','\\"'), m.group(2))
elif value[-1] == "'":
value = '"%s"' % value[1:-1].replace('"','\\"')
@@ -366,3 +385,23 @@ def do_block_translate(parser, token):
return BlockTranslateNode(extra_context, singular, plural, countervar,
counter)
+
+@register.tag
+def language(parser, token):
+ """
+ This will enable the given language just for this block.
+
+ Usage::
+
+ {% language "de" %}
+ This is {{ bar }} and {{ boo }}.
+ {% endlanguage %}
+
+ """
+ bits = token.split_contents()
+ if len(bits) < 2:
+ raise TemplateSyntaxError("'%s' takes one argument (language)" % bits[0])
+ language = parser.compile_filter(bits[1])
+ nodelist = parser.parse(('endlanguage',))
+ parser.delete_first_token()
+ return LanguageNode(nodelist, language)
View
6 docs/topics/http/urls.txt
@@ -28,6 +28,12 @@ This mapping can be as short or as long as needed. It can reference other
mappings. And, because it's pure Python code, it can be constructed
dynamically.
+.. versionadded:: 1.4
+
+ Django also allows to translate URLs according to the active language.
+ This process is described in the
+ :ref:`internationalization docs <url-internationalization>`.
+
.. _how-django-processes-a-request:
How Django processes a request
View
26 docs/topics/i18n/internationalization.txt
@@ -887,6 +887,32 @@ return the URL in the active language. Example::
that a carelessly translated URL causes a collision with a non-translated
URL pattern.
+.. _reversing_in_templates:
+
+.. templatetag:: language
+
+Reversing in templates
+----------------------
+
+If localized URLs get reversed in templates they always use the current
+language. To link to a URL in another language use the ``language``
+template tag. It enables the given language in the enclosed template section:
+
+.. code-block:: html+django
+
+ {% load i18n %}
+
+ {% get_available_languages as languages %}
+
+ {% trans "View this category in:" %}
+ {% for lang_code, lang_name in languages %}
+ {% language lang_code %}
+ <a href="{% url category slug=category.slug %}">{{ lang_name }}</a>
+ {% endlanguage %}
+ {% endfor %}
+
+The :ttag:`language` tag expects the language code as the only argument.
+
.. _set_language-redirect-view:
The ``set_language`` redirect view
View
42 tests/regressiontests/i18n/patterns/tests.py
@@ -6,6 +6,7 @@
from django.core.urlresolvers import reverse, clear_url_caches
from django.test import TestCase
from django.test.utils import override_settings
+from django.template import Template, Context
from django.utils import translation
@@ -241,3 +242,44 @@ def test_pt_br_url(self):
self.assertEqual(response.status_code, 200)
self.assertEqual(response['content-language'], 'pt-br')
self.assertEqual(response.context['LANGUAGE_CODE'], 'pt-br')
+
+
+class URLTagTests(URLTestCaseBase):
+ """
+ Test if the language tag works.
+ """
+ def test_strings_only(self):
+ t = Template("""{% load i18n %}
+ {% language 'nl' %}{% url no-prefix-translated %}{% endlanguage %}
+ {% language 'pt-br' %}{% url no-prefix-translated %}{% endlanguage %}""")
+ self.assertEqual(t.render(Context({})).strip().split(),
+ [u'/vertaald/', u'/traduzidos/'])
+
+ def test_context(self):
+ ctx = Context({'lang1':'nl', 'lang2':'pt-br'})
+ tpl = Template("""{% load i18n %}
+ {% language lang1 %}{% url no-prefix-translated %}{% endlanguage %}
+ {% language lang2 %}{% url no-prefix-translated %}{% endlanguage %}""")
+ self.assertEqual(tpl.render(ctx).strip().split(),
+ [u'/vertaald/', u'/traduzidos/'])
+
+ def test_args(self):
+ tpl = Template("""{% load i18n %}
+ {% language 'nl' %}{% url no-prefix-translated-slug 'apo' %}{% endlanguage %}
+ {% language 'pt-br' %}{% url no-prefix-translated-slug 'apo' %}{% endlanguage %}""")
+ self.assertEqual(tpl.render(Context({})).strip().split(),
+ [u'/vertaald/apo/', u'/traduzidos/apo/'])
+
+ def test_kwargs(self):
+ tpl = Template("""{% load i18n %}
+ {% language 'nl' %}{% url no-prefix-translated-slug slug='apo' %}{% endlanguage %}
+ {% language 'pt-br' %}{% url no-prefix-translated-slug slug='apo' %}{% endlanguage %}""")
+ self.assertEqual(tpl.render(Context({})).strip().split(),
+ [u'/vertaald/apo/', u'/traduzidos/apo/'])
+
+ def test_future_kwargs(self):
+ tpl = Template("""{% load i18n %}{% load url from future %}
+ {% language 'nl' %}{% url 'no-prefix-translated-slug' slug='apo' %}{% endlanguage %}
+ {% language 'pt-br' %}{% url 'no-prefix-translated-slug' slug='apo' %}{% endlanguage %}""")
+ self.assertEqual(tpl.render(Context({})).strip().split(),
+ [u'/vertaald/apo/', u'/traduzidos/apo/'])
Please sign in to comment.
Something went wrong with that request. Please try again.