summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/utils/translation/trans_real.py2
-rw-r--r--tests/regressiontests/i18n/commands/compilation.py63
-rw-r--r--tests/regressiontests/i18n/commands/extraction.py183
-rw-r--r--tests/regressiontests/i18n/commands/locale/fr/LC_MESSAGES/django.po71
-rw-r--r--tests/regressiontests/i18n/commands/templates/test.html11
-rw-r--r--tests/regressiontests/i18n/tests.py3
6 files changed, 253 insertions, 80 deletions
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index f43cfd9705..3addf1ddfb 100644
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -439,6 +439,7 @@ block_re = re.compile(r"""^\s*blocktrans(\s+.*context\s+(?:"[^"]*?")|(?:'[^']*?'
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 @@ def templatize(src, origin=None):
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
index 98b4b33356..1f38910b61 100644
--- a/tests/regressiontests/i18n/commands/compilation.py
+++ b/tests/regressiontests/i18n/commands/compilation.py
@@ -7,17 +7,15 @@ except ImportError:
from django.core.management import CommandError
from django.core.management.commands.compilemessages import compile_messages
from django.test import TestCase
+from django.test.utils import override_settings
+from django.utils import translation
-
-LOCALE='es_AR'
+test_dir = os.path.abspath(os.path.dirname(__file__))
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__))
def tearDown(self):
os.chdir(self._cwd)
@@ -25,11 +23,60 @@ class MessageCompilationTests(TestCase):
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()
+ os.chdir(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()
- 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):
+ # Ticket #11240
+
+ LOCALE='fr'
+ MO_FILE='locale/%s/LC_MESSAGES/django.mo' % LOCALE
+
+ def setUp(self):
+ super(PoFileContentsTests, self).setUp()
+ self.addCleanup(os.unlink, os.path.join(test_dir, self.MO_FILE))
+
+ def test_percent_symbol_in_po_file(self):
+ os.chdir(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))
+
+
+class PercentRenderingTests(MessageCompilationTests):
+ # Ticket #11240 -- Testing rendering doesn't belong here but we are trying
+ # to keep tests for all the stack together
+
+ LOCALE='it'
+ MO_FILE='locale/%s/LC_MESSAGES/django.mo' % LOCALE
+
+ @override_settings(LOCALE_PATHS=(os.path.join(test_dir, 'locale'),))
+ def test_percent_symbol_escaping(self):
+ from django.template import Template, Context
+ os.chdir(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)
+ with translation.override(self.LOCALE):
+ t = Template('{% load i18n %}{% trans "Looks like a str fmt spec %% o but shouldn\'t be interpreted as such" %}')
+ rendered = t.render(Context({}))
+ self.assertEqual(rendered, 'IT translation contains %% for the above string')
+
+ t = Template('{% load i18n %}{% trans "Completed 50%% of all the tasks" %}')
+ rendered = t.render(Context({}))
+ self.assertEqual(rendered, 'IT translation of Completed 50%% of all the tasks')
diff --git a/tests/regressiontests/i18n/commands/extraction.py b/tests/regressiontests/i18n/commands/extraction.py
index fb612a3a42..e6796d47f4 100644
--- a/tests/regressiontests/i18n/commands/extraction.py
+++ b/tests/regressiontests/i18n/commands/extraction.py
@@ -31,10 +31,13 @@ class ExtractorTests(TestCase):
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:
@@ -49,35 +52,57 @@ class BasicExtractorTests(ExtractorTests):
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.assertTrue('#. Translators: This comment should be extracted' in po_contents)
- self.assertTrue('This comment should not be extracted' not in po_contents)
- # Comments in templates
- self.assertTrue('#. Translators: Django template comment for translators' in po_contents)
- self.assertTrue("#. Translators: Django comment block for translators\n#. string's meaning unveiled" in po_contents)
+ #po_contents = open(self.PO_FILE, 'r').read()
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.read()
+ self.assertTrue('#. Translators: This comment should be extracted' in po_contents)
+ self.assertTrue('This comment should not be extracted' not in po_contents)
+ # Comments in templates
+ self.assertTrue('#. Translators: Django template comment for translators' in po_contents)
+ self.assertTrue("#. Translators: Django comment block for translators\n#. string's meaning unveiled" in po_contents)
- self.assertTrue('#. Translators: One-line translator comment #1' in po_contents)
- self.assertTrue('#. Translators: Two-line translator comment #1\n#. continued here.' in po_contents)
+ self.assertTrue('#. Translators: One-line translator comment #1' in po_contents)
+ self.assertTrue('#. Translators: Two-line translator comment #1\n#. continued here.' in po_contents)
- self.assertTrue('#. Translators: One-line translator comment #2' in po_contents)
- self.assertTrue('#. Translators: Two-line translator comment #2\n#. continued here.' in po_contents)
+ self.assertTrue('#. Translators: One-line translator comment #2' in po_contents)
+ self.assertTrue('#. Translators: Two-line translator comment #2\n#. continued here.' in po_contents)
- self.assertTrue('#. Translators: One-line translator comment #3' in po_contents)
- self.assertTrue('#. Translators: Two-line translator comment #3\n#. continued here.' in po_contents)
+ self.assertTrue('#. Translators: One-line translator comment #3' in po_contents)
+ self.assertTrue('#. Translators: Two-line translator comment #3\n#. continued here.' in po_contents)
- self.assertTrue('#. Translators: One-line translator comment #4' in po_contents)
- self.assertTrue('#. Translators: Two-line translator comment #4\n#. continued here.' in po_contents)
+ self.assertTrue('#. Translators: One-line translator comment #4' in po_contents)
+ self.assertTrue('#. Translators: Two-line translator comment #4\n#. continued here.' in po_contents)
- 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)
+ 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('I think that 100%% is more that 50%% of anything.', po_contents)
- self.assertMsgId('I think that 100%% is more that 50%% of %(obj)s.', po_contents)
+ #po_contents = open(self.PO_FILE, 'r').read()
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.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))
+ #po_contents = open(self.PO_FILE, 'r').read()
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.read()
+ self.assertMsgId('I think that 100%% is more that 50%% of anything.', po_contents)
+ self.assertMsgId('I think that 100%% is more that 50%% of %(obj)s.', po_contents)
def test_extraction_error(self):
os.chdir(self.test_dir)
@@ -103,26 +128,28 @@ class BasicExtractorTests(ExtractorTests):
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()
- # {% trans %}
- self.assertTrue('msgctxt "Special trans context #1"' in po_contents)
- self.assertTrue("Translatable literal #7a" in po_contents)
- self.assertTrue('msgctxt "Special trans context #2"' in po_contents)
- self.assertTrue("Translatable literal #7b" in po_contents)
- self.assertTrue('msgctxt "Special trans context #3"' in po_contents)
- self.assertTrue("Translatable literal #7c" in po_contents)
+ #po_contents = open(self.PO_FILE, 'r').read()
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.read()
+ # {% trans %}
+ self.assertTrue('msgctxt "Special trans context #1"' in po_contents)
+ self.assertTrue("Translatable literal #7a" in po_contents)
+ self.assertTrue('msgctxt "Special trans context #2"' in po_contents)
+ self.assertTrue("Translatable literal #7b" in po_contents)
+ self.assertTrue('msgctxt "Special trans context #3"' in po_contents)
+ self.assertTrue("Translatable literal #7c" in po_contents)
- # {% blocktrans %}
- self.assertTrue('msgctxt "Special blocktrans context #1"' in po_contents)
- self.assertTrue("Translatable literal #8a" in po_contents)
- self.assertTrue('msgctxt "Special blocktrans context #2"' in po_contents)
- self.assertTrue("Translatable literal #8b-singular" in po_contents)
- self.assertTrue("Translatable literal #8b-plural" in po_contents)
- self.assertTrue('msgctxt "Special blocktrans context #3"' in po_contents)
- self.assertTrue("Translatable literal #8c-singular" in po_contents)
- self.assertTrue("Translatable literal #8c-plural" in po_contents)
- self.assertTrue('msgctxt "Special blocktrans context #4"' in po_contents)
- self.assertTrue("Translatable literal #8d" in po_contents)
+ # {% blocktrans %}
+ self.assertTrue('msgctxt "Special blocktrans context #1"' in po_contents)
+ self.assertTrue("Translatable literal #8a" in po_contents)
+ self.assertTrue('msgctxt "Special blocktrans context #2"' in po_contents)
+ self.assertTrue("Translatable literal #8b-singular" in po_contents)
+ self.assertTrue("Translatable literal #8b-plural" in po_contents)
+ self.assertTrue('msgctxt "Special blocktrans context #3"' in po_contents)
+ self.assertTrue("Translatable literal #8c-singular" in po_contents)
+ self.assertTrue("Translatable literal #8c-plural" in po_contents)
+ self.assertTrue('msgctxt "Special blocktrans context #4"' in po_contents)
+ self.assertTrue("Translatable literal #8d" in po_contents)
class JavascriptExtractorTests(ExtractorTests):
@@ -132,20 +159,22 @@ class JavascriptExtractorTests(ExtractorTests):
os.chdir(self.test_dir)
management.call_command('makemessages', domain='djangojs', locale=LOCALE, verbosity=0)
self.assertTrue(os.path.exists(self.PO_FILE))
- po_contents = open(self.PO_FILE, 'r').read()
- self.assertMsgId('This literal should be included.', po_contents)
- self.assertMsgId('This one as well.', po_contents)
- self.assertMsgId(r'He said, \"hello\".', po_contents)
- self.assertMsgId("okkkk", po_contents)
- self.assertMsgId("TEXT", po_contents)
- self.assertMsgId("It's at http://example.com", po_contents)
- self.assertMsgId("String", po_contents)
- self.assertMsgId("/* but this one will be too */ 'cause there is no way of telling...", po_contents)
- self.assertMsgId("foo", po_contents)
- self.assertMsgId("bar", po_contents)
- self.assertMsgId("baz", po_contents)
- self.assertMsgId("quz", po_contents)
- self.assertMsgId("foobar", po_contents)
+ #po_contents = open(self.PO_FILE, 'r').read()
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.read()
+ self.assertMsgId('This literal should be included.', po_contents)
+ self.assertMsgId('This one as well.', po_contents)
+ self.assertMsgId(r'He said, \"hello\".', po_contents)
+ self.assertMsgId("okkkk", po_contents)
+ self.assertMsgId("TEXT", po_contents)
+ self.assertMsgId("It's at http://example.com", po_contents)
+ self.assertMsgId("String", po_contents)
+ self.assertMsgId("/* but this one will be too */ 'cause there is no way of telling...", po_contents)
+ self.assertMsgId("foo", po_contents)
+ self.assertMsgId("bar", po_contents)
+ self.assertMsgId("baz", po_contents)
+ self.assertMsgId("quz", po_contents)
+ self.assertMsgId("foobar", po_contents)
class IgnoredExtractorTests(ExtractorTests):
@@ -154,9 +183,11 @@ class IgnoredExtractorTests(ExtractorTests):
pattern1 = os.path.join('ignore_dir', '*')
management.call_command('makemessages', locale=LOCALE, verbosity=0, ignore_patterns=[pattern1])
self.assertTrue(os.path.exists(self.PO_FILE))
- po_contents = open(self.PO_FILE, 'r').read()
- self.assertMsgId('This literal should be included.', po_contents)
- self.assertNotMsgId('This should be ignored.', po_contents)
+ #po_contents = open(self.PO_FILE, 'r').read()
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.read()
+ self.assertMsgId('This literal should be included.', po_contents)
+ self.assertNotMsgId('This should be ignored.', po_contents)
class SymlinkExtractorTests(ExtractorTests):
@@ -184,9 +215,11 @@ class SymlinkExtractorTests(ExtractorTests):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=LOCALE, verbosity=0, symlinks=True)
self.assertTrue(os.path.exists(self.PO_FILE))
- po_contents = open(self.PO_FILE, 'r').read()
- self.assertMsgId('This literal should be included.', po_contents)
- self.assertTrue('templates_symlinked/test.html' in po_contents)
+ #po_contents = open(self.PO_FILE, 'r').read()
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.read()
+ self.assertMsgId('This literal should be included.', po_contents)
+ self.assertTrue('templates_symlinked/test.html' in po_contents)
class CopyPluralFormsExtractorTests(ExtractorTests):
@@ -195,8 +228,10 @@ class CopyPluralFormsExtractorTests(ExtractorTests):
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.assertTrue('Plural-Forms: nplurals=2; plural=(n != 1)' in po_contents)
+ #po_contents = open(self.PO_FILE, 'r').read()
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.read()
+ self.assertTrue('Plural-Forms: nplurals=2; plural=(n != 1)' in po_contents)
class NoWrapExtractorTests(ExtractorTests):
@@ -205,15 +240,19 @@ class NoWrapExtractorTests(ExtractorTests):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=LOCALE, verbosity=0, no_wrap=True)
self.assertTrue(os.path.exists(self.PO_FILE))
- po_contents = open(self.PO_FILE, 'r').read()
- self.assertMsgId('This literal should also be included wrapped or not wrapped depending on the use of the --no-wrap option.', po_contents)
+ #po_contents = open(self.PO_FILE, 'r').read()
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.read()
+ self.assertMsgId('This literal should also be included wrapped or not wrapped depending on the use of the --no-wrap option.', po_contents)
def test_no_wrap_disabled(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=LOCALE, verbosity=0, no_wrap=False)
self.assertTrue(os.path.exists(self.PO_FILE))
- po_contents = open(self.PO_FILE, 'r').read()
- self.assertMsgId('""\n"This literal should also be included wrapped or not wrapped depending on the "\n"use of the --no-wrap option."', po_contents, use_quotes=False)
+ #po_contents = open(self.PO_FILE, 'r').read()
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.read()
+ self.assertMsgId('""\n"This literal should also be included wrapped or not wrapped depending on the "\n"use of the --no-wrap option."', po_contents, use_quotes=False)
class NoLocationExtractorTests(ExtractorTests):
@@ -222,12 +261,16 @@ class NoLocationExtractorTests(ExtractorTests):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=LOCALE, verbosity=0, no_location=True)
self.assertTrue(os.path.exists(self.PO_FILE))
- po_contents = open(self.PO_FILE, 'r').read()
- self.assertFalse('#: templates/test.html:55' in po_contents)
+ #po_contents = open(self.PO_FILE, 'r').read()
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.read()
+ self.assertFalse('#: templates/test.html:55' in po_contents)
def test_no_location_disabled(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=LOCALE, verbosity=0, no_location=False)
self.assertTrue(os.path.exists(self.PO_FILE))
- po_contents = open(self.PO_FILE, 'r').read()
- self.assertTrue('#: templates/test.html:55' in po_contents)
+ #po_contents = open(self.PO_FILE, 'r').read()
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.read()
+ self.assertTrue('#: templates/test.html:55' in po_contents)
diff --git a/tests/regressiontests/i18n/commands/locale/fr/LC_MESSAGES/django.po b/tests/regressiontests/i18n/commands/locale/fr/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..26bf6f133c
--- /dev/null
+++ b/tests/regressiontests/i18n/commands/locale/fr/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-10 19:12-0300\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: fr\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
index 24fc708621..6f794af789 100644
--- a/tests/regressiontests/i18n/commands/templates/test.html
+++ b/tests/regressiontests/i18n/commands/templates/test.html
@@ -65,4 +65,13 @@ continued here.{% endcomment %}
{% 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
index 33b16886cb..cc17d74315 100644
--- a/tests/regressiontests/i18n/tests.py
+++ b/tests/regressiontests/i18n/tests.py
@@ -31,7 +31,8 @@ if can_run_extraction_tests:
CopyPluralFormsExtractorTests, NoWrapExtractorTests,
NoLocationExtractorTests)
if can_run_compilation_tests:
- from .commands.compilation import MessageCompilationTests, PoFileTests
+ from .commands.compilation import (PoFileTests, PoFileContentsTests,
+ PercentRenderingTests)
from .contenttypes.tests import ContentTypeTests
from .forms import I18nForm, SelectDateForm, SelectDateWidget, CompanyForm
from .models import Company, TestModel