Index: django/core/management/commands/makemessages.py
===================================================================
--- django/core/management/commands/makemessages.py	(révision 14445)
+++ django/core/management/commands/makemessages.py	(copie de travail)
@@ -225,7 +225,7 @@
                         raise SyntaxError(msg)
                 if verbosity > 1:
                     sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
-                cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
+                cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --keyword=pgettext:1c,2 --keyword=npgettext:1c,2,3 --keyword=pgettext_lazy:1c,2 --keyword=npgettext_lazy:1c,2,3 --from-code UTF-8 -o - "%s"' % (
                     domain, os.path.join(dirpath, thefile))
                 msgs, errors = _popen(cmd)
                 if errors:
Index: django/utils/translation/trans_real.py
===================================================================
--- django/utils/translation/trans_real.py	(révision 14445)
+++ django/utils/translation/trans_real.py	(copie de travail)
@@ -279,6 +279,14 @@
 def ugettext(message):
     return do_translate(message, 'ugettext')
 
+def pgettext(context, message):
+    # \x04 is a magic gettext number to separate context from message
+    result = do_translate(u"%s\x04%s" % (context, message), 'ugettext')
+    if "\x04" in result:
+        # Translation not found
+        result = message
+    return result
+
 def gettext_noop(message):
     """
     Marks strings for translation but doesn't translate them now. This can be
@@ -313,6 +321,15 @@
     """
     return do_ntranslate(singular, plural, number, 'ungettext')
 
+def npgettext(context, singular, plural, number):
+    # \x04 is a magic gettext number to separate context from message
+    result = do_ntranslate(u"%s\x04%s" % (context, singular),
+                           u"%s\x04%s" % (context, plural), number, 'ungettext')
+    if "\x04" in result:
+        # Translation not found
+        result = do_ntranslate(singular, plural, number, 'ungettext')
+    return result
+
 def check_for_language(lang_code):
     """
     Checks whether there is a global language file for the given language
Index: django/utils/translation/__init__.py
===================================================================
--- django/utils/translation/__init__.py	(révision 14445)
+++ django/utils/translation/__init__.py	(copie de travail)
@@ -10,7 +10,8 @@
         'get_language', 'get_language_bidi', 'get_date_formats',
         'get_partial_date_formats', 'check_for_language', 'to_locale',
         'get_language_from_request', 'templatize', 'ugettext', 'ugettext_lazy',
-        'ungettext', 'deactivate_all']
+        'ungettext', 'ungettext_lazy', 'pgettext', 'pgettext_lazy',
+        'npgettext', 'npgettext_lazy', 'deactivate_all']
 
 # Here be dragons, so a short explanation of the logic won't hurt:
 # We are trying to solve two problems: (1) access settings, in particular
@@ -63,10 +64,18 @@
 def ungettext(singular, plural, number):
     return _trans.ungettext(singular, plural, number)
 
+def pgettext(context, message):
+    return _trans.pgettext(context, message)
+
+def npgettext(context, singular, plural, number):
+    return _trans.npgettext(context, singular, plural, number)
+
 ngettext_lazy = lazy(ngettext, str)
 gettext_lazy = lazy(gettext, str)
 ungettext_lazy = lazy(ungettext, unicode)
 ugettext_lazy = lazy(ugettext, unicode)
+pgettext_lazy = lazy(pgettext, unicode)
+npgettext_lazy = lazy(npgettext, unicode)
 
 def activate(language):
     return _trans.activate(language)
Index: django/utils/translation/trans_null.py
===================================================================
--- django/utils/translation/trans_null.py	(révision 14445)
+++ django/utils/translation/trans_null.py	(copie de travail)
@@ -15,6 +15,12 @@
 def ungettext(singular, plural, number):
     return force_unicode(ngettext(singular, plural, number))
 
+def pgettext(context, message):
+    return ugettext(message)
+
+def npgettext(context, singular, plural, number):
+    return ungettext(singular, plural, number)
+
 activate = lambda x: None
 deactivate = deactivate_all = lambda: None
 get_language = lambda: settings.LANGUAGE_CODE
Index: tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po
===================================================================
--- tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po	(révision 14445)
+++ tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po	(copie de travail)
@@ -20,3 +20,20 @@
 #: models.py:3
 msgid "Date/time"
 msgstr "Datum/Zeit (LOCALE_PATHS)"
+
+#: models.py:5
+msgctxt "month name"
+msgid "May"
+msgstr "Mai"
+
+#: models.py:7
+msgctxt "verb"
+msgid "May"
+msgstr "Kann"
+
+#: models.py:9
+msgctxt "search"
+msgid "%d result"
+msgid_plural "%d results"
+msgstr[0] "%d Resultat"
+msgstr[1] "%d Resultate"
Index: tests/regressiontests/i18n/tests.py
===================================================================
--- tests/regressiontests/i18n/tests.py	(révision 14445)
+++ tests/regressiontests/i18n/tests.py	(copie de travail)
@@ -11,7 +11,7 @@
 from django.utils.formats import get_format, date_format, time_format, localize, localize_input, iter_format_modules
 from django.utils.numberformat import format as nformat
 from django.utils.safestring import mark_safe, SafeString, SafeUnicode
-from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy, to_locale
+from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy, pgettext, npgettext, to_locale
 from django.utils.importlib import import_module
 
 
@@ -54,6 +54,22 @@
         s2 = pickle.loads(pickle.dumps(s1))
         self.assertEqual(unicode(s2), "test")
 
+    def test_pgettext(self):
+        # Reset translation catalog to include other/locale/de
+        self.old_locale_paths = settings.LOCALE_PATHS
+        settings.LOCALE_PATHS += (os.path.join(os.path.dirname(os.path.abspath(__file__)), 'other', 'locale'),)
+        from django.utils.translation import trans_real
+        trans_real._active = {}
+        trans_real._translations = {}
+        activate('de')
+
+        self.assertEqual(pgettext("unexisting", "May"), u"May")
+        self.assertEqual(pgettext("month name", "May"), u"Mai")
+        self.assertEqual(pgettext("verb", "May"), u"Kann")
+        self.assertEqual(npgettext("search", "%d result", "%d results", 4) % 4, u"4 Resultate")
+
+        settings.LOCALE_PATHS = self.old_locale_paths
+
     def test_string_concat(self):
         """
         unicode(string_concat(...)) should not raise a TypeError - #4796
