Ticket #14806: 14806.template-tags-pgettext.3.diff
File 14806.template-tags-pgettext.3.diff, 28.7 KB (added by , 13 years ago) |
---|
-
django/template/base.py
diff --git a/django/template/base.py b/django/template/base.py index 8001e93..3a2b740 100644
a b from django.utils.itercompat import is_iterable 10 10 from django.utils.text import (smart_split, unescape_string_literal, 11 11 get_text_list) 12 12 from django.utils.encoding import smart_unicode, force_unicode, smart_str 13 from django.utils.translation import ugettext_lazy 13 from django.utils.translation import ugettext_lazy, pgettext_lazy 14 14 from django.utils.safestring import (SafeData, EscapeData, mark_safe, 15 15 mark_for_escaping) 16 16 from django.utils.formats import localize … … class Variable(object): 673 673 self.literal = None 674 674 self.lookups = None 675 675 self.translate = False 676 self.message_context = None 676 677 677 678 try: 678 679 # First try to treat this variable as a number. … … class Variable(object): 720 721 # We're dealing with a literal, so it's already been "resolved" 721 722 value = self.literal 722 723 if self.translate: 723 return ugettext_lazy(value) 724 if self.message_context: 725 return pgettext_lazy(self.message_context, value) 726 else: 727 return ugettext_lazy(value) 724 728 return value 725 729 726 730 def __repr__(self): -
django/templatetags/i18n.py
diff --git a/django/templatetags/i18n.py b/django/templatetags/i18n.py index 669cdc9..dc3d93e 100644
a b class GetCurrentLanguageBidiNode(Node): 70 70 71 71 72 72 class TranslateNode(Node): 73 def __init__(self, filter_expression, noop, asvar=None): 73 def __init__(self, filter_expression, noop, asvar=None, 74 message_context=None): 74 75 self.noop = noop 75 76 self.asvar = asvar 77 self.message_context = message_context 76 78 self.filter_expression = filter_expression 77 79 if isinstance(self.filter_expression.var, basestring): 78 self.filter_expression.var = Variable(u"'%s'" % self.filter_expression.var) 80 self.filter_expression.var = Variable(u"'%s'" % 81 self.filter_expression.var) 79 82 80 83 def render(self, context): 81 84 self.filter_expression.var.translate = not self.noop 85 if self.message_context: 86 self.filter_expression.var.message_context = ( 87 self.message_context.resolve(context)) 82 88 output = self.filter_expression.resolve(context) 83 89 value = _render_value_in_context(output, context) 84 90 if self.asvar: … … class TranslateNode(Node): 90 96 91 97 class BlockTranslateNode(Node): 92 98 def __init__(self, extra_context, singular, plural=None, countervar=None, 93 counter=None ):99 counter=None, message_context=None): 94 100 self.extra_context = extra_context 95 101 self.singular = singular 96 102 self.plural = plural 97 103 self.countervar = countervar 98 104 self.counter = counter 105 self.message_context = message_context 99 106 100 107 def render_token_list(self, tokens): 101 108 result = [] … … class BlockTranslateNode(Node): 109 116 return ''.join(result), vars 110 117 111 118 def render(self, context): 119 if self.message_context: 120 message_context = self.message_context.resolve(context) 121 else: 122 message_context = None 112 123 tmp_context = {} 113 124 for var, val in self.extra_context.items(): 114 125 tmp_context[var] = val.resolve(context) … … class BlockTranslateNode(Node): 123 134 context[self.countervar] = count 124 135 plural, plural_vars = self.render_token_list(self.plural) 125 136 plural = re.sub(u'%(?!\()', u'%%', plural) 126 result = translation.ungettext(singular, plural, count) 137 if message_context: 138 result = translation.npgettext(message_context, singular, 139 plural, count) 140 else: 141 result = translation.ungettext(singular, plural, count) 127 142 vars.extend(plural_vars) 128 143 else: 129 result = translation.ugettext(singular) 144 if message_context: 145 result = translation.pgettext(message_context, singular) 146 else: 147 result = translation.ugettext(singular) 130 148 data = dict([(v, _render_value_in_context(context.get(v, ''), context)) for v in vars]) 131 149 context.pop() 132 150 try: … … def do_translate(parser, token): 290 308 This will just try to translate the contents of 291 309 the variable ``variable``. Make sure that the string 292 310 in there is something that is in the .po file. 311 312 It is possible to store the translated string into a variable:: 313 314 {% trans "this is a test" as var %} 315 {{ var }} 316 317 Contextual translations are also supported:: 318 319 {% trans "this is a test" context "greeting" %} 320 321 This is equivalent to calling pgettext instead of (u)gettext. 293 322 """ 294 323 class TranslateParser(TokenParser): 295 324 def top(self): … … def do_translate(parser, token): 301 330 # backwards compatibility with existing uses of ``trans`` 302 331 # where single quote use is supported. 303 332 if value[0] == "'": 304 pos = None305 333 m = re.match("^'([^']+)'(\|.*$)", value) 306 334 if m: 307 335 value = '"%s"%s' % (m.group(1).replace('"','\\"'), m.group(2)) … … def do_translate(parser, token): 310 338 311 339 noop = False 312 340 asvar = None 341 message_context = None 313 342 314 343 while self.more(): 315 344 tag = self.tag() 316 345 if tag == 'noop': 317 346 noop = True 347 elif tag == 'context': 348 message_context = parser.compile_filter(self.value()) 318 349 elif tag == 'as': 319 350 asvar = self.tag() 320 351 else: 321 352 raise TemplateSyntaxError( 322 "only options for 'trans' are 'noop' and 'as VAR.") 323 return (value, noop, asvar) 324 value, noop, asvar = TranslateParser(token.contents).top() 325 return TranslateNode(parser.compile_filter(value), noop, asvar) 353 "Only options for 'trans' are 'noop', " \ 354 "'context \"xxx\"', and 'as VAR'.") 355 return value, noop, asvar, message_context 356 value, noop, asvar, message_context = TranslateParser(token.contents).top() 357 return TranslateNode(parser.compile_filter(value), noop, asvar, 358 message_context) 326 359 327 360 @register.tag("blocktrans") 328 361 def do_block_translate(parser, token): … … def do_block_translate(parser, token): 349 382 350 383 {% blocktrans with foo|filter as bar and baz|filter as boo %} 351 384 {% blocktrans count var|length as count %} 385 386 Contextual translations are supported:: 387 388 {% blocktrans with bar=foo|filter context "greeting" %} 389 This is {{ bar }}. 390 {% endblocktrans %} 391 392 This is equivalent to calling pgettext/npgettext instead of 393 (u)gettext/(u)ngettext. 352 394 """ 353 395 bits = token.split_contents() 354 396 … … def do_block_translate(parser, token): 369 411 if len(value) != 1: 370 412 raise TemplateSyntaxError('"count" in %r tag expected exactly ' 371 413 'one keyword argument.' % bits[0]) 414 elif option == "context": 415 try: 416 value = remaining_bits.pop(0) 417 value = parser.compile_filter(value) 418 except Exception: 419 raise TemplateSyntaxError('"context" in %r tag expected ' 420 'exactly one argument.' % bits[0]) 372 421 else: 373 422 raise TemplateSyntaxError('Unknown argument for %r tag: %r.' % 374 423 (bits[0], option)) … … def do_block_translate(parser, token): 378 427 countervar, counter = options['count'].items()[0] 379 428 else: 380 429 countervar, counter = None, None 381 extra_context = options.get('with', {}) 430 if 'context' in options: 431 message_context = options['context'] 432 else: 433 message_context = None 434 extra_context = options.get('with', {}) 382 435 383 436 singular = [] 384 437 plural = [] … … def do_block_translate(parser, token): 401 454 raise TemplateSyntaxError("'blocktrans' doesn't allow other block tags (seen %r) inside it" % token.contents) 402 455 403 456 return BlockTranslateNode(extra_context, singular, plural, countervar, 404 counter )457 counter, message_context) 405 458 406 459 @register.tag 407 460 def language(parser, token): -
django/utils/translation/trans_real.py
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index 71765e7..f43cfd9 100644
a b def blankout(src, char): 433 433 """ 434 434 return dot_re.sub(char, src) 435 435 436 inline_re = re.compile(r"""^\s*trans\s+((?:".*?")|(?:'.*?'))\s*""") 437 block_re = re.compile(r"""^\s*blocktrans(?:\s+|$)""") 436 context_re = re.compile(r"""^\s+.*context\s+((?:"[^"]*?")|(?:'[^']*?'))\s*""") 437 inline_re = re.compile(r"""^\s*trans\s+((?:"[^"]*?")|(?:'[^']*?'))(\s+.*context\s+(?:"[^"]*?")|(?:'[^']*?'))?\s*""") 438 block_re = re.compile(r"""^\s*blocktrans(\s+.*context\s+(?:"[^"]*?")|(?:'[^']*?'))?(?:\s+|$)""") 438 439 endblock_re = re.compile(r"""^\s*endblocktrans$""") 439 440 plural_re = re.compile(r"""^\s*plural$""") 440 441 constant_re = re.compile(r"""_\(((?:".*?")|(?:'.*?'))\)""") 441 442 443 442 444 def templatize(src, origin=None): 443 445 """ 444 446 Turns a Django template into something that is understood by xgettext. It … … def templatize(src, origin=None): 448 450 from django.template import (Lexer, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK, 449 451 TOKEN_COMMENT, TRANSLATOR_COMMENT_MARK) 450 452 out = StringIO() 453 message_context = None 451 454 intrans = False 452 455 inplural = False 453 456 singular = [] … … def templatize(src, origin=None): 477 480 pluralmatch = plural_re.match(t.contents) 478 481 if endbmatch: 479 482 if inplural: 480 out.write(' ngettext(%r,%r,count) ' % (''.join(singular), ''.join(plural))) 483 if message_context: 484 out.write(' npgettext(%r, %r, %r,count) ' % (message_context, ''.join(singular), ''.join(plural))) 485 else: 486 out.write(' ngettext(%r, %r, count) ' % (''.join(singular), ''.join(plural))) 481 487 for part in singular: 482 488 out.write(blankout(part, 'S')) 483 489 for part in plural: 484 490 out.write(blankout(part, 'P')) 485 491 else: 486 out.write(' gettext(%r) ' % ''.join(singular)) 492 if message_context: 493 out.write(' pgettext(%r, %r) ' % (message_context, ''.join(singular))) 494 else: 495 out.write(' gettext(%r) ' % ''.join(singular)) 487 496 for part in singular: 488 497 out.write(blankout(part, 'S')) 498 message_context = None 489 499 intrans = False 490 500 inplural = False 491 501 singular = [] … … def templatize(src, origin=None): 515 525 cmatches = constant_re.findall(t.contents) 516 526 if imatch: 517 527 g = imatch.group(1) 518 if g[0] == '"': g = g.strip('"') 519 elif g[0] == "'": g = g.strip("'") 520 out.write(' gettext(%r) ' % g) 528 if g[0] == '"': 529 g = g.strip('"') 530 elif g[0] == "'": 531 g = g.strip("'") 532 if imatch.group(2): 533 # A context is provided 534 context_match = context_re.match(imatch.group(2)) 535 message_context = context_match.group(1) 536 if message_context[0] == '"': 537 message_context = message_context.strip('"') 538 elif message_context[0] == "'": 539 message_context = message_context.strip("'") 540 out.write(' pgettext(%r, %r) ' % (message_context, g)) 541 message_context = None 542 else: 543 out.write(' gettext(%r) ' % g) 521 544 elif bmatch: 522 545 for fmatch in constant_re.findall(t.contents): 523 546 out.write(' _(%s) ' % fmatch) 547 if bmatch.group(1): 548 # A context is provided 549 context_match = context_re.match(bmatch.group(1)) 550 message_context = context_match.group(1) 551 if message_context[0] == '"': 552 message_context = message_context.strip('"') 553 elif message_context[0] == "'": 554 message_context = message_context.strip("'") 524 555 intrans = True 525 556 inplural = False 526 557 singular = [] -
docs/releases/1.4.txt
diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt index 3e364fb..00acc65 100644
a b Additionally, it's now possible to define translatable URL patterns using 191 191 :ref:`url-internationalization` for more information about the language prefix 192 192 and how to internationalize URL patterns. 193 193 194 Contextual translation support for ``{% trans %}`` and ``{% blocktrans %}`` 195 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 196 197 Django 1.3 introduced :ref:`contextual translation<contextual-markers>` support 198 in Python files via the ``pgettext`` function. This is now also supported by 199 the :ttag:`trans` and :ttag:`blocktrans` template tags using the new 200 ``context`` keyword. 201 194 202 Customizable ``SingleObjectMixin`` URLConf kwargs 195 203 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 196 204 -
docs/topics/i18n/internationalization.txt
diff --git a/docs/topics/i18n/internationalization.txt b/docs/topics/i18n/internationalization.txt index b06c9bd..7dc3db0 100644
a b will appear in the .po file as: 266 266 msgid "May" 267 267 msgstr "" 268 268 269 .. versionadded:: 1.4 270 271 Contextual markers are also supported by the :ttag:`trans` and 272 :ttag:`blocktrans` template tags. 273 269 274 .. _lazy-translations: 270 275 271 276 Lazy translation … … It's not possible to mix a template variable inside a string within ``{% trans 453 458 %}``. If your translations require strings with variables (placeholders), use 454 459 ``{% blocktrans %}`` instead. 455 460 456 .. version changed:: 1.4461 .. versionadded:: 1.4 457 462 458 463 If you'd like to retrieve a translated string without displaying it, you can 459 464 use the following syntax:: … … or should be used as arguments for other template tags or filters:: 479 484 {% endfor %} 480 485 </p> 481 486 487 .. versionadded:: 1.4 488 489 ``{% trans %}`` also supports :ref:`contextual markers<contextual-markers>` 490 using the ``context`` keyword: 491 492 .. code-block:: html+django 493 494 {% trans "May" context "month name" %} 495 482 496 .. templatetag:: blocktrans 483 497 484 498 ``blocktrans`` template tag … … be retrieved (and stored) beforehand:: 560 574 This is a URL: {{ the_url }} 561 575 {% endblocktrans %} 562 576 577 .. versionadded:: 1.4 578 579 ``{% blocktrans %}`` also supports :ref:`contextual 580 markers<contextual-markers>` using the ``context`` keyword: 581 582 .. code-block:: html+django 583 584 {% blocktrans with name=user.username context="greeting" %}Hi {{ name }}{% endblocktrans %} 585 563 586 .. _template-translation-vars: 564 587 565 588 Other tags -
tests/regressiontests/i18n/commands/extraction.py
diff --git a/tests/regressiontests/i18n/commands/extraction.py b/tests/regressiontests/i18n/commands/extraction.py index 7d7cdf7..c495772 100644
a b class BasicExtractorTests(ExtractorTests): 94 94 os.remove('./templates/template_with_error.html') 95 95 os.remove('./templates/template_with_error.html.py') # Waiting for #8536 to be fixed 96 96 97 def test_template_message_context_extractor(self): 98 """ 99 Ensure that message contexts are correctly extracted for the 100 {% trans %} and {% blocktrans %} template tags. 101 Refs #14806. 102 """ 103 os.chdir(self.test_dir) 104 management.call_command('makemessages', locale=LOCALE, verbosity=0) 105 self.assertTrue(os.path.exists(self.PO_FILE)) 106 po_contents = open(self.PO_FILE, 'r').read() 107 # {% trans %} 108 self.assertTrue('msgctxt "Special trans context #1"' in po_contents) 109 self.assertTrue("Translatable literal #7a" in po_contents) 110 self.assertTrue('msgctxt "Special trans context #2"' in po_contents) 111 self.assertTrue("Translatable literal #7b" in po_contents) 112 self.assertTrue('msgctxt "Special trans context #3"' in po_contents) 113 self.assertTrue("Translatable literal #7c" in po_contents) 114 115 # {% blocktrans %} 116 self.assertTrue('msgctxt "Special blocktrans context #1"' in po_contents) 117 self.assertTrue("Translatable literal #8a" in po_contents) 118 self.assertTrue('msgctxt "Special blocktrans context #2"' in po_contents) 119 self.assertTrue("Translatable literal #8b-singular" in po_contents) 120 self.assertTrue("Translatable literal #8b-plural" in po_contents) 121 self.assertTrue('msgctxt "Special blocktrans context #3"' in po_contents) 122 self.assertTrue("Translatable literal #8c-singular" in po_contents) 123 self.assertTrue("Translatable literal #8c-plural" in po_contents) 124 self.assertTrue('msgctxt "Special blocktrans context #4"' in po_contents) 125 self.assertTrue("Translatable literal #8d" in po_contents) 97 126 98 127 class JavascriptExtractorTests(ExtractorTests): 99 128 -
tests/regressiontests/i18n/commands/templates/test.html
diff --git a/tests/regressiontests/i18n/commands/templates/test.html b/tests/regressiontests/i18n/commands/templates/test.html index b5d705c..24fc708 100644
a b continued here.{% endcomment %} 57 57 {% comment %} Translators: Two-line translator comment #5 -- with non ASCII characters: áéíóúö 58 58 continued here.{% endcomment %} 59 59 {% trans "Translatable literal #6b" %} 60 61 {% trans "Translatable literal #7a" context "Special trans context #1" %} 62 {% trans "Translatable literal #7b" as var context "Special trans context #2" %} 63 {% trans "Translatable literal #7c" context "Special trans context #3" as var %} 64 65 {% blocktrans context "Special blocktrans context #1" %}Translatable literal #8a{% endblocktrans %} 66 {% blocktrans count 2 context "Special blocktrans context #2" %}Translatable literal #8b-singular{% plural %}Translatable literal #8b-plural{% endblocktrans %} 67 {% blocktrans context "Special blocktrans context #3" count 2 %}Translatable literal #8c-singular{% plural %}Translatable literal #8c-plural{% endblocktrans %} 68 {% blocktrans with a=1 context "Special blocktrans context #4" %}Translatable literal #8d {{ a }}{% endblocktrans %} 69 No newline at end of file -
tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po
diff --git a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo index a1a93c8..f825e39 100644 Binary files a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo and b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo differ diff --git a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po index 7226ad1..a471d38 100644
a b msgid "%(percent)s%% represents %(num)s object" 52 52 msgid_plural "%(percent)s%% represents %(num)s objects" 53 53 msgstr[0] "%(percent)s%% stellt %(num)s Objekt dar" 54 54 msgstr[1] "%(percent)s%% stellt %(num)s Objekte dar" 55 56 #: models.py:17 57 msgctxt "super search" 58 msgid "%(number)s super result" 59 msgid_plural "%(number)s super results" 60 msgstr[0] "%(number)s Super-Ergebnis" 61 msgstr[1] "%(number)s Super-Ergebnisse" 62 63 #: models.py:19 64 msgctxt "other super search" 65 msgid "%(number)s super result" 66 msgid_plural "%(number)s super results" 67 msgstr[0] "%(number)s anderen Super-Ergebnis" 68 msgstr[1] "%(number)s andere Super-Ergebnisse" 69 70 #: models.py:21 71 msgctxt "comment count" 72 msgid "There are %(num_comments)s comments" 73 msgstr "Es gibt %(num_comments)s Kommentare" 74 75 #: models.py:23 76 msgctxt "other comment count" 77 msgid "There are %(num_comments)s comments" 78 msgstr "Andere: Es gibt %(num_comments)s Kommentare" 79 No newline at end of file -
tests/regressiontests/i18n/tests.py
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py index fc69d9c..10e9935 100644
a b from threading import local 9 9 10 10 from django.conf import settings 11 11 from django.template import Template, Context 12 from django.template.base import TemplateSyntaxError 12 13 from django.test import TestCase, RequestFactory 13 14 from django.test.utils import override_settings 14 15 from django.utils import translation … … class TranslationTests(TestCase): 87 88 self.assertEqual(pgettext("verb", "May"), u"Kann") 88 89 self.assertEqual(npgettext("search", "%d result", "%d results", 4) % 4, u"4 Resultate") 89 90 91 def test_template_tags_pgettext(self): 92 """ 93 Ensure that message contexts are taken into account the {% trans %} and 94 {% blocktrans %} template tags. 95 Refs #14806. 96 """ 97 # Reset translation catalog to include other/locale/de 98 extended_locale_paths = settings.LOCALE_PATHS + ( 99 os.path.join(here, 'other', 'locale'), 100 ) 101 with self.settings(LOCALE_PATHS=extended_locale_paths): 102 from django.utils.translation import trans_real 103 trans_real._active = local() 104 trans_real._translations = {} 105 with translation.override('de'): 106 107 # {% trans %} ----------------------------------- 108 109 # Inexisting context... 110 t = Template('{% load i18n %}{% trans "May" context "unexisting" %}') 111 rendered = t.render(Context()) 112 self.assertEqual(rendered, 'May') 113 114 # Existing context... 115 # Using a literal 116 t = Template('{% load i18n %}{% trans "May" context "month name" %}') 117 rendered = t.render(Context()) 118 self.assertEqual(rendered, 'Mai') 119 t = Template('{% load i18n %}{% trans "May" context "verb" %}') 120 rendered = t.render(Context()) 121 self.assertEqual(rendered, 'Kann') 122 123 # Using a variable 124 t = Template('{% load i18n %}{% trans "May" context message_context %}') 125 rendered = t.render(Context({'message_context': 'month name'})) 126 self.assertEqual(rendered, 'Mai') 127 t = Template('{% load i18n %}{% trans "May" context message_context %}') 128 rendered = t.render(Context({'message_context': 'verb'})) 129 self.assertEqual(rendered, 'Kann') 130 131 # Using a filter 132 t = Template('{% load i18n %}{% trans "May" context message_context|lower %}') 133 rendered = t.render(Context({'message_context': 'MONTH NAME'})) 134 self.assertEqual(rendered, 'Mai') 135 t = Template('{% load i18n %}{% trans "May" context message_context|lower %}') 136 rendered = t.render(Context({'message_context': 'VERB'})) 137 self.assertEqual(rendered, 'Kann') 138 139 # Using 'as' 140 t = Template('{% load i18n %}{% trans "May" context "month name" as var %}Value: {{ var }}') 141 rendered = t.render(Context()) 142 self.assertEqual(rendered, 'Value: Mai') 143 t = Template('{% load i18n %}{% trans "May" as var context "verb" %}Value: {{ var }}') 144 rendered = t.render(Context()) 145 self.assertEqual(rendered, 'Value: Kann') 146 147 # Mis-uses 148 self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% trans "May" context as var %}{{ var }}') 149 self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% trans "May" as var context %}{{ var }}') 150 151 # {% blocktrans %} ------------------------------ 152 153 # Inexisting context... 154 t = Template('{% load i18n %}{% blocktrans context "unexisting" %}May{% endblocktrans %}') 155 rendered = t.render(Context()) 156 self.assertEqual(rendered, 'May') 157 158 # Existing context... 159 # Using a literal 160 t = Template('{% load i18n %}{% blocktrans context "month name" %}May{% endblocktrans %}') 161 rendered = t.render(Context()) 162 self.assertEqual(rendered, 'Mai') 163 t = Template('{% load i18n %}{% blocktrans context "verb" %}May{% endblocktrans %}') 164 rendered = t.render(Context()) 165 self.assertEqual(rendered, 'Kann') 166 167 # Using a variable 168 t = Template('{% load i18n %}{% blocktrans context message_context %}May{% endblocktrans %}') 169 rendered = t.render(Context({'message_context': 'month name'})) 170 self.assertEqual(rendered, 'Mai') 171 t = Template('{% load i18n %}{% blocktrans context message_context %}May{% endblocktrans %}') 172 rendered = t.render(Context({'message_context': 'verb'})) 173 self.assertEqual(rendered, 'Kann') 174 175 # Using a filter 176 t = Template('{% load i18n %}{% blocktrans context message_context|lower %}May{% endblocktrans %}') 177 rendered = t.render(Context({'message_context': 'MONTH NAME'})) 178 self.assertEqual(rendered, 'Mai') 179 t = Template('{% load i18n %}{% blocktrans context message_context|lower %}May{% endblocktrans %}') 180 rendered = t.render(Context({'message_context': 'VERB'})) 181 self.assertEqual(rendered, 'Kann') 182 183 # Using 'count' 184 t = Template('{% load i18n %}{% blocktrans count number=1 context "super search" %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}') 185 rendered = t.render(Context()) 186 self.assertEqual(rendered, '1 Super-Ergebnis') 187 t = Template('{% load i18n %}{% blocktrans count number=2 context "super search" %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}') 188 rendered = t.render(Context()) 189 self.assertEqual(rendered, '2 Super-Ergebnisse') 190 t = Template('{% load i18n %}{% blocktrans context "other super search" count number=1 %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}') 191 rendered = t.render(Context()) 192 self.assertEqual(rendered, '1 anderen Super-Ergebnis') 193 t = Template('{% load i18n %}{% blocktrans context "other super search" count number=2 %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}') 194 rendered = t.render(Context()) 195 self.assertEqual(rendered, '2 andere Super-Ergebnisse') 196 197 # Using 'with' 198 t = Template('{% load i18n %}{% blocktrans with num_comments=5 context "comment count" %}There are {{ num_comments }} comments{% endblocktrans %}') 199 rendered = t.render(Context()) 200 self.assertEqual(rendered, 'Es gibt 5 Kommentare') 201 t = Template('{% load i18n %}{% blocktrans with num_comments=5 context "other comment count" %}There are {{ num_comments }} comments{% endblocktrans %}') 202 rendered = t.render(Context()) 203 self.assertEqual(rendered, 'Andere: Es gibt 5 Kommentare') 204 205 # Mis-uses 206 self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% blocktrans context with month="May" %}{{ month }}{% endblocktrans %}') 207 self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% blocktrans context %}{% endblocktrans %}') 208 self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% blocktrans count number=2 context %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}') 209 210 90 211 def test_string_concat(self): 91 212 """ 92 213 unicode(string_concat(...)) should not raise a TypeError - #4796