diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -439,6 +439,7 @@
 endblock_re = re.compile(r"""^\s*endblocktrans$""")
 plural_re = re.compile(r"""^\s*plural$""")
 constant_re = re.compile(r"""_\(((?:".*?")|(?:'.*?'))\)""")
+one_percent_re = re.compile(r"""(?<!%)%(?!%)""")
 
 
 def templatize(src, origin=None):
@@ -529,6 +530,7 @@
                         g = g.strip('"')
                     elif g[0] == "'":
                         g = g.strip("'")
+                    g = one_percent_re.sub('%%', g)
                     if imatch.group(2):
                         # A context is provided
                         context_match = context_re.match(imatch.group(2))
diff --git a/tests/regressiontests/i18n/commands/compilation.py b/tests/regressiontests/i18n/commands/compilation.py
--- a/tests/regressiontests/i18n/commands/compilation.py
+++ b/tests/regressiontests/i18n/commands/compilation.py
@@ -9,12 +9,8 @@
 from django.test import TestCase
 
 
-LOCALE='es_AR'
-
 class MessageCompilationTests(TestCase):
 
-    MO_FILE='locale/%s/LC_MESSAGES/django.mo' % LOCALE
-
     def setUp(self):
         self._cwd = os.getcwd()
         self.test_dir = os.path.abspath(os.path.dirname(__file__))
@@ -25,11 +21,34 @@
 
 class PoFileTests(MessageCompilationTests):
 
+    LOCALE='es_AR'
+    MO_FILE='locale/%s/LC_MESSAGES/django.mo' % LOCALE
+
     def test_bom_rejection(self):
         os.chdir(self.test_dir)
-        # We don't use the django.core.management intrastructure (call_command()
+        # We don't use the django.core.management infrastructure (call_command()
         # et al) because CommandError's cause exit(1) there. We test the
         # underlying compile_messages function instead
         out = StringIO()
-        self.assertRaises(CommandError, compile_messages, out, locale=LOCALE)
+        self.assertRaises(CommandError, compile_messages, out, locale=self.LOCALE)
         self.assertFalse(os.path.exists(self.MO_FILE))
+
+
+class PoFileContentsTests(MessageCompilationTests):
+
+    LOCALE='de'
+    MO_FILE='locale/%s/LC_MESSAGES/django.mo' % LOCALE
+
+    def setUp(self):
+        super(PoFileContentsTests, self).setUp()
+        self.addCleanup(os.unlink, os.path.join(self.test_dir, self.MO_FILE))
+
+    def test_percent_symbol_in_po_file(self):
+        # ticket #11240
+        os.chdir(self.test_dir)
+        # We don't use the django.core.management infrastructure (call_command()
+        # et al) because CommandError's cause exit(1) there. We test the
+        # underlying compile_messages function instead
+        out = StringIO()
+        compile_messages(out, locale=self.LOCALE)
+        self.assertTrue(os.path.exists(self.MO_FILE))
diff --git a/tests/regressiontests/i18n/commands/extraction.py b/tests/regressiontests/i18n/commands/extraction.py
--- a/tests/regressiontests/i18n/commands/extraction.py
+++ b/tests/regressiontests/i18n/commands/extraction.py
@@ -31,10 +31,13 @@
         os.chdir(self._cwd)
 
     def assertMsgId(self, msgid, s, use_quotes=True):
+        q = '"'
         if use_quotes:
             msgid = '"%s"' % msgid
+            q = "'"
+        needle = 'msgid %s' % msgid
         msgid = re.escape(msgid)
-        return self.assertTrue(re.search('^msgid %s' % msgid, s, re.MULTILINE))
+        return self.assertTrue(re.search('^msgid %s' % msgid, s, re.MULTILINE), 'Could not find %(q)s%(n)s%(q)s in generated PO file' % {'n':needle, 'q':q})
 
     def assertNotMsgId(self, msgid, s, use_quotes=True):
         if use_quotes:
@@ -71,7 +74,23 @@
         self.assertTrue('#. Translators: One-line translator comment #5 -- with non ASCII characters: áéíóúö' in po_contents)
         self.assertTrue('#. Translators: Two-line translator comment #5 -- with non ASCII characters: áéíóúö\n#. continued here.' in po_contents)
 
-    def test_templatize(self):
+    def test_templatize_trans_tag(self):
+        # ticket #11240
+        os.chdir(self.test_dir)
+        management.call_command('makemessages', locale=LOCALE, verbosity=0)
+        self.assertTrue(os.path.exists(self.PO_FILE))
+        po_contents = open(self.PO_FILE, 'r').read()
+        self.assertMsgId('Literal with a percent symbol at the end %%', po_contents)
+        self.assertMsgId('Literal with a percent %% symbol in the middle', po_contents)
+        self.assertMsgId('Completed 50%% of all the tasks', po_contents)
+        self.assertMsgId('Completed 99%% of all the tasks', po_contents)
+        self.assertMsgId("Shouldn't double escape this sequence: %% (two percent signs)", po_contents)
+        self.assertMsgId("Shouldn't double escape this sequence %% either", po_contents)
+        self.assertMsgId("Looks like a str fmt spec %%s but shouldn't be interpreted as such", po_contents)
+        self.assertMsgId("Looks like a str fmt spec %% o but shouldn't be interpreted as such", po_contents)
+
+    def test_templatize_blocktrans_tag(self):
+        # ticket #11966
         os.chdir(self.test_dir)
         management.call_command('makemessages', locale=LOCALE, verbosity=0)
         self.assertTrue(os.path.exists(self.PO_FILE))
diff --git a/tests/regressiontests/i18n/commands/locale/de/LC_MESSAGES/django.po b/tests/regressiontests/i18n/commands/locale/de/LC_MESSAGES/django.po
new file mode 100644
--- /dev/null
+++ b/tests/regressiontests/i18n/commands/locale/de/LC_MESSAGES/django.po
@@ -0,0 +1,71 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-12-04 04:59-0600\n"
+"PO-Revision-Date: 2011-12-04 10:03-0300\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#. Translators: Django template comment for translators
+#: templates/test.html:9
+#, python-format
+msgid "I think that 100%% is more that 50%% of anything."
+msgstr ""
+
+#: templates/test.html:10
+#, python-format
+msgid "I think that 100%% is more that 50%% of %(obj)s."
+msgstr ""
+
+#: templates/test.html:70
+#, python-format
+msgid "Literal with a percent symbol at the end %%"
+msgstr ""
+
+#: templates/test.html:71
+#, python-format
+msgid "Literal with a percent %% symbol in the middle"
+msgstr ""
+
+#: templates/test.html:72
+#, python-format
+msgid "Completed 50%% of all the tasks"
+msgstr ""
+
+#: templates/test.html:73
+#, python-format
+msgctxt "ctx0"
+msgid "Completed 99%% of all the tasks"
+msgstr ""
+
+#: templates/test.html:74
+#, python-format
+msgid "Shouldn't double escape this sequence: %% (two percent signs)"
+msgstr ""
+
+#: templates/test.html:75
+#, python-format
+msgctxt "ctx1"
+msgid "Shouldn't double escape this sequence %% either"
+msgstr ""
+
+#: templates/test.html:76
+#, python-format
+msgid "Looks like a str fmt spec %%s but shouldn't be interpreted as such"
+msgstr "Translation of the above string"
+
+#: templates/test.html:77
+#, python-format
+msgid "Looks like a str fmt spec %% o but shouldn't be interpreted as such"
+msgstr "Translation contains %% for the above string"
diff --git a/tests/regressiontests/i18n/commands/templates/test.html b/tests/regressiontests/i18n/commands/templates/test.html
--- a/tests/regressiontests/i18n/commands/templates/test.html
+++ b/tests/regressiontests/i18n/commands/templates/test.html
@@ -65,4 +65,13 @@
 {% blocktrans context "Special blocktrans context #1" %}Translatable literal #8a{% endblocktrans %}
 {% blocktrans count 2 context "Special blocktrans context #2" %}Translatable literal #8b-singular{% plural %}Translatable literal #8b-plural{% endblocktrans %}
 {% blocktrans context "Special blocktrans context #3" count 2 %}Translatable literal #8c-singular{% plural %}Translatable literal #8c-plural{% endblocktrans %}
-{% blocktrans with a=1 context "Special blocktrans context #4" %}Translatable literal #8d {{ a }}{% endblocktrans %}
\ No newline at end of file
+{% blocktrans with a=1 context "Special blocktrans context #4" %}Translatable literal #8d {{ a }}{% endblocktrans %}
+
+{% trans "Literal with a percent symbol at the end %" %}
+{% trans "Literal with a percent % symbol in the middle" %}
+{% trans "Completed 50% of all the tasks" %}
+{% trans "Completed 99% of all the tasks" context "ctx0" %}
+{% trans "Shouldn't double escape this sequence: %% (two percent signs)" %}
+{% trans "Shouldn't double escape this sequence %% either" context "ctx1" %}
+{% trans "Looks like a str fmt spec %s but shouldn't be interpreted as such" %}
+{% trans "Looks like a str fmt spec % o but shouldn't be interpreted as such" %}
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
--- a/tests/regressiontests/i18n/tests.py
+++ b/tests/regressiontests/i18n/tests.py
@@ -31,7 +31,7 @@
         CopyPluralFormsExtractorTests, NoWrapExtractorTests,
         NoLocationExtractorTests)
 if can_run_compilation_tests:
-    from .commands.compilation import MessageCompilationTests, PoFileTests
+    from .commands.compilation import PoFileTests, PoFileContentsTests
 from .contenttypes.tests import ContentTypeTests
 from .forms import I18nForm, SelectDateForm, SelectDateWidget, CompanyForm
 from .models import Company, TestModel
