Fixed #22404 -- Added a view that exposes i18n catalog as a JSON
Added django.views.i18n.json_catalog() view, which returns a JSON response containing translations, formats, and a plural expression for the specified language.
This commit is contained in:
parent
e8cd65f829
commit
244404227e
|
@ -17,6 +17,9 @@ from django.utils.translation import (
|
|||
LANGUAGE_SESSION_KEY, check_for_language, get_language, to_locale,
|
||||
)
|
||||
|
||||
DEFAULT_PACKAGES = ['django.conf']
|
||||
LANGUAGE_QUERY_PARAMETER = 'language'
|
||||
|
||||
|
||||
def set_language(request):
|
||||
"""
|
||||
|
@ -36,7 +39,7 @@ def set_language(request):
|
|||
next = '/'
|
||||
response = http.HttpResponseRedirect(next)
|
||||
if request.method == 'POST':
|
||||
lang_code = request.POST.get('language')
|
||||
lang_code = request.POST.get(LANGUAGE_QUERY_PARAMETER)
|
||||
if lang_code and check_for_language(lang_code):
|
||||
next_trans = translate_url(next, lang_code)
|
||||
if next_trans != next:
|
||||
|
@ -199,7 +202,7 @@ def get_javascript_catalog(locale, domain, packages):
|
|||
default_locale = to_locale(settings.LANGUAGE_CODE)
|
||||
app_configs = apps.get_app_configs()
|
||||
allowable_packages = set(app_config.name for app_config in app_configs)
|
||||
allowable_packages.add('django.conf')
|
||||
allowable_packages.update(DEFAULT_PACKAGES)
|
||||
packages = [p for p in packages if p in allowable_packages]
|
||||
t = {}
|
||||
paths = []
|
||||
|
@ -284,6 +287,21 @@ def get_javascript_catalog(locale, domain, packages):
|
|||
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):
|
||||
"""
|
||||
Returns "identity" versions of the JavaScript i18n functions -- i.e.,
|
||||
|
@ -305,16 +323,35 @@ def javascript_catalog(request, domain='djangojs', packages=None):
|
|||
go to the djangojs domain. But this might be needed if you
|
||||
deliver your JavaScript source from Django templates.
|
||||
"""
|
||||
locale = to_locale(get_language())
|
||||
|
||||
if request.GET and 'language' in request.GET:
|
||||
if check_for_language(request.GET['language']):
|
||||
locale = to_locale(request.GET['language'])
|
||||
|
||||
if packages is None:
|
||||
packages = ['django.conf']
|
||||
if isinstance(packages, six.string_types):
|
||||
packages = packages.split('+')
|
||||
|
||||
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.
|
||||
}
|
||||
"""
|
||||
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)
|
||||
|
|
|
@ -357,6 +357,10 @@ Internationalization
|
|||
for languages which can be written in different scripts, for example Latin
|
||||
and Cyrillic (e.g. ``be@latin``).
|
||||
|
||||
* Added the :func:`django.views.i18n.json_catalog` view to help build a custom
|
||||
client-side i18n library upon Django translations. It returns a JSON object
|
||||
containing a translations catalog, formatting settings, and a plural rule.
|
||||
|
||||
* Added the ``name_translated`` attribute to the object returned by the
|
||||
:ttag:`get_language_info` template tag. Also added a corresponding template
|
||||
filter: :tfilter:`language_name_translated`.
|
||||
|
|
|
@ -1213,6 +1213,52 @@ Additionally, if there are complex rules around pluralization, the catalog view
|
|||
will render a conditional expression. This will evaluate to either a ``true``
|
||||
(should pluralize) or ``false`` (should **not** pluralize) value.
|
||||
|
||||
The ``json_catalog`` view
|
||||
-------------------------
|
||||
|
||||
.. versionadded:: 1.9
|
||||
|
||||
.. function:: json_catalog(request, domain='djangojs', packages=None)
|
||||
|
||||
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:: json
|
||||
|
||||
{
|
||||
"catalog": {
|
||||
# Translations catalog
|
||||
},
|
||||
"formats": {
|
||||
# Language formats for date, time, etc.
|
||||
},
|
||||
"plural": "..." # Expression for plural forms, or null.
|
||||
}
|
||||
|
||||
Note on performance
|
||||
-------------------
|
||||
|
||||
|
|
|
@ -105,6 +105,20 @@ class I18NTests(TestCase):
|
|||
# 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('/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)')
|
||||
|
||||
|
||||
@override_settings(ROOT_URLCONF='view_tests.urls')
|
||||
class JsI18NTests(SimpleTestCase):
|
||||
|
@ -127,6 +141,21 @@ class JsI18NTests(SimpleTestCase):
|
|||
response = self.client.get('/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('/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
|
||||
|
|
|
@ -84,6 +84,7 @@ urlpatterns = [
|
|||
url(r'^jsi18n_admin/$', i18n.javascript_catalog, js_info_dict_admin),
|
||||
url(r'^jsi18n_template/$', views.jsi18n),
|
||||
url(r'^jsi18n_multi_catalogs/$', views.jsi18n_multi_catalogs),
|
||||
url(r'^jsoni18n/$', i18n.json_catalog, js_info_dict),
|
||||
|
||||
# Static views
|
||||
url(r'^site_media/(?P<path>.*)$', static.serve, {'document_root': media_dir}),
|
||||
|
|
Loading…
Reference in New Issue