Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
Jannis Leidel authored July 04, 2011
53  django/templatetags/i18n.py
... ...
@@ -1,15 +1,16 @@
  1
+from __future__ import with_statement
1 2
 import re
2 3
 
3  
-from django.template import Node, Variable, VariableNode
4  
-from django.template import TemplateSyntaxError, TokenParser, Library
5  
-from django.template import TOKEN_TEXT, TOKEN_VAR
  4
+from django.template import (Node, Variable, TemplateSyntaxError,
  5
+    TokenParser, Library, TOKEN_TEXT, TOKEN_VAR)
6 6
 from django.template.base import _render_value_in_context
7  
-from django.utils import translation
8  
-from django.utils.encoding import force_unicode
9 7
 from django.template.defaulttags import token_kwargs
  8
+from django.utils import translation
  9
+
10 10
 
11 11
 register = Library()
12 12
 
  13
+
13 14
 class GetAvailableLanguagesNode(Node):
14 15
     def __init__(self, variable):
15 16
         self.variable = variable
@@ -19,6 +20,7 @@ def render(self, context):
19 20
         context[self.variable] = [(k, translation.ugettext(v)) for k, v in settings.LANGUAGES]
20 21
         return ''
21 22
 
  23
+
22 24
 class GetLanguageInfoNode(Node):
23 25
     def __init__(self, lang_code, variable):
24 26
         self.lang_code = Variable(lang_code)
@@ -29,6 +31,7 @@ def render(self, context):
29 31
         context[self.variable] = translation.get_language_info(lang_code)
30 32
         return ''
31 33
 
  34
+
32 35
 class GetLanguageInfoListNode(Node):
33 36
     def __init__(self, languages, variable):
34 37
         self.languages = Variable(languages)
@@ -47,6 +50,7 @@ def render(self, context):
47 50
         context[self.variable] = [self.get_language_info(lang) for lang in langs]
48 51
         return ''
49 52
 
  53
+
50 54
 class GetCurrentLanguageNode(Node):
51 55
     def __init__(self, variable):
52 56
         self.variable = variable
@@ -55,6 +59,7 @@ def render(self, context):
55 59
         context[self.variable] = translation.get_language()
56 60
         return ''
57 61
 
  62
+
58 63
 class GetCurrentLanguageBidiNode(Node):
59 64
     def __init__(self, variable):
60 65
         self.variable = variable
@@ -63,6 +68,7 @@ def render(self, context):
63 68
         context[self.variable] = translation.get_language_bidi()
64 69
         return ''
65 70
 
  71
+
66 72
 class TranslateNode(Node):
67 73
     def __init__(self, filter_expression, noop):
68 74
         self.noop = noop
@@ -75,6 +81,7 @@ def render(self, context):
75 81
         output = self.filter_expression.resolve(context)
76 82
         return _render_value_in_context(output, context)
77 83
 
  84
+
78 85
 class BlockTranslateNode(Node):
79 86
     def __init__(self, extra_context, singular, plural=None, countervar=None,
80 87
             counter=None):
@@ -117,6 +124,18 @@ def render(self, context):
117 124
         context.pop()
118 125
         return result % data
119 126
 
  127
+
  128
+class LanguageNode(Node):
  129
+    def __init__(self, nodelist, language):
  130
+        self.nodelist = nodelist
  131
+        self.language = language
  132
+
  133
+    def render(self, context):
  134
+        with translation.override(self.language.resolve(context)):
  135
+            output = self.nodelist.render(context)
  136
+        return output
  137
+
  138
+
120 139
 @register.tag("get_available_languages")
121 140
 def do_get_available_languages(parser, token):
122 141
     """
@@ -271,9 +290,9 @@ def top(self):
271 290
             # where single quote use is supported.
272 291
             if value[0] == "'":
273 292
                 pos = None
274  
-                m = re.match("^'([^']+)'(\|.*$)",value)
  293
+                m = re.match("^'([^']+)'(\|.*$)", value)
275 294
                 if m:
276  
-                    value = '"%s"%s' % (m.group(1).replace('"','\\"'),m.group(2))
  295
+                    value = '"%s"%s' % (m.group(1).replace('"','\\"'), m.group(2))
277 296
                 elif value[-1] == "'":
278 297
                     value = '"%s"' % value[1:-1].replace('"','\\"')
279 298
 
@@ -366,3 +385,23 @@ def do_block_translate(parser, token):
366 385
 
367 386
     return BlockTranslateNode(extra_context, singular, plural, countervar,
368 387
             counter)
  388
+
  389
+@register.tag
  390
+def language(parser, token):
  391
+    """
  392
+    This will enable the given language just for this block.
  393
+
  394
+    Usage::
  395
+
  396
+        {% language "de" %}
  397
+            This is {{ bar }} and {{ boo }}.
  398
+        {% endlanguage %}
  399
+
  400
+    """
  401
+    bits = token.split_contents()
  402
+    if len(bits) < 2:
  403
+        raise TemplateSyntaxError("'%s' takes one argument (language)" % bits[0])
  404
+    language = parser.compile_filter(bits[1])
  405
+    nodelist = parser.parse(('endlanguage',))
  406
+    parser.delete_first_token()
  407
+    return LanguageNode(nodelist, language)
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
28 28
 mappings. And, because it's pure Python code, it can be constructed
29 29
 dynamically.
30 30
 
  31
+.. versionadded:: 1.4
  32
+
  33
+    Django also allows to translate URLs according to the active language.
  34
+    This process is described in the
  35
+    :ref:`internationalization docs <url-internationalization>`.
  36
+
31 37
 .. _how-django-processes-a-request:
32 38
 
33 39
 How Django processes a request
26  docs/topics/i18n/internationalization.txt
@@ -887,6 +887,32 @@ return the URL in the active language. Example::
887 887
     that a carelessly translated URL causes a collision with a non-translated
888 888
     URL pattern.
889 889
 
  890
+.. _reversing_in_templates:
  891
+
  892
+.. templatetag:: language
  893
+
  894
+Reversing in templates
  895
+----------------------
  896
+
  897
+If localized URLs get reversed in templates they always use the current
  898
+language. To link to a URL in another language use the ``language``
  899
+template tag. It enables the given language in the enclosed template section:
  900
+
  901
+.. code-block:: html+django
  902
+
  903
+    {% load i18n %}
  904
+
  905
+    {% get_available_languages as languages %}
  906
+
  907
+    {% trans "View this category in:" %}
  908
+    {% for lang_code, lang_name in languages %}
  909
+        {% language lang_code %}
  910
+        <a href="{% url category slug=category.slug %}">{{ lang_name }}</a>
  911
+        {% endlanguage %}
  912
+    {% endfor %}
  913
+
  914
+The :ttag:`language` tag expects the language code as the only argument.
  915
+
890 916
 .. _set_language-redirect-view:
891 917
 
892 918
 The ``set_language`` redirect view
42  tests/regressiontests/i18n/patterns/tests.py
@@ -6,6 +6,7 @@
6 6
 from django.core.urlresolvers import reverse, clear_url_caches
7 7
 from django.test import TestCase
8 8
 from django.test.utils import override_settings
  9
+from django.template import Template, Context
9 10
 from django.utils import translation
10 11
 
11 12
 
@@ -241,3 +242,44 @@ def test_pt_br_url(self):
241 242
         self.assertEqual(response.status_code, 200)
242 243
         self.assertEqual(response['content-language'], 'pt-br')
243 244
         self.assertEqual(response.context['LANGUAGE_CODE'], 'pt-br')
  245
+
  246
+
  247
+class URLTagTests(URLTestCaseBase):
  248
+    """
  249
+    Test if the language tag works.
  250
+    """
  251
+    def test_strings_only(self):
  252
+        t = Template("""{% load i18n %}
  253
+            {% language 'nl' %}{% url no-prefix-translated %}{% endlanguage %}
  254
+            {% language 'pt-br' %}{% url no-prefix-translated %}{% endlanguage %}""")
  255
+        self.assertEqual(t.render(Context({})).strip().split(),
  256
+                         [u'/vertaald/', u'/traduzidos/'])
  257
+
  258
+    def test_context(self):
  259
+        ctx = Context({'lang1':'nl', 'lang2':'pt-br'})
  260
+        tpl = Template("""{% load i18n %}
  261
+            {% language lang1 %}{% url no-prefix-translated %}{% endlanguage %}
  262
+            {% language lang2 %}{% url no-prefix-translated %}{% endlanguage %}""")
  263
+        self.assertEqual(tpl.render(ctx).strip().split(),
  264
+                         [u'/vertaald/', u'/traduzidos/'])
  265
+
  266
+    def test_args(self):
  267
+        tpl = Template("""{% load i18n %}
  268
+            {% language 'nl' %}{% url no-prefix-translated-slug 'apo' %}{% endlanguage %}
  269
+            {% language 'pt-br' %}{% url no-prefix-translated-slug 'apo' %}{% endlanguage %}""")
  270
+        self.assertEqual(tpl.render(Context({})).strip().split(),
  271
+                         [u'/vertaald/apo/', u'/traduzidos/apo/'])
  272
+
  273
+    def test_kwargs(self):
  274
+        tpl = Template("""{% load i18n %}
  275
+            {% language 'nl'  %}{% url no-prefix-translated-slug slug='apo' %}{% endlanguage %}
  276
+            {% language 'pt-br' %}{% url no-prefix-translated-slug slug='apo' %}{% endlanguage %}""")
  277
+        self.assertEqual(tpl.render(Context({})).strip().split(),
  278
+                         [u'/vertaald/apo/', u'/traduzidos/apo/'])
  279
+
  280
+    def test_future_kwargs(self):
  281
+        tpl = Template("""{% load i18n %}{% load url from future %}
  282
+            {% language 'nl'  %}{% url 'no-prefix-translated-slug' slug='apo' %}{% endlanguage %}
  283
+            {% language 'pt-br' %}{% url 'no-prefix-translated-slug' slug='apo' %}{% endlanguage %}""")
  284
+        self.assertEqual(tpl.render(Context({})).strip().split(),
  285
+                         [u'/vertaald/apo/', u'/traduzidos/apo/'])

0 notes on commit 286a1ca

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