Enable i18n support in URL configuration.

This supports i18n using all of the following:
- I18N urls
- Session
- Cookie
- HTTP header
This commit is contained in:
Umair Khan
2016-05-19 08:33:30 -07:00
committed by Tim Abbott
parent 94b2af76f9
commit f9bbc5d6ff
6 changed files with 116 additions and 13 deletions

View File

@@ -1,8 +1,9 @@
from django.conf.urls import patterns, url from django.conf.urls import patterns, url
urlpatterns = patterns('analytics.views', i18n_urlpatterns = [
url(r'^activity$', 'get_activity'), url(r'^activity$', 'analytics.views.get_activity'),
url(r'^realm_activity/(?P<realm>[\S]+)/$', 'get_realm_activity'), url(r'^realm_activity/(?P<realm>[\S]+)/$', 'analytics.views.get_realm_activity'),
url(r'^user_activity/(?P<email>[\S]+)/$', 'get_user_activity'), url(r'^user_activity/(?P<email>[\S]+)/$', 'analytics.views.get_user_activity'),
) ]
urlpatterns = patterns('', *i18n_urlpatterns)

View File

@@ -1,7 +1,7 @@
from django.conf.urls import patterns, url from django.conf.urls import patterns, url
from django.views.generic import TemplateView, RedirectView from django.views.generic import TemplateView, RedirectView
urlpatterns = patterns('', i18n_urlpatterns = [
# Zephyr/MIT # Zephyr/MIT
url(r'^zephyr/$', TemplateView.as_view(template_name='corporate/zephyr.html')), url(r'^zephyr/$', TemplateView.as_view(template_name='corporate/zephyr.html')),
url(r'^mit/$', TemplateView.as_view(template_name='corporate/mit.html')), url(r'^mit/$', TemplateView.as_view(template_name='corporate/mit.html')),
@@ -11,5 +11,6 @@ urlpatterns = patterns('',
url(r'^terms/$', TemplateView.as_view(template_name='corporate/terms.html')), url(r'^terms/$', TemplateView.as_view(template_name='corporate/terms.html')),
url(r'^terms-enterprise/$', TemplateView.as_view(template_name='corporate/terms-enterprise.html')), url(r'^terms-enterprise/$', TemplateView.as_view(template_name='corporate/terms-enterprise.html')),
url(r'^privacy/$', TemplateView.as_view(template_name='corporate/privacy.html')), url(r'^privacy/$', TemplateView.as_view(template_name='corporate/privacy.html')),
]
) urlpatterns = patterns('', *i18n_urlpatterns)

View File

@@ -63,3 +63,34 @@ You can instead use:
[Handlebars]: http://handlebarsjs.com/ [Handlebars]: http://handlebarsjs.com/
[trans]: http://jinja.pocoo.org/docs/dev/templates/#i18n [trans]: http://jinja.pocoo.org/docs/dev/templates/#i18n
[blocktrans]: https://docs.djangoproject.com/en/1.8/topics/i18n/translation/#std:templatetag-blocktrans [blocktrans]: https://docs.djangoproject.com/en/1.8/topics/i18n/translation/#std:templatetag-blocktrans
## Testing Translations
First of all make sure that you have compiled the translation strings
using `python manage.py compilemessages`.
Django figures out the effective language by going through the
following steps:
1. It looks for the language code in the url.
2. It loooks for the LANGUGE_SESSION_KEY key in the current user's
session.
3. It looks for the cookie named 'django_language'. You can set a
different name through LANGUAGE_COOKIE_NAME setting.
4. It looks for the `Accept-Language` HTTP header in the HTTP request.
Normally your browser will take care of this.
The easiest way to test translations is through the i18n urls e.g. if
you have German translations available you can access the German
version of a page by going to `/de/path_to_page`.
To test translations using other methods you will need an HTTP client
library like `requests`, `cURL` or `urllib`. Here is a sample code to
test `Accept-Language` header using requests:
```
import requests
headers = {"Accept-Language": "de"}
response = requests.get("http://localhost:9991/login/", headers=headers)
print(response.content)
```

57
zerver/tests/test_i18n.py Normal file
View File

@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from django.test import TestCase
from django.conf import settings
from http.cookies import SimpleCookie
class TranslationTestCase(TestCase):
"""
Tranlations strings should change with locale. URLs should be locale
aware.
"""
def fetch(self, method, url, expected_status, **kwargs):
# e.g. self.client.post(url) if method is "post"
response = getattr(self.client, method)(url, **kwargs)
self.assertEqual(response.status_code, expected_status,
msg="Expected %d, received %d for %s to %s" % (
expected_status, response.status_code, method, url))
return response
def test_accept_language_header(self):
languages = [('en', 'Register'),
('de', 'Registrieren'),
('sr', 'Региструј се'),
('zh-cn', '注册'),
]
for lang, word in languages:
response = self.fetch('get', '/integrations/', 200,
HTTP_ACCEPT_LANGUAGE=lang)
self.assertTrue(word in response.content)
def test_cookie(self):
languages = [('en', 'Register'),
('de', 'Registrieren'),
('sr', 'Региструј се'),
('zh-cn', '注册'),
]
for lang, word in languages:
self.client.cookies = SimpleCookie({settings.LANGUAGE_COOKIE_NAME: lang})
response = self.fetch('get', '/integrations/', 200)
self.assertTrue(word in response.content)
def test_i18n_urls(self):
languages = [('en', 'Register'),
('de', 'Registrieren'),
('sr', 'Региструј се'),
('zh-cn', '注册'),
]
for lang, word in languages:
response = self.fetch('get', '/{}/integrations/'.format(lang), 200)
self.assertTrue(word in response.content)

View File

@@ -1,13 +1,14 @@
from django.conf.urls import patterns, url, include from django.conf.urls import patterns, url, include
urlpatterns = patterns('zilencer.views', i18n_urlpatterns = [
# SSO dispatch page for desktop app with SSO # SSO dispatch page for desktop app with SSO
# Allows the user to enter their email address only, # Allows the user to enter their email address only,
# and then redirects the user to the proper deployment # and then redirects the user to the proper deployment
# SSO-login page # SSO-login page
url(r'^accounts/deployment_dispatch$', 'account_deployment_dispatch', url(r'^accounts/deployment_dispatch$',
'zilencer.views.account_deployment_dispatch',
{'template_name': 'zerver/login.html'}), {'template_name': 'zerver/login.html'}),
) ]
# Zilencer views following the REST API style # Zilencer views following the REST API style
v1_api_and_json_patterns = patterns('zilencer.views', v1_api_and_json_patterns = patterns('zilencer.views',
@@ -18,7 +19,8 @@ v1_api_and_json_patterns = patterns('zilencer.views',
url('^endpoints$', 'lookup_endpoints_for_user'), url('^endpoints$', 'lookup_endpoints_for_user'),
) )
urlpatterns += patterns('', urlpatterns = patterns('',
url(r'^api/v1/', include(v1_api_and_json_patterns)), url(r'^api/v1/', include(v1_api_and_json_patterns)),
url(r'^json/', include(v1_api_and_json_patterns)), url(r'^json/', include(v1_api_and_json_patterns)),
*i18n_urlpatterns
) )

View File

@@ -1,6 +1,8 @@
from django.conf import settings from django.conf import settings
from django.conf.urls import patterns, url, include from django.conf.urls import patterns, url, include
from django.conf.urls.i18n import i18n_patterns
from django.views.generic import TemplateView, RedirectView from django.views.generic import TemplateView, RedirectView
from django.utils.module_loading import import_string
import os.path import os.path
import zerver.forms import zerver.forms
@@ -13,7 +15,7 @@ import zerver.forms
# #
# - Likewise for the local dev server in tools/run-dev.py. # - Likewise for the local dev server in tools/run-dev.py.
urlpatterns = patterns('', i18n_urls = [
url(r'^$', 'zerver.views.home'), url(r'^$', 'zerver.views.home'),
# We have a desktop-specific landing page in case we change our / to not log in in the future. We don't # We have a desktop-specific landing page in case we change our / to not log in in the future. We don't
# want to require a new desktop app build for everyone in that case # want to require a new desktop app build for everyone in that case
@@ -86,7 +88,10 @@ urlpatterns = patterns('',
name='landing-page'), name='landing-page'),
url(r'^new-user/$', RedirectView.as_view(url='/hello')), url(r'^new-user/$', RedirectView.as_view(url='/hello')),
url(r'^features/$', TemplateView.as_view(template_name='zerver/features.html')), url(r'^features/$', TemplateView.as_view(template_name='zerver/features.html')),
) ]
urlpatterns = []
urlpatterns += patterns('', *i18n_urls)
# These are used for voyager development. On a real voyager instance, # These are used for voyager development. On a real voyager instance,
# these files would be served by nginx. # these files would be served by nginx.
@@ -271,6 +276,7 @@ for app_name in settings.EXTRA_INSTALLED_APPS:
if os.path.exists(os.path.join(app_dir, 'urls.py')): if os.path.exists(os.path.join(app_dir, 'urls.py')):
urlpatterns += patterns('', url(r'^', include('%s.urls' % (app_name,))), urlpatterns += patterns('', url(r'^', include('%s.urls' % (app_name,))),
) )
i18n_urls += import_string("{}.urls.i18n_urlpatterns".format(app_name))
urlpatterns += patterns('zerver.tornadoviews', urlpatterns += patterns('zerver.tornadoviews',
# Tornado views # Tornado views
@@ -294,3 +300,8 @@ if settings.DEVELOPMENT:
urlpatterns += patterns('', urlpatterns += patterns('',
url(r'^static/(?P<path>.*)$', 'django.views.static.serve', url(r'^static/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': static_root})) {'document_root': static_root}))
# The sequence is important; if i18n urls don't come first then
# reverse url mapping points to i18n urls which causes the frontend
# tests to fail
urlpatterns = i18n_patterns(*i18n_urls) + urlpatterns