-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding middleware and tests. Removing dependency on django-localeurl.…
… Added the big list of locales (more than we support) and the subset of our supported locales.
- Loading branch information
James Socol
committed
Apr 1, 2010
1 parent
fff6989
commit d03b6f8
Showing
13 changed files
with
357 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
""" | ||
Taken from zamboni.amo.middleware. | ||
Tried to use localeurl but it choked on 'en-US' with capital letters. | ||
""" | ||
|
||
import urllib | ||
|
||
from django.http import HttpResponsePermanentRedirect | ||
from django.utils.encoding import smart_str | ||
|
||
import l10n | ||
|
||
from . import urlresolvers | ||
from sumo.helpers import urlparams | ||
|
||
|
||
class LocaleURLMiddleware(object): | ||
""" | ||
1. Search for the locale. | ||
2. Save it in the request. | ||
3. Strip them from the URL. | ||
""" | ||
|
||
def process_request(self, request): | ||
prefixer = urlresolvers.Prefixer(request) | ||
urlresolvers.set_url_prefix(prefixer) | ||
full_path = prefixer.fix(prefixer.shortened_path) | ||
|
||
if 'lang' in request.GET: | ||
# Blank out the locale so that we can set a new one. Remove lang | ||
# from the query params so we don't have an infinite loop. | ||
prefixer.locale = '' | ||
new_path = prefixer.fix(prefixer.shortened_path) | ||
query = dict((smart_str(k), request.GET[k]) for k in request.GET) | ||
query.pop('lang') | ||
return HttpResponsePermanentRedirect(urlparams(new_path, **query)) | ||
|
||
if full_path != request.path: | ||
query_string = request.META.get('QUERY_STRING', '') | ||
if query_string: | ||
full_path = '%s?%s' % (full_path, query_string) | ||
|
||
full_path = urllib.quote(full_path.encode('utf-8')) | ||
response = HttpResponsePermanentRedirect(full_path) | ||
|
||
# Vary on Accept-Language if we changed the locale | ||
old_locale = prefixer.locale | ||
new_locale, _ = prefixer.split_path(full_path) | ||
if old_locale != new_locale: | ||
response['Vary'] = 'Accept-Language' | ||
|
||
return response | ||
|
||
request.path_info = '/' + prefixer.shortened_path | ||
request.locale = prefixer.locale | ||
l10n.activate(prefixer.locale) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from django.test import Client, TestCase | ||
|
||
|
||
class TestLocaleMiddleware(TestCase): | ||
client = Client() | ||
|
||
def test_default_redirect(self): | ||
# User wants en-us, we send en-US | ||
response = self.client.get('/search', follow=True, | ||
HTTP_ACCEPT_LANGUAGE='en-us') | ||
self.assertRedirects(response, '/en-US/search', status_code=301) | ||
|
||
# User wants fr-FR, we send fr | ||
response = self.client.get('/search', follow=True, | ||
HTTP_ACCEPT_LANGUAGE='fr-fr') | ||
self.assertRedirects(response, '/fr/search', status_code=301) | ||
|
||
# User wants xx, we send en-US | ||
response = self.client.get('/search', follow=True, | ||
HTTP_ACCEPT_LANGUAGE='xx') | ||
self.assertRedirects(response, '/en-US/search', status_code=301) | ||
|
||
# User doesn't know what they want, we send en-US | ||
response = self.client.get('/search', follow=True, | ||
HTTP_ACCEPT_LANGUAGE='') | ||
self.assertRedirects(response, '/en-US/search', status_code=301) | ||
|
||
def test_specificity(self): | ||
"""Requests for /fr-FR/search should end up on /fr/search""" | ||
reponse = self.client.get('/fr-FR/search', follow=True) | ||
self.assertRedirects(reponse, '/fr/search', status_code=301) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
from django.conf import settings | ||
from django.core.urlresolvers import reverse as django_reverse | ||
from django.utils.thread_support import currentThread | ||
from django.utils.translation.trans_real import parse_accept_lang_header | ||
|
||
|
||
# Thread-local storage for URL prefixes. Access with (get|set)_url_prefix. | ||
_prefixes = {} | ||
|
||
|
||
def set_url_prefix(prefix): | ||
"""Set the ``prefix`` for the current thread.""" | ||
_prefixes[currentThread()] = prefix | ||
|
||
|
||
def get_url_prefix(): | ||
"""Get the prefix for the current thread, or None.""" | ||
return _prefixes.get(currentThread()) | ||
|
||
|
||
def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None): | ||
"""Wraps Django's reverse to prepend the correct locale.""" | ||
prefixer = get_url_prefix() | ||
|
||
if prefixer: | ||
prefix = prefix or '/' | ||
url = django_reverse(viewname, urlconf, args, kwargs, prefix) | ||
if prefixer: | ||
return prefixer.fix(url) | ||
else: | ||
return url | ||
|
||
|
||
class Prefixer(object): | ||
|
||
def __init__(self, request): | ||
self.request = request | ||
split = self.split_path(request.path_info) | ||
self.locale, self.shortened_path = split | ||
|
||
def split_path(self, path_): | ||
""" | ||
Split the requested path into (locale, path). | ||
locale will be empty if it isn't found. | ||
""" | ||
path = path_.lstrip('/') | ||
|
||
# Use partitition instead of split since it always returns 3 parts | ||
first, _, rest = path.partition('/') | ||
|
||
if first.lower() in settings.LANGUAGES: | ||
return first, rest | ||
else: | ||
supported = [x for x in settings.LANGUAGE_URL_MAP if | ||
x.split('-')[0] == | ||
first.lower().split('-')[0]] | ||
if len(supported): | ||
return supported[0], rest | ||
else: | ||
return '', path | ||
|
||
def get_language(self): | ||
""" | ||
Return a locale code we support on the site using the | ||
user's Accept-Language header to determine which is best. This | ||
mostly follows the RFCs but read bug 439568 for details. | ||
""" | ||
if 'lang' in self.request.GET: | ||
lang = self.request.GET['lang'].lower() | ||
if lang in settings.LANGUAGE_URL_MAP: | ||
return settings.LANGUAGE_URL_MAP[lang] | ||
|
||
if self.request.META.get('HTTP_ACCEPT_LANGUAGE'): | ||
ranked_languages = parse_accept_lang_header( | ||
self.request.META['HTTP_ACCEPT_LANGUAGE']) | ||
|
||
# Do we support or remap their locale? | ||
supported = [lang[0] for lang in ranked_languages if lang[0] | ||
in settings.LANGUAGE_URL_MAP] | ||
|
||
# Do we support a less specific locale? (xx-YY -> xx) | ||
if not len(supported): | ||
for lang in ranked_languages: | ||
supported = [x for x in settings.LANGUAGE_URL_MAP if | ||
lang[0].split('-', 1)[0] == | ||
x.split('-', 1)[0]] | ||
if supported: | ||
break | ||
|
||
if len(supported): | ||
return settings.LANGUAGE_URL_MAP[supported[0]] | ||
|
||
return settings.LANGUAGE_CODE | ||
|
||
def fix(self, path): | ||
path = path.lstrip('/') | ||
url_parts = [self.request.META['SCRIPT_NAME']] | ||
|
||
if path.partition('/')[0] not in settings.SUPPORTED_NONLOCALES: | ||
locale = self.locale if self.locale else self.get_language() | ||
url_parts.append(locale) | ||
|
||
url_parts.append(path) | ||
|
||
return '/'.join(url_parts) |
Empty file.
Oops, something went wrong.