diff --git a/django/template/base.py b/django/template/base.py
index 8001e93..3129886 100644
--- a/django/template/base.py
+++ b/django/template/base.py
@@ -10,7 +10,7 @@ from django.utils.itercompat import is_iterable
 from django.utils.text import (smart_split, unescape_string_literal,
     get_text_list)
 from django.utils.encoding import smart_unicode, force_unicode, smart_str
-from django.utils.translation import ugettext_lazy
+from django.utils.translation import ugettext_lazy, pgettext_lazy
 from django.utils.safestring import (SafeData, EscapeData, mark_safe,
     mark_for_escaping)
 from django.utils.formats import localize
@@ -673,6 +673,7 @@ class Variable(object):
         self.literal = None
         self.lookups = None
         self.translate = False
+        self.trans_context = None
 
         try:
             # First try to treat this variable as a number.
@@ -720,7 +721,10 @@ class Variable(object):
             # We're dealing with a literal, so it's already been "resolved"
             value = self.literal
         if self.translate:
-            return ugettext_lazy(value)
+            if self.trans_context:
+                return pgettext_lazy(self.trans_context, value)
+            else:
+                return ugettext_lazy(value)
         return value
 
     def __repr__(self):
@@ -814,11 +818,10 @@ class NodeList(list):
         bits = []
         for node in self:
             if isinstance(node, Node):
-                bit = self.render_node(node, context)
+                bits.append(self.render_node(node, context))
             else:
-                bit = node
-            bits.append(force_unicode(bit))
-        return mark_safe(u''.join(bits))
+                bits.append(node)
+        return mark_safe(''.join([force_unicode(b) for b in bits]))
 
     def get_nodes_by_type(self, nodetype):
         "Return a list of all nodes of the given type"
diff --git a/django/templatetags/i18n.py b/django/templatetags/i18n.py
index 669cdc9..4f64316 100644
--- a/django/templatetags/i18n.py
+++ b/django/templatetags/i18n.py
@@ -70,15 +70,21 @@ class GetCurrentLanguageBidiNode(Node):
 
 
 class TranslateNode(Node):
-    def __init__(self, filter_expression, noop, asvar=None):
+    def __init__(self, filter_expression, noop, asvar=None,
+                 trans_context=None):
         self.noop = noop
         self.asvar = asvar
+        self.trans_context = trans_context
         self.filter_expression = filter_expression
         if isinstance(self.filter_expression.var, basestring):
-            self.filter_expression.var = Variable(u"'%s'" % self.filter_expression.var)
+            self.filter_expression.var = Variable(u"'%s'" %
+                                                  self.filter_expression.var)
 
     def render(self, context):
         self.filter_expression.var.translate = not self.noop
+        if self.trans_context:
+            self.filter_expression.var.trans_context = (
+                self.trans_context.resolve(context))
         output = self.filter_expression.resolve(context)
         value = _render_value_in_context(output, context)
         if self.asvar:
@@ -90,12 +96,13 @@ class TranslateNode(Node):
 
 class BlockTranslateNode(Node):
     def __init__(self, extra_context, singular, plural=None, countervar=None,
-            counter=None):
+            counter=None, trans_context=None):
         self.extra_context = extra_context
         self.singular = singular
         self.plural = plural
         self.countervar = countervar
         self.counter = counter
+        self.trans_context = trans_context
 
     def render_token_list(self, tokens):
         result = []
@@ -109,6 +116,10 @@ class BlockTranslateNode(Node):
         return ''.join(result), vars
 
     def render(self, context):
+        if self.trans_context:
+            trans_context = self.trans_context.resolve(context)
+        else:
+            trans_context = None
         tmp_context = {}
         for var, val in self.extra_context.items():
             tmp_context[var] = val.resolve(context)
@@ -123,10 +134,17 @@ class BlockTranslateNode(Node):
             context[self.countervar] = count
             plural, plural_vars = self.render_token_list(self.plural)
             plural = re.sub(u'%(?!\()', u'%%', plural)
-            result = translation.ungettext(singular, plural, count)
+            if trans_context:
+                result = translation.npgettext(trans_context, singular, plural,
+                                               count)
+            else:
+                result = translation.ungettext(singular, plural, count)
             vars.extend(plural_vars)
         else:
-            result = translation.ugettext(singular)
+            if trans_context:
+                result = translation.pgettext(trans_context, singular)
+            else:
+                result = translation.ugettext(singular)
         data = dict([(v, _render_value_in_context(context.get(v, ''), context)) for v in vars])
         context.pop()
         try:
@@ -301,7 +319,6 @@ def do_translate(parser, token):
             # backwards compatibility with existing uses of ``trans``
             # where single quote use is supported.
             if value[0] == "'":
-                pos = None
                 m = re.match("^'([^']+)'(\|.*$)", value)
                 if m:
                     value = '"%s"%s' % (m.group(1).replace('"','\\"'), m.group(2))
@@ -310,19 +327,23 @@ def do_translate(parser, token):
 
             noop = False
             asvar = None
+            trans_context = None
 
             while self.more():
                 tag = self.tag()
                 if tag == 'noop':
                     noop = True
+                elif tag == 'context':
+                    trans_context = parser.compile_filter(self.tag())
                 elif tag == 'as':
                     asvar = self.tag()
                 else:
                     raise TemplateSyntaxError(
                         "only options for 'trans' are 'noop' and 'as VAR.")
-            return (value, noop, asvar)
-    value, noop, asvar = TranslateParser(token.contents).top()
-    return TranslateNode(parser.compile_filter(value), noop, asvar)
+            return value, noop, asvar, trans_context
+    value, noop, asvar, trans_context = TranslateParser(token.contents).top()
+    return TranslateNode(parser.compile_filter(value), noop, asvar,
+                         trans_context)
 
 @register.tag("blocktrans")
 def do_block_translate(parser, token):
@@ -369,6 +390,13 @@ def do_block_translate(parser, token):
             if len(value) != 1:
                 raise TemplateSyntaxError('"count" in %r tag expected exactly '
                                           'one keyword argument.' % bits[0])
+        elif option == "context":
+            try:
+                value = remaining_bits.pop(0)
+                value = parser.compile_filter(value)
+            except Exception:
+                raise TemplateSyntaxError('"context" in %r tag expected '
+                                          'exactly one argument.' % bits[0])
         else:
             raise TemplateSyntaxError('Unknown argument for %r tag: %r.' %
                                       (bits[0], option))
@@ -378,7 +406,11 @@ def do_block_translate(parser, token):
         countervar, counter = options['count'].items()[0]
     else:
         countervar, counter = None, None
-    extra_context = options.get('with', {}) 
+    if 'context' in options:
+        trans_context = options['context']
+    else:
+        trans_context = None
+    extra_context = options.get('with', {})
 
     singular = []
     plural = []
@@ -401,7 +433,7 @@ def do_block_translate(parser, token):
         raise TemplateSyntaxError("'blocktrans' doesn't allow other block tags (seen %r) inside it" % token.contents)
 
     return BlockTranslateNode(extra_context, singular, plural, countervar,
-            counter)
+            counter, trans_context)
 
 @register.tag
 def language(parser, token):
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 a1a93c83296f0fb97d500466a8df30338fdb137e..9ab2f4672535fe38d864ec37cbd7815cac8db453 100644
GIT binary patch
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..9bf79ce 100644
--- a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po
+++ b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po
@@ -52,3 +52,18 @@ msgid "%(percent)s%% represents %(num)s object"
 msgid_plural "%(percent)s%% represents %(num)s objects"
 msgstr[0] "%(percent)s%% stellt %(num)s Objekt dar"
 msgstr[1] "%(percent)s%% stellt %(num)s Objekte dar"
+
+#: models.py:17
+msgctxt "super search"
+msgid "%(number)s super result"
+msgid_plural "%(number)s super results"
+msgstr[0] "%(number)s Super-Ergebnis"
+msgstr[1] "%(number)s Super-Ergebnisse"
+
+#: models.py:19
+msgctxt "other super search"
+msgid "%(number)s super result"
+msgid_plural "%(number)s super results"
+msgstr[0] "%(number)s anderen Super-Ergebnis"
+msgstr[1] "%(number)s andere Super-Ergebnisse"
+
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
index fc69d9c..7b0e285 100644
--- a/tests/regressiontests/i18n/tests.py
+++ b/tests/regressiontests/i18n/tests.py
@@ -9,6 +9,7 @@ from threading import local
 
 from django.conf import settings
 from django.template import Template, Context
+from django.template.base import TemplateSyntaxError
 from django.test import TestCase, RequestFactory
 from django.test.utils import override_settings
 from django.utils import translation
@@ -87,6 +88,69 @@ class TranslationTests(TestCase):
                 self.assertEqual(pgettext("verb", "May"), u"Kann")
                 self.assertEqual(npgettext("search", "%d result", "%d results", 4) % 4, u"4 Resultate")
 
+    def test_template_tags_pgettext(self):
+        # Reset translation catalog to include other/locale/de
+        extended_locale_paths = settings.LOCALE_PATHS + (
+            os.path.join(here, 'other', 'locale'),
+        )
+        with self.settings(LOCALE_PATHS=extended_locale_paths):
+            from django.utils.translation import trans_real
+            trans_real._active = local()
+            trans_real._translations = {}
+            with translation.override('de'):
+
+                # Blocktrans ---------
+
+                # Inexisting context...
+                t = Template('{% load i18n %}{% blocktrans context "unexisting" %}May{% endblocktrans %}')
+                rendered = t.render(Context())
+                self.assertEqual(rendered, 'May')
+
+                # Existing context...
+                # Using a literal
+                t = Template('{% load i18n %}{% blocktrans context "month name" %}May{% endblocktrans %}')
+                rendered = t.render(Context())
+                self.assertEqual(rendered, 'Mai')
+                t = Template('{% load i18n %}{% blocktrans context "verb" %}May{% endblocktrans %}')
+                rendered = t.render(Context())
+                self.assertEqual(rendered, 'Kann')
+
+                # Using a variable
+                t = Template('{% load i18n %}{% blocktrans context trans_context %}May{% endblocktrans %}')
+                rendered = t.render(Context({'trans_context': 'month name'}))
+                self.assertEqual(rendered, 'Mai')
+                t = Template('{% load i18n %}{% blocktrans context trans_context %}May{% endblocktrans %}')
+                rendered = t.render(Context({'trans_context': 'verb'}))
+                self.assertEqual(rendered, 'Kann')
+
+                # Using a filter
+                t = Template('{% load i18n %}{% blocktrans context trans_context|lower %}May{% endblocktrans %}')
+                rendered = t.render(Context({'trans_context': 'MONTH NAME'}))
+                self.assertEqual(rendered, 'Mai')
+                t = Template('{% load i18n %}{% blocktrans context trans_context|lower %}May{% endblocktrans %}')
+                rendered = t.render(Context({'trans_context': 'VERB'}))
+                self.assertEqual(rendered, 'Kann')
+
+                # Using 'count'
+                t = Template('{% load i18n %}{% blocktrans count number=1 context "super search" %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}')
+                rendered = t.render(Context())
+                self.assertEqual(rendered, '1 Super-Ergebnis')
+                t = Template('{% load i18n %}{% blocktrans count number=2 context "super search" %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}')
+                rendered = t.render(Context())
+                self.assertEqual(rendered, '2 Super-Ergebnisse')
+                t = Template('{% load i18n %}{% blocktrans count number=1 context "other super search" %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}')
+                rendered = t.render(Context())
+                self.assertEqual(rendered, '1 anderen Super-Ergebnis')
+                t = Template('{% load i18n %}{% blocktrans count number=2 context "other super search" %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}')
+                rendered = t.render(Context())
+                self.assertEqual(rendered, '2 andere Super-Ergebnisse')
+
+                # Mis-uses
+                self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% blocktrans context with month="May" %}{{ month }}{% endblocktrans %}')
+                self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% blocktrans context %}{% endblocktrans %}')
+                self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% blocktrans count number=2 context %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}')
+
+
     def test_string_concat(self):
         """
         unicode(string_concat(...)) should not raise a TypeError - #4796
