From 4a5e8087ac7676ef08e76275c1f756778b39c13e Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Sat, 17 Nov 2012 15:37:30 +0100 Subject: [PATCH] Fixed #19136 -- Properly escape gettext context prefixes in the i18n JavaScript view template. --- django/views/i18n.py | 8 +-- .../views/locale/de/LC_MESSAGES/djangojs.mo | Bin 0 -> 615 bytes .../views/locale/de/LC_MESSAGES/djangojs.po | 40 ++++++++++++++ .../views/templates/jsi18n.html | 44 +++++++++++++++ tests/regressiontests/views/tests/__init__.py | 2 +- tests/regressiontests/views/tests/i18n.py | 52 +++++++++++++++++- tests/regressiontests/views/urls.py | 7 +++ tests/regressiontests/views/views.py | 3 + 8 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 tests/regressiontests/views/locale/de/LC_MESSAGES/djangojs.mo create mode 100644 tests/regressiontests/views/locale/de/LC_MESSAGES/djangojs.po create mode 100644 tests/regressiontests/views/templates/jsi18n.html diff --git a/django/views/i18n.py b/django/views/i18n.py index 00ef224254..96643f0d7d 100644 --- a/django/views/i18n.py +++ b/django/views/i18n.py @@ -99,16 +99,16 @@ function ngettext(singular, plural, count) { function gettext_noop(msgid) { return msgid; } function pgettext(context, msgid) { - var value = gettext(context + '\x04' + msgid); - if (value.indexOf('\x04') != -1) { + var value = gettext(context + '\\x04' + msgid); + if (value.indexOf('\\x04') != -1) { value = msgid; } return value; } function npgettext(context, singular, plural, count) { - var value = ngettext(context + '\x04' + singular, context + '\x04' + plural, count); - if (value.indexOf('\x04') != -1) { + var value = ngettext(context + '\\x04' + singular, context + '\\x04' + plural, count); + if (value.indexOf('\\x04') != -1) { value = ngettext(singular, plural, count); } return value; diff --git a/tests/regressiontests/views/locale/de/LC_MESSAGES/djangojs.mo b/tests/regressiontests/views/locale/de/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000000000000000000000000000000000000..34ba691029be7805899e6e28a03d36a5eb358d2f GIT binary patch literal 615 zcmYk3(P|Vi6o#X&D03m=g$Q~PF9b!hPG*IcX}1*HEv$BMSw?RqyK_35l1Y{%TkIRO z58#b&;DdPUBls--nNrpRAOHDh{!C6Xf1eC~Fw}kU0vv+}z<^X&;4!!ckHAmx9Q*jmWA~sF=riaPI)E;qi1n3xs+7ayesA_Fa2=_;)xbJu z!=??Qb|uedpKEdCNkyy>$0}0Ei(KX+FNA#0C4-k6uA_IBU4 z^w9bCAgiX;WP2z%%(Ek05Ls+whh=O6lb1{f|-o MyW5`FCmfai1AfY)s{jB1 literal 0 HcmV?d00001 diff --git a/tests/regressiontests/views/locale/de/LC_MESSAGES/djangojs.po b/tests/regressiontests/views/locale/de/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000000..88cc35e88f --- /dev/null +++ b/tests/regressiontests/views/locale/de/LC_MESSAGES/djangojs.po @@ -0,0 +1,40 @@ +# 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 , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: django tests\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-02-14 17:33+0100\n" +"PO-Revision-Date: 2011-01-21 21:37-0300\n" +"Last-Translator: Jannis Leidel \n" +"Language-Team: 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" + +#: models.py:7 +msgctxt "month name" +msgid "May" +msgstr "Mai" + +#: models.py:9 +msgctxt "verb" +msgid "May" +msgstr "Kann" + +#: models.py:11 +msgid "%s item" +msgid_plural "%s items" +msgstr[0] "%s Element" +msgstr[1] "%s Elemente" + +#: models.py:11 +msgctxt "search" +msgid "%s result" +msgid_plural "%s results" +msgstr[0] "%s Resultat" +msgstr[1] "%s Resultate" diff --git a/tests/regressiontests/views/templates/jsi18n.html b/tests/regressiontests/views/templates/jsi18n.html new file mode 100644 index 0000000000..d6093c8ef4 --- /dev/null +++ b/tests/regressiontests/views/templates/jsi18n.html @@ -0,0 +1,44 @@ + + + + + + +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ + + diff --git a/tests/regressiontests/views/tests/__init__.py b/tests/regressiontests/views/tests/__init__.py index 12d0c59014..17f3f4562d 100644 --- a/tests/regressiontests/views/tests/__init__.py +++ b/tests/regressiontests/views/tests/__init__.py @@ -4,7 +4,7 @@ from .debug import (DebugViewTests, ExceptionReporterTests, ExceptionReporterTests, PlainTextReportTests, ExceptionReporterFilterTests, AjaxResponseExceptionReporterFilter) from .defaults import DefaultsTests -from .i18n import JsI18NTests, I18NTests, JsI18NTestsMultiPackage +from .i18n import JsI18NTests, I18NTests, JsI18NTestsMultiPackage, JavascriptI18nTests from .shortcuts import ShortcutTests from .specials import URLHandling from .static import StaticHelperTest, StaticUtilsTests, StaticTests diff --git a/tests/regressiontests/views/tests/i18n.py b/tests/regressiontests/views/tests/i18n.py index 601df6d512..d0bf7d2299 100644 --- a/tests/regressiontests/views/tests/i18n.py +++ b/tests/regressiontests/views/tests/i18n.py @@ -6,11 +6,17 @@ from os import path from django.conf import settings from django.core.urlresolvers import reverse -from django.test import TestCase -from django.utils import six -from django.utils.translation import override, get_language +from django.test import LiveServerTestCase, TestCase +from django.test.utils import override_settings +from django.utils import six, unittest +from django.utils.translation import override from django.utils.text import javascript_quote +try: + from selenium.webdriver.firefox import webdriver as firefox +except ImportError: + firefox = None + from ..urls import locale_dir @@ -152,3 +158,43 @@ class JsI18NTestsMultiPackage(TestCase): response = self.client.get('/views/jsi18n/') self.assertContains(response, javascript_quote('este texto de app3 debe ser traducido')) + + +@unittest.skipUnless(firefox, 'Selenium not installed') +class JavascriptI18nTests(LiveServerTestCase): + urls = 'regressiontests.views.urls' + + @classmethod + def setUpClass(cls): + cls.selenium = firefox.WebDriver() + super(JavascriptI18nTests, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + cls.selenium.quit() + super(JavascriptI18nTests, cls).tearDownClass() + + @override_settings(LANGUAGE_CODE='de') + def test_javascript_gettext(self): + extended_apps = list(settings.INSTALLED_APPS) + ['regressiontests.views'] + with self.settings(INSTALLED_APPS=extended_apps): + self.selenium.get('%s%s' % (self.live_server_url, '/jsi18n_template/')) + + elem = self.selenium.find_element_by_id("gettext") + self.assertEqual(elem.text, u"Entfernen") + elem = self.selenium.find_element_by_id("ngettext_sing") + self.assertEqual(elem.text, "1 Element") + elem = self.selenium.find_element_by_id("ngettext_plur") + self.assertEqual(elem.text, "455 Elemente") + elem = self.selenium.find_element_by_id("pgettext") + self.assertEqual(elem.text, "Kann") + elem = self.selenium.find_element_by_id("npgettext_sing") + self.assertEqual(elem.text, "1 Resultat") + elem = self.selenium.find_element_by_id("npgettext_plur") + self.assertEqual(elem.text, "455 Resultate") + + def test_escaping(self): + extended_apps = list(settings.INSTALLED_APPS) + ['regressiontests.views'] + with self.settings(INSTALLED_APPS=extended_apps): + response = self.client.get('%s%s' % (self.live_server_url, '/jsi18n_admin/')) + self.assertContains(response, '\\x04') diff --git a/tests/regressiontests/views/urls.py b/tests/regressiontests/views/urls.py index 90d2382f71..ae3b9c0a9e 100644 --- a/tests/regressiontests/views/urls.py +++ b/tests/regressiontests/views/urls.py @@ -32,6 +32,11 @@ js_info_dict_multi_packages2 = { 'packages': ('regressiontests.views.app3', 'regressiontests.views.app4'), } +js_info_dict_admin = { + 'domain': 'djangojs', + 'packages': ('django.contrib.admin', 'regressiontests.views'), +} + urlpatterns = patterns('', (r'^$', views.index_page), @@ -51,6 +56,8 @@ urlpatterns = patterns('', (r'^jsi18n_english_translation/$', 'django.views.i18n.javascript_catalog', js_info_dict_english_translation), (r'^jsi18n_multi_packages1/$', 'django.views.i18n.javascript_catalog', js_info_dict_multi_packages1), (r'^jsi18n_multi_packages2/$', 'django.views.i18n.javascript_catalog', js_info_dict_multi_packages2), + (r'^jsi18n_admin/$', 'django.views.i18n.javascript_catalog', js_info_dict_admin), + (r'^jsi18n_template/$', views.jsi18n), # Static views (r'^site_media/(?P.*)$', 'django.views.static.serve', {'document_root': media_dir}), diff --git a/tests/regressiontests/views/views.py b/tests/regressiontests/views/views.py index 2836d1bdde..ed9d61144a 100644 --- a/tests/regressiontests/views/views.py +++ b/tests/regressiontests/views/views.py @@ -51,6 +51,9 @@ def template_exception(request, n): return render_to_response('debug/template_exception.html', {'arg': except_args[int(n)]}) +def jsi18n(request): + return render_to_response('jsi18n.html') + # Some views to exercise the shortcuts def render_to_response_view(request):