Kaydet (Commit) 6bb2175e authored tarafından Moritz Sichert's avatar Moritz Sichert Kaydeden (comit) Tim Graham

Fixed #22106 -- Allowed using more than one instance of javascript_catalog per project.

üst 556eb677
...@@ -94,87 +94,87 @@ js_catalog_template = r""" ...@@ -94,87 +94,87 @@ js_catalog_template = r"""
django.pluralidx = function (count) { return (count == 1) ? 0 : 1; }; django.pluralidx = function (count) { return (count == 1) ? 0 : 1; };
{% endif %} {% endif %}
{% if catalog_str %}
/* gettext library */ /* gettext library */
django.catalog = {{ catalog_str }}; django.catalog = django.catalog || {};
{% if catalog_str %}
django.gettext = function (msgid) { var newcatalog = {{ catalog_str }};
var value = django.catalog[msgid]; for (var key in newcatalog) {
if (typeof(value) == 'undefined') { django.catalog[key] = newcatalog[key];
return msgid; }
} else {
return (typeof(value) == 'string') ? value : value[0];
}
};
django.ngettext = function (singular, plural, count) {
var value = django.catalog[singular];
if (typeof(value) == 'undefined') {
return (count == 1) ? singular : plural;
} else {
return value[django.pluralidx(count)];
}
};
django.gettext_noop = function (msgid) { return msgid; };
django.pgettext = function (context, msgid) {
var value = django.gettext(context + '\x04' + msgid);
if (value.indexOf('\x04') != -1) {
value = msgid;
}
return value;
};
django.npgettext = function (context, singular, plural, count) {
var value = django.ngettext(context + '\x04' + singular, context + '\x04' + plural, count);
if (value.indexOf('\x04') != -1) {
value = django.ngettext(singular, plural, count);
}
return value;
};
{% else %}
/* gettext identity library */
django.gettext = function (msgid) { return msgid; };
django.ngettext = function (singular, plural, count) { return (count == 1) ? singular : plural; };
django.gettext_noop = function (msgid) { return msgid; };
django.pgettext = function (context, msgid) { return msgid; };
django.npgettext = function (context, singular, plural, count) { return (count == 1) ? singular : plural; };
{% endif %} {% endif %}
django.interpolate = function (fmt, obj, named) { if (!django.jsi18n_initialized) {
if (named) { django.gettext = function (msgid) {
return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])}); var value = django.catalog[msgid];
} else { if (typeof(value) == 'undefined') {
return fmt.replace(/%s/g, function(match){return String(obj.shift())}); return msgid;
} } else {
}; return (typeof(value) == 'string') ? value : value[0];
}
};
/* formatting library */
django.ngettext = function (singular, plural, count) {
django.formats = {{ formats_str }}; var value = django.catalog[singular];
if (typeof(value) == 'undefined') {
django.get_format = function (format_type) { return (count == 1) ? singular : plural;
var value = django.formats[format_type]; } else {
if (typeof(value) == 'undefined') { return value[django.pluralidx(count)];
return format_type; }
} else { };
django.gettext_noop = function (msgid) { return msgid; };
django.pgettext = function (context, msgid) {
var value = django.gettext(context + '\x04' + msgid);
if (value.indexOf('\x04') != -1) {
value = msgid;
}
return value; return value;
} };
};
/* add to global namespace */ django.npgettext = function (context, singular, plural, count) {
globals.pluralidx = django.pluralidx; var value = django.ngettext(context + '\x04' + singular, context + '\x04' + plural, count);
globals.gettext = django.gettext; if (value.indexOf('\x04') != -1) {
globals.ngettext = django.ngettext; value = django.ngettext(singular, plural, count);
globals.gettext_noop = django.gettext_noop; }
globals.pgettext = django.pgettext; return value;
globals.npgettext = django.npgettext; };
globals.interpolate = django.interpolate;
globals.get_format = django.get_format; django.interpolate = function (fmt, obj, named) {
if (named) {
return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
} else {
return fmt.replace(/%s/g, function(match){return String(obj.shift())});
}
};
/* formatting library */
django.formats = {{ formats_str }};
django.get_format = function (format_type) {
var value = django.formats[format_type];
if (typeof(value) == 'undefined') {
return format_type;
} else {
return value;
}
};
/* add to global namespace */
globals.pluralidx = django.pluralidx;
globals.gettext = django.gettext;
globals.ngettext = django.ngettext;
globals.gettext_noop = django.gettext_noop;
globals.pgettext = django.pgettext;
globals.npgettext = django.npgettext;
globals.interpolate = django.interpolate;
globals.get_format = django.get_format;
django.jsi18n_initialized = true;
}
}(this)); }(this));
{% endautoescape %} {% endautoescape %}
......
...@@ -143,6 +143,9 @@ Internationalization ...@@ -143,6 +143,9 @@ Internationalization
* The :func:`django.views.i18n.set_language` view now properly redirects to * The :func:`django.views.i18n.set_language` view now properly redirects to
:ref:`translated URLs <url-internationalization>`, when available. :ref:`translated URLs <url-internationalization>`, when available.
* The :func:`django.views.i18n.javascript_catalog` view now works correctly
if used multiple times with different configurations on the same page.
Management Commands Management Commands
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
......
...@@ -952,6 +952,31 @@ different apps and this changes often and you don't want to pull in one big ...@@ -952,6 +952,31 @@ different apps and this changes often and you don't want to pull in one big
catalog file. As a security measure, these values can only be either catalog file. As a security measure, these values can only be either
``django.conf`` or any package from the :setting:`INSTALLED_APPS` setting. ``django.conf`` or any package from the :setting:`INSTALLED_APPS` setting.
You can also split the catalogs in multiple URLs and load them as you need in
your sites::
js_info_dict_app = {
'packages': ('your.app.package',),
}
js_info_dict_other_app = {
'packages': ('your.other.app.package',),
}
urlpatterns = [
url(r'^jsi18n/app/$', javascript_catalog, js_info_dict_app),
url(r'^jsi18n/other_app/$', javascript_catalog, js_info_dict_other_app),
]
If you use more than one ``javascript_catalog`` on a site and some of them
define the same strings, the strings in the catalog that was loaded last take
precedence.
.. versionchanged:: 1.9
Before Django 1.9, the catalogs completely overwrote each other and you
could only use one at a time.
The JavaScript translations found in the paths listed in the The JavaScript translations found in the paths listed in the
:setting:`LOCALE_PATHS` setting are also always included. To keep consistency :setting:`LOCALE_PATHS` setting are also always included. To keep consistency
with the translations lookup order algorithm used for Python and templates, the with the translations lookup order algorithm used for Python and templates, the
......
<html>
<head>
<script type="text/javascript" src="/jsi18n/app1/"></script>
<script type="text/javascript" src="/jsi18n/app2/"></script>
<body>
<p id="app1string">
<script type="text/javascript">
document.write(gettext('this app1 string is to be translated'))
</script>
</p>
<p id="app2string">
<script type="text/javascript">
document.write(gettext('this app2 string is to be translated'))
</script>
</p>
</body>
</html>
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
from __future__ import unicode_literals
import gettext import gettext
import json import json
import os import os
...@@ -100,7 +102,7 @@ class I18NTests(TestCase): ...@@ -100,7 +102,7 @@ class I18NTests(TestCase):
self.assertContains(response, json.dumps(trans_txt), 1) self.assertContains(response, json.dumps(trans_txt), 1)
if lang_code == 'fr': if lang_code == 'fr':
# Message with context (msgctxt) # Message with context (msgctxt)
self.assertContains(response, r'"month name\u0004May": "mai"', 1) self.assertContains(response, '"month name\\u0004May": "mai"', 1)
@override_settings(ROOT_URLCONF='view_tests.urls') @override_settings(ROOT_URLCONF='view_tests.urls')
...@@ -270,6 +272,16 @@ class JavascriptI18nTests(LiveServerTestCase): ...@@ -270,6 +272,16 @@ class JavascriptI18nTests(LiveServerTestCase):
elem = self.selenium.find_element_by_id("npgettext_plur") elem = self.selenium.find_element_by_id("npgettext_plur")
self.assertEqual(elem.text, "455 Resultate") self.assertEqual(elem.text, "455 Resultate")
@modify_settings(INSTALLED_APPS={'append': ['view_tests.app1', 'view_tests.app2']})
@override_settings(LANGUAGE_CODE='fr')
def test_multiple_catalogs(self):
self.selenium.get('%s%s' % (self.live_server_url, '/jsi18n_multi_catalogs/'))
elem = self.selenium.find_element_by_id('app1string')
self.assertEqual(elem.text, 'il faut traduire cette chaîne de caractères de app1')
elem = self.selenium.find_element_by_id('app2string')
self.assertEqual(elem.text, 'il faut traduire cette chaîne de caractères de app2')
class JavascriptI18nChromeTests(JavascriptI18nTests): class JavascriptI18nChromeTests(JavascriptI18nTests):
webdriver_class = 'selenium.webdriver.chrome.webdriver.WebDriver' webdriver_class = 'selenium.webdriver.chrome.webdriver.WebDriver'
......
...@@ -38,6 +38,16 @@ js_info_dict_admin = { ...@@ -38,6 +38,16 @@ js_info_dict_admin = {
'packages': ('django.contrib.admin', 'view_tests'), 'packages': ('django.contrib.admin', 'view_tests'),
} }
js_info_dict_app1 = {
'domain': 'djangojs',
'packages': ('view_tests.app1',),
}
js_info_dict_app2 = {
'domain': 'djangojs',
'packages': ('view_tests.app2',),
}
js_info_dict_app5 = { js_info_dict_app5 = {
'domain': 'djangojs', 'domain': 'djangojs',
'packages': ('view_tests.app5',), 'packages': ('view_tests.app5',),
...@@ -64,12 +74,15 @@ urlpatterns = [ ...@@ -64,12 +74,15 @@ urlpatterns = [
# i18n views # i18n views
url(r'^i18n/', include('django.conf.urls.i18n')), url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^jsi18n/$', i18n.javascript_catalog, js_info_dict), url(r'^jsi18n/$', i18n.javascript_catalog, js_info_dict),
url(r'^jsi18n/app1/$', i18n.javascript_catalog, js_info_dict_app1),
url(r'^jsi18n/app2/$', i18n.javascript_catalog, js_info_dict_app2),
url(r'^jsi18n/app5/$', i18n.javascript_catalog, js_info_dict_app5), url(r'^jsi18n/app5/$', i18n.javascript_catalog, js_info_dict_app5),
url(r'^jsi18n_english_translation/$', i18n.javascript_catalog, js_info_dict_english_translation), url(r'^jsi18n_english_translation/$', i18n.javascript_catalog, js_info_dict_english_translation),
url(r'^jsi18n_multi_packages1/$', i18n.javascript_catalog, js_info_dict_multi_packages1), url(r'^jsi18n_multi_packages1/$', i18n.javascript_catalog, js_info_dict_multi_packages1),
url(r'^jsi18n_multi_packages2/$', i18n.javascript_catalog, js_info_dict_multi_packages2), url(r'^jsi18n_multi_packages2/$', i18n.javascript_catalog, js_info_dict_multi_packages2),
url(r'^jsi18n_admin/$', i18n.javascript_catalog, js_info_dict_admin), url(r'^jsi18n_admin/$', i18n.javascript_catalog, js_info_dict_admin),
url(r'^jsi18n_template/$', views.jsi18n), url(r'^jsi18n_template/$', views.jsi18n),
url(r'^jsi18n_multi_catalogs/$', views.jsi18n_multi_catalogs),
# Static views # Static views
url(r'^site_media/(?P<path>.*)$', static.serve, {'document_root': media_dir}), url(r'^site_media/(?P<path>.*)$', static.serve, {'document_root': media_dir}),
......
...@@ -82,6 +82,10 @@ def jsi18n(request): ...@@ -82,6 +82,10 @@ def jsi18n(request):
return render_to_response('jsi18n.html') return render_to_response('jsi18n.html')
def jsi18n_multi_catalogs(request):
return render_to_response('jsi18n-multi-catalogs.html')
def raises_template_does_not_exist(request, path='i_dont_exist.html'): def raises_template_does_not_exist(request, path='i_dont_exist.html'):
# We need to inspect the HTML generated by the fancy 500 debug view but # We need to inspect the HTML generated by the fancy 500 debug view but
# the test client ignores it, so we send it explicitly. # the test client ignores it, so we send it explicitly.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment