Refs #19567 -- Removed deprecated javascript_catalog() and json_catalog() views.
This commit is contained in:
parent
933dc62742
commit
2b20e4148f
@ -1,8 +1,6 @@
|
|||||||
import importlib
|
|
||||||
import itertools
|
import itertools
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import warnings
|
|
||||||
|
|
||||||
from django import http
|
from django import http
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
@ -10,18 +8,15 @@ from django.conf import settings
|
|||||||
from django.template import Context, Engine
|
from django.template import Context, Engine
|
||||||
from django.urls import translate_url
|
from django.urls import translate_url
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils._os import upath
|
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.formats import get_format
|
from django.utils.formats import get_format
|
||||||
from django.utils.http import is_safe_url, urlunquote
|
from django.utils.http import is_safe_url, urlunquote
|
||||||
from django.utils.translation import (
|
from django.utils.translation import (
|
||||||
LANGUAGE_SESSION_KEY, check_for_language, get_language, to_locale,
|
LANGUAGE_SESSION_KEY, check_for_language, get_language,
|
||||||
)
|
)
|
||||||
from django.utils.translation.trans_real import DjangoTranslation
|
from django.utils.translation.trans_real import DjangoTranslation
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
|
|
||||||
DEFAULT_PACKAGES = ['django.conf']
|
|
||||||
LANGUAGE_QUERY_PARAMETER = 'language'
|
LANGUAGE_QUERY_PARAMETER = 'language'
|
||||||
|
|
||||||
|
|
||||||
@ -210,69 +205,6 @@ def render_javascript_catalog(catalog=None, plural=None):
|
|||||||
return http.HttpResponse(template.render(context), 'text/javascript')
|
return http.HttpResponse(template.render(context), 'text/javascript')
|
||||||
|
|
||||||
|
|
||||||
def get_javascript_catalog(locale, domain, packages):
|
|
||||||
app_configs = apps.get_app_configs()
|
|
||||||
allowable_packages = set(app_config.name for app_config in app_configs)
|
|
||||||
allowable_packages.update(DEFAULT_PACKAGES)
|
|
||||||
packages = [p for p in packages if p in allowable_packages]
|
|
||||||
paths = []
|
|
||||||
# paths of requested packages
|
|
||||||
for package in packages:
|
|
||||||
p = importlib.import_module(package)
|
|
||||||
path = os.path.join(os.path.dirname(upath(p.__file__)), 'locale')
|
|
||||||
paths.append(path)
|
|
||||||
|
|
||||||
trans = DjangoTranslation(locale, domain=domain, localedirs=paths)
|
|
||||||
trans_cat = trans._catalog
|
|
||||||
|
|
||||||
plural = None
|
|
||||||
if '' in trans_cat:
|
|
||||||
for line in trans_cat[''].split('\n'):
|
|
||||||
if line.startswith('Plural-Forms:'):
|
|
||||||
plural = line.split(':', 1)[1].strip()
|
|
||||||
if plural is not None:
|
|
||||||
# this should actually be a compiled function of a typical plural-form:
|
|
||||||
# Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 :
|
|
||||||
# n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
|
|
||||||
plural = [el.strip() for el in plural.split(';') if el.strip().startswith('plural=')][0].split('=', 1)[1]
|
|
||||||
|
|
||||||
pdict = {}
|
|
||||||
maxcnts = {}
|
|
||||||
catalog = {}
|
|
||||||
trans_fallback_cat = trans._fallback._catalog if trans._fallback else {}
|
|
||||||
for key, value in itertools.chain(six.iteritems(trans_cat), six.iteritems(trans_fallback_cat)):
|
|
||||||
if key == '' or key in catalog:
|
|
||||||
continue
|
|
||||||
if isinstance(key, six.string_types):
|
|
||||||
catalog[key] = value
|
|
||||||
elif isinstance(key, tuple):
|
|
||||||
msgid = key[0]
|
|
||||||
cnt = key[1]
|
|
||||||
maxcnts[msgid] = max(cnt, maxcnts.get(msgid, 0))
|
|
||||||
pdict.setdefault(msgid, {})[cnt] = value
|
|
||||||
else:
|
|
||||||
raise TypeError(key)
|
|
||||||
for k, v in pdict.items():
|
|
||||||
catalog[k] = [v.get(i, '') for i in range(maxcnts[k] + 1)]
|
|
||||||
|
|
||||||
return catalog, plural
|
|
||||||
|
|
||||||
|
|
||||||
def _get_locale(request):
|
|
||||||
language = request.GET.get(LANGUAGE_QUERY_PARAMETER)
|
|
||||||
if not (language and check_for_language(language)):
|
|
||||||
language = get_language()
|
|
||||||
return to_locale(language)
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_packages(packages):
|
|
||||||
if packages is None:
|
|
||||||
packages = list(DEFAULT_PACKAGES)
|
|
||||||
elif isinstance(packages, six.string_types):
|
|
||||||
packages = packages.split('+')
|
|
||||||
return packages
|
|
||||||
|
|
||||||
|
|
||||||
def null_javascript_catalog(request, domain=None, packages=None):
|
def null_javascript_catalog(request, domain=None, packages=None):
|
||||||
"""
|
"""
|
||||||
Returns "identity" versions of the JavaScript i18n functions -- i.e.,
|
Returns "identity" versions of the JavaScript i18n functions -- i.e.,
|
||||||
@ -281,61 +213,6 @@ def null_javascript_catalog(request, domain=None, packages=None):
|
|||||||
return render_javascript_catalog()
|
return render_javascript_catalog()
|
||||||
|
|
||||||
|
|
||||||
def javascript_catalog(request, domain='djangojs', packages=None):
|
|
||||||
"""
|
|
||||||
Returns the selected language catalog as a javascript library.
|
|
||||||
|
|
||||||
Receives the list of packages to check for translations in the
|
|
||||||
packages parameter either from an infodict or as a +-delimited
|
|
||||||
string from the request. Default is 'django.conf'.
|
|
||||||
|
|
||||||
Additionally you can override the gettext domain for this view,
|
|
||||||
but usually you don't want to do that, as JavaScript messages
|
|
||||||
go to the djangojs domain. But this might be needed if you
|
|
||||||
deliver your JavaScript source from Django templates.
|
|
||||||
"""
|
|
||||||
warnings.warn(
|
|
||||||
"The javascript_catalog() view is deprecated in favor of the "
|
|
||||||
"JavaScriptCatalog view.", RemovedInDjango20Warning, stacklevel=2
|
|
||||||
)
|
|
||||||
locale = _get_locale(request)
|
|
||||||
packages = _parse_packages(packages)
|
|
||||||
catalog, plural = get_javascript_catalog(locale, domain, packages)
|
|
||||||
return render_javascript_catalog(catalog, plural)
|
|
||||||
|
|
||||||
|
|
||||||
def json_catalog(request, domain='djangojs', packages=None):
|
|
||||||
"""
|
|
||||||
Return the selected language catalog as a JSON object.
|
|
||||||
|
|
||||||
Receives the same parameters as javascript_catalog(), but returns
|
|
||||||
a response with a JSON object of the following format:
|
|
||||||
|
|
||||||
{
|
|
||||||
"catalog": {
|
|
||||||
# Translations catalog
|
|
||||||
},
|
|
||||||
"formats": {
|
|
||||||
# Language formats for date, time, etc.
|
|
||||||
},
|
|
||||||
"plural": '...' # Expression for plural forms, or null.
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
warnings.warn(
|
|
||||||
"The json_catalog() view is deprecated in favor of the "
|
|
||||||
"JSONCatalog view.", RemovedInDjango20Warning, stacklevel=2
|
|
||||||
)
|
|
||||||
locale = _get_locale(request)
|
|
||||||
packages = _parse_packages(packages)
|
|
||||||
catalog, plural = get_javascript_catalog(locale, domain, packages)
|
|
||||||
data = {
|
|
||||||
'catalog': catalog,
|
|
||||||
'formats': get_formats(),
|
|
||||||
'plural': plural,
|
|
||||||
}
|
|
||||||
return http.JsonResponse(data)
|
|
||||||
|
|
||||||
|
|
||||||
class JavaScriptCatalog(View):
|
class JavaScriptCatalog(View):
|
||||||
"""
|
"""
|
||||||
Return the selected language catalog as a JavaScript library.
|
Return the selected language catalog as a JavaScript library.
|
||||||
|
@ -384,7 +384,7 @@ 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
|
* The ``django.views.i18n.javascript_catalog()`` view now works correctly
|
||||||
if used multiple times with different configurations on the same page.
|
if used multiple times with different configurations on the same page.
|
||||||
|
|
||||||
* The :func:`django.utils.timezone.make_aware` function gained an ``is_dst``
|
* The :func:`django.utils.timezone.make_aware` function gained an ``is_dst``
|
||||||
@ -394,7 +394,7 @@ Internationalization
|
|||||||
for languages which can be written in different scripts, for example Latin
|
for languages which can be written in different scripts, for example Latin
|
||||||
and Cyrillic (e.g. ``be@latin``).
|
and Cyrillic (e.g. ``be@latin``).
|
||||||
|
|
||||||
* Added the :func:`django.views.i18n.json_catalog` view to help build a custom
|
* Added the ``django.views.i18n.json_catalog()`` view to help build a custom
|
||||||
client-side i18n library upon Django translations. It returns a JSON object
|
client-side i18n library upon Django translations. It returns a JSON object
|
||||||
containing a translations catalog, formatting settings, and a plural rule.
|
containing a translations catalog, formatting settings, and a plural rule.
|
||||||
|
|
||||||
|
@ -366,3 +366,5 @@ these features.
|
|||||||
|
|
||||||
* The keyword arguments ``virtual_only`` in ``Field.contribute_to_class()`` and
|
* The keyword arguments ``virtual_only`` in ``Field.contribute_to_class()`` and
|
||||||
``virtual`` in ``Model._meta.add_field()`` are removed.
|
``virtual`` in ``Model._meta.add_field()`` are removed.
|
||||||
|
|
||||||
|
* The ``javascript_catalog()`` and ``json_catalog()`` views are removed.
|
||||||
|
@ -1049,88 +1049,6 @@ If you use more than one ``JavaScriptCatalog`` view on a site and some of them
|
|||||||
define the same strings, the strings in the catalog that was loaded last take
|
define the same strings, the strings in the catalog that was loaded last take
|
||||||
precedence.
|
precedence.
|
||||||
|
|
||||||
The ``javascript_catalog`` view
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
.. function:: javascript_catalog(request, domain='djangojs', packages=None)
|
|
||||||
|
|
||||||
.. deprecated:: 1.10
|
|
||||||
|
|
||||||
``javascript_catalog()`` is deprecated in favor of
|
|
||||||
:class:`JavaScriptCatalog` and will be removed in Django 2.0.
|
|
||||||
|
|
||||||
The main solution to these problems is the
|
|
||||||
:meth:`django.views.i18n.javascript_catalog` view, which sends out a JavaScript
|
|
||||||
code library with functions that mimic the ``gettext`` interface, plus an array
|
|
||||||
of translation strings. Those translation strings are taken from applications or
|
|
||||||
Django core, according to what you specify in either the ``info_dict`` or the
|
|
||||||
URL. Paths listed in :setting:`LOCALE_PATHS` are also included.
|
|
||||||
|
|
||||||
You hook it up like this::
|
|
||||||
|
|
||||||
from django.views.i18n import javascript_catalog
|
|
||||||
|
|
||||||
js_info_dict = {
|
|
||||||
'packages': ('your.app.package',),
|
|
||||||
}
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^jsi18n/$', javascript_catalog, js_info_dict, name='javascript-catalog'),
|
|
||||||
]
|
|
||||||
|
|
||||||
Each string in ``packages`` should be in Python dotted-package syntax (the
|
|
||||||
same format as the strings in :setting:`INSTALLED_APPS`) and should refer to a
|
|
||||||
package that contains a ``locale`` directory. If you specify multiple packages,
|
|
||||||
all those catalogs are merged into one catalog. This is useful if you have
|
|
||||||
JavaScript that uses strings from different applications.
|
|
||||||
|
|
||||||
The precedence of translations is such that the packages appearing later in the
|
|
||||||
``packages`` argument have higher precedence than the ones appearing at the
|
|
||||||
beginning, this is important in the case of clashing translations for the same
|
|
||||||
literal.
|
|
||||||
|
|
||||||
By default, the view uses the ``djangojs`` gettext domain. This can be
|
|
||||||
changed by altering the ``domain`` argument.
|
|
||||||
|
|
||||||
You can make the view dynamic by putting the packages into the URL pattern::
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^jsi18n/(?P<packages>\S+?)/$', javascript_catalog, name='javascript-catalog'),
|
|
||||||
]
|
|
||||||
|
|
||||||
With this, you specify the packages as a list of package names delimited by '+'
|
|
||||||
signs in the URL. This is especially useful if your pages use code from
|
|
||||||
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
|
|
||||||
``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.
|
|
||||||
|
|
||||||
The JavaScript translations found in the paths listed in the
|
|
||||||
:setting:`LOCALE_PATHS` setting are also always included. To keep consistency
|
|
||||||
with the translations lookup order algorithm used for Python and templates, the
|
|
||||||
directories listed in :setting:`LOCALE_PATHS` have the highest precedence with
|
|
||||||
the ones appearing first having higher precedence than the ones appearing
|
|
||||||
later.
|
|
||||||
|
|
||||||
Using the JavaScript translation catalog
|
Using the JavaScript translation catalog
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
@ -1326,57 +1244,6 @@ The ``JSONCatalog`` view
|
|||||||
|
|
||||||
.. JSON doesn't allow comments so highlighting as JSON won't work here.
|
.. JSON doesn't allow comments so highlighting as JSON won't work here.
|
||||||
|
|
||||||
The ``json_catalog`` view
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
.. function:: json_catalog(request, domain='djangojs', packages=None)
|
|
||||||
|
|
||||||
.. deprecated:: 1.10
|
|
||||||
|
|
||||||
``json_catalog()`` is deprecated in favor of :class:`JSONCatalog` and will
|
|
||||||
be removed in Django 2.0.
|
|
||||||
|
|
||||||
In order to use another client-side library to handle translations, you may
|
|
||||||
want to take advantage of the ``json_catalog()`` view. It's similar to
|
|
||||||
:meth:`~django.views.i18n.javascript_catalog` but returns a JSON response.
|
|
||||||
|
|
||||||
The JSON object contains i18n formatting settings (those available for
|
|
||||||
`get_format`_), a plural rule (as a ``plural`` part of a GNU gettext
|
|
||||||
``Plural-Forms`` expression), and translation strings. The translation strings
|
|
||||||
are taken from applications or Django's own translations, according to what is
|
|
||||||
specified either via ``urlpatterns`` arguments or as request parameters. Paths
|
|
||||||
listed in :setting:`LOCALE_PATHS` are also included.
|
|
||||||
|
|
||||||
The view is hooked up to your application and configured in the same fashion as
|
|
||||||
:meth:`~django.views.i18n.javascript_catalog` (namely, the ``domain`` and
|
|
||||||
``packages`` arguments behave identically)::
|
|
||||||
|
|
||||||
from django.views.i18n import json_catalog
|
|
||||||
|
|
||||||
js_info_dict = {
|
|
||||||
'packages': ('your.app.package',),
|
|
||||||
}
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^jsoni18n/$', json_catalog, js_info_dict),
|
|
||||||
]
|
|
||||||
|
|
||||||
The response format is as follows:
|
|
||||||
|
|
||||||
.. code-block:: text
|
|
||||||
|
|
||||||
{
|
|
||||||
"catalog": {
|
|
||||||
# Translations catalog
|
|
||||||
},
|
|
||||||
"formats": {
|
|
||||||
# Language formats for date, time, etc.
|
|
||||||
},
|
|
||||||
"plural": "..." # Expression for plural forms, or null.
|
|
||||||
}
|
|
||||||
|
|
||||||
.. JSON doesn't allow comments so highlighting as JSON won't work here.
|
|
||||||
|
|
||||||
Note on performance
|
Note on performance
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
@ -1,244 +0,0 @@
|
|||||||
# -*- coding:utf-8 -*-
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import gettext
|
|
||||||
import json
|
|
||||||
from os import path
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.test import (
|
|
||||||
SimpleTestCase, ignore_warnings, modify_settings, override_settings,
|
|
||||||
)
|
|
||||||
from django.test.selenium import SeleniumTestCase
|
|
||||||
from django.utils import six
|
|
||||||
from django.utils._os import upath
|
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
|
||||||
from django.utils.translation import override
|
|
||||||
|
|
||||||
from ..urls import locale_dir
|
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='view_tests.urls')
|
|
||||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
|
||||||
class JsI18NTests(SimpleTestCase):
|
|
||||||
"""
|
|
||||||
Tests deprecated django views in django/views/i18n.py
|
|
||||||
"""
|
|
||||||
def test_jsi18n(self):
|
|
||||||
"""The javascript_catalog can be deployed with language settings"""
|
|
||||||
for lang_code in ['es', 'fr', 'ru']:
|
|
||||||
with override(lang_code):
|
|
||||||
catalog = gettext.translation('djangojs', locale_dir, [lang_code])
|
|
||||||
if six.PY3:
|
|
||||||
trans_txt = catalog.gettext('this is to be translated')
|
|
||||||
else:
|
|
||||||
trans_txt = catalog.ugettext('this is to be translated')
|
|
||||||
response = self.client.get('/old_jsi18n/')
|
|
||||||
# response content must include a line like:
|
|
||||||
# "this is to be translated": <value of trans_txt Python variable>
|
|
||||||
# json.dumps() is used to be able to check unicode strings
|
|
||||||
self.assertContains(response, json.dumps(trans_txt), 1)
|
|
||||||
if lang_code == 'fr':
|
|
||||||
# Message with context (msgctxt)
|
|
||||||
self.assertContains(response, '"month name\\u0004May": "mai"', 1)
|
|
||||||
|
|
||||||
def test_jsoni18n(self):
|
|
||||||
"""
|
|
||||||
The json_catalog returns the language catalog and settings as JSON.
|
|
||||||
"""
|
|
||||||
with override('de'):
|
|
||||||
response = self.client.get('/old_jsoni18n/')
|
|
||||||
data = json.loads(response.content.decode('utf-8'))
|
|
||||||
self.assertIn('catalog', data)
|
|
||||||
self.assertIn('formats', data)
|
|
||||||
self.assertIn('plural', data)
|
|
||||||
self.assertEqual(data['catalog']['month name\x04May'], 'Mai')
|
|
||||||
self.assertIn('DATETIME_FORMAT', data['formats'])
|
|
||||||
self.assertEqual(data['plural'], '(n != 1)')
|
|
||||||
|
|
||||||
def test_jsi18n_with_missing_en_files(self):
|
|
||||||
"""
|
|
||||||
The javascript_catalog shouldn't load the fallback language in the
|
|
||||||
case that the current selected language is actually the one translated
|
|
||||||
from, and hence missing translation files completely.
|
|
||||||
|
|
||||||
This happens easily when you're translating from English to other
|
|
||||||
languages and you've set settings.LANGUAGE_CODE to some other language
|
|
||||||
than English.
|
|
||||||
"""
|
|
||||||
with self.settings(LANGUAGE_CODE='es'), override('en-us'):
|
|
||||||
response = self.client.get('/old_jsi18n/')
|
|
||||||
self.assertNotContains(response, 'esto tiene que ser traducido')
|
|
||||||
|
|
||||||
def test_jsoni18n_with_missing_en_files(self):
|
|
||||||
"""
|
|
||||||
Same as above for the json_catalog view. Here we also check for the
|
|
||||||
expected JSON format.
|
|
||||||
"""
|
|
||||||
with self.settings(LANGUAGE_CODE='es'), override('en-us'):
|
|
||||||
response = self.client.get('/old_jsoni18n/')
|
|
||||||
data = json.loads(response.content.decode('utf-8'))
|
|
||||||
self.assertIn('catalog', data)
|
|
||||||
self.assertIn('formats', data)
|
|
||||||
self.assertIn('plural', data)
|
|
||||||
self.assertEqual(data['catalog'], {})
|
|
||||||
self.assertIn('DATETIME_FORMAT', data['formats'])
|
|
||||||
self.assertIsNone(data['plural'])
|
|
||||||
|
|
||||||
def test_jsi18n_fallback_language(self):
|
|
||||||
"""
|
|
||||||
Let's make sure that the fallback language is still working properly
|
|
||||||
in cases where the selected language cannot be found.
|
|
||||||
"""
|
|
||||||
with self.settings(LANGUAGE_CODE='fr'), override('fi'):
|
|
||||||
response = self.client.get('/old_jsi18n/')
|
|
||||||
self.assertContains(response, 'il faut le traduire')
|
|
||||||
self.assertNotContains(response, "Untranslated string")
|
|
||||||
|
|
||||||
def test_i18n_fallback_language_plural(self):
|
|
||||||
"""
|
|
||||||
The fallback to a language with less plural forms maintains the real
|
|
||||||
language's number of plural forms.
|
|
||||||
"""
|
|
||||||
with self.settings(LANGUAGE_CODE='pt'), override('ru'):
|
|
||||||
response = self.client.get('/jsi18n/')
|
|
||||||
self.assertEqual(
|
|
||||||
response.context['catalog']['{count} plural3'],
|
|
||||||
['{count} plural3', '{count} plural3s', '{count} plural3 p3t']
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_i18n_english_variant(self):
|
|
||||||
with override('en-gb'):
|
|
||||||
response = self.client.get('/old_jsi18n/')
|
|
||||||
self.assertIn(
|
|
||||||
'"this color is to be translated": "this colour is to be translated"',
|
|
||||||
response.context['catalog_str']
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_i18n_language_non_english_default(self):
|
|
||||||
"""
|
|
||||||
Check if the Javascript i18n view returns an empty language catalog
|
|
||||||
if the default language is non-English, the selected language
|
|
||||||
is English and there is not 'en' translation available. See #13388,
|
|
||||||
#3594 and #13726 for more details.
|
|
||||||
"""
|
|
||||||
with self.settings(LANGUAGE_CODE='fr'), override('en-us'):
|
|
||||||
response = self.client.get('/old_jsi18n/')
|
|
||||||
self.assertNotContains(response, 'Choisir une heure')
|
|
||||||
|
|
||||||
@modify_settings(INSTALLED_APPS={'append': 'view_tests.app0'})
|
|
||||||
def test_non_english_default_english_userpref(self):
|
|
||||||
"""
|
|
||||||
Same as above with the difference that there IS an 'en' translation
|
|
||||||
available. The Javascript i18n view must return a NON empty language catalog
|
|
||||||
with the proper English translations. See #13726 for more details.
|
|
||||||
"""
|
|
||||||
with self.settings(LANGUAGE_CODE='fr'), override('en-us'):
|
|
||||||
response = self.client.get('/old_jsi18n_english_translation/')
|
|
||||||
self.assertContains(response, 'this app0 string is to be translated')
|
|
||||||
|
|
||||||
def test_i18n_language_non_english_fallback(self):
|
|
||||||
"""
|
|
||||||
Makes sure that the fallback language is still working properly
|
|
||||||
in cases where the selected language cannot be found.
|
|
||||||
"""
|
|
||||||
with self.settings(LANGUAGE_CODE='fr'), override('none'):
|
|
||||||
response = self.client.get('/old_jsi18n/')
|
|
||||||
self.assertContains(response, 'Choisir une heure')
|
|
||||||
|
|
||||||
def test_escaping(self):
|
|
||||||
# Force a language via GET otherwise the gettext functions are a noop!
|
|
||||||
response = self.client.get('/old_jsi18n_admin/?language=de')
|
|
||||||
self.assertContains(response, '\\x04')
|
|
||||||
|
|
||||||
@modify_settings(INSTALLED_APPS={'append': ['view_tests.app5']})
|
|
||||||
def test_non_BMP_char(self):
|
|
||||||
"""
|
|
||||||
Non-BMP characters should not break the javascript_catalog (#21725).
|
|
||||||
"""
|
|
||||||
with self.settings(LANGUAGE_CODE='en-us'), override('fr'):
|
|
||||||
response = self.client.get('/old_jsi18n/app5/')
|
|
||||||
self.assertContains(response, 'emoji')
|
|
||||||
self.assertContains(response, '\\ud83d\\udca9')
|
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='view_tests.urls')
|
|
||||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
|
||||||
class JsI18NTestsMultiPackage(SimpleTestCase):
|
|
||||||
"""
|
|
||||||
Tests for django views in django/views/i18n.py that need to change
|
|
||||||
settings.LANGUAGE_CODE and merge JS translation from several packages.
|
|
||||||
"""
|
|
||||||
@modify_settings(INSTALLED_APPS={'append': ['view_tests.app1', 'view_tests.app2']})
|
|
||||||
def test_i18n_language_english_default(self):
|
|
||||||
"""
|
|
||||||
Check if the JavaScript i18n view returns a complete language catalog
|
|
||||||
if the default language is en-us, the selected language has a
|
|
||||||
translation available and a catalog composed by djangojs domain
|
|
||||||
translations of multiple Python packages is requested. See #13388,
|
|
||||||
#3594 and #13514 for more details.
|
|
||||||
"""
|
|
||||||
with self.settings(LANGUAGE_CODE='en-us'), override('fr'):
|
|
||||||
response = self.client.get('/old_jsi18n_multi_packages1/')
|
|
||||||
self.assertContains(response, 'il faut traduire cette cha\\u00eene de caract\\u00e8res de app1')
|
|
||||||
|
|
||||||
@modify_settings(INSTALLED_APPS={'append': ['view_tests.app3', 'view_tests.app4']})
|
|
||||||
def test_i18n_different_non_english_languages(self):
|
|
||||||
"""
|
|
||||||
Similar to above but with neither default or requested language being
|
|
||||||
English.
|
|
||||||
"""
|
|
||||||
with self.settings(LANGUAGE_CODE='fr'), override('es-ar'):
|
|
||||||
response = self.client.get('/old_jsi18n_multi_packages2/')
|
|
||||||
self.assertContains(response, 'este texto de app3 debe ser traducido')
|
|
||||||
|
|
||||||
def test_i18n_with_locale_paths(self):
|
|
||||||
extended_locale_paths = settings.LOCALE_PATHS + [
|
|
||||||
path.join(
|
|
||||||
path.dirname(path.dirname(path.abspath(upath(__file__)))),
|
|
||||||
'app3',
|
|
||||||
'locale',
|
|
||||||
),
|
|
||||||
]
|
|
||||||
with self.settings(LANGUAGE_CODE='es-ar', LOCALE_PATHS=extended_locale_paths):
|
|
||||||
with override('es-ar'):
|
|
||||||
response = self.client.get('/old_jsi18n/')
|
|
||||||
self.assertContains(response, 'este texto de app3 debe ser traducido')
|
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='view_tests.urls')
|
|
||||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
|
||||||
class JavascriptI18nTests(SeleniumTestCase):
|
|
||||||
|
|
||||||
# The test cases use fixtures & translations from these apps.
|
|
||||||
available_apps = [
|
|
||||||
'django.contrib.admin', 'django.contrib.auth',
|
|
||||||
'django.contrib.contenttypes', 'view_tests',
|
|
||||||
]
|
|
||||||
|
|
||||||
@override_settings(LANGUAGE_CODE='de')
|
|
||||||
def test_javascript_gettext(self):
|
|
||||||
self.selenium.get('%s%s' % (self.live_server_url, '/old_jsi18n_template/'))
|
|
||||||
|
|
||||||
elem = self.selenium.find_element_by_id("gettext")
|
|
||||||
self.assertEqual(elem.text, "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")
|
|
||||||
|
|
||||||
@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, '/old_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')
|
|
@ -72,19 +72,6 @@ urlpatterns = [
|
|||||||
url(r'technical404/$', views.technical404, name="my404"),
|
url(r'technical404/$', views.technical404, name="my404"),
|
||||||
url(r'classbased404/$', views.Http404View.as_view()),
|
url(r'classbased404/$', views.Http404View.as_view()),
|
||||||
|
|
||||||
# deprecated i18n views
|
|
||||||
url(r'^old_jsi18n/$', i18n.javascript_catalog, js_info_dict),
|
|
||||||
url(r'^old_jsi18n/app1/$', i18n.javascript_catalog, js_info_dict_app1),
|
|
||||||
url(r'^old_jsi18n/app2/$', i18n.javascript_catalog, js_info_dict_app2),
|
|
||||||
url(r'^old_jsi18n/app5/$', i18n.javascript_catalog, js_info_dict_app5),
|
|
||||||
url(r'^old_jsi18n_english_translation/$', i18n.javascript_catalog, js_info_dict_english_translation),
|
|
||||||
url(r'^old_jsi18n_multi_packages1/$', i18n.javascript_catalog, js_info_dict_multi_packages1),
|
|
||||||
url(r'^old_jsi18n_multi_packages2/$', i18n.javascript_catalog, js_info_dict_multi_packages2),
|
|
||||||
url(r'^old_jsi18n_admin/$', i18n.javascript_catalog, js_info_dict_admin),
|
|
||||||
url(r'^old_jsi18n_template/$', views.old_jsi18n),
|
|
||||||
url(r'^old_jsi18n_multi_catalogs/$', views.old_jsi18n_multi_catalogs),
|
|
||||||
url(r'^old_jsoni18n/$', i18n.json_catalog, js_info_dict),
|
|
||||||
|
|
||||||
# i18n views
|
# i18n views
|
||||||
url(r'^i18n/', include('django.conf.urls.i18n')),
|
url(r'^i18n/', include('django.conf.urls.i18n')),
|
||||||
url(r'^jsi18n/$', i18n.JavaScriptCatalog.as_view(packages=['view_tests'])),
|
url(r'^jsi18n/$', i18n.JavaScriptCatalog.as_view(packages=['view_tests'])),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user