Commit 7b09ab5e by Sarina Canelake

dark_lang: only allow released langs in accept header LOC-72, LOC-85

Only return languages we've actually released LOC-85
Perform fuzzy matching to greedily serve the best released language LOC-72
parent e4cd2982
......@@ -83,11 +83,17 @@ class DarkLangMiddleware(object):
self._clean_accept_headers(request)
self._activate_preview_language(request)
def _is_released(self, lang_code):
"""
``True`` iff one of the values in ``self.released_langs`` is a prefix of ``lang_code``.
"""
return any(lang_code.lower().startswith(released_lang.lower()) for released_lang in self.released_langs)
def _fuzzy_match(self, lang_code):
"""Returns a fuzzy match for lang_code"""
if lang_code in self.released_langs:
return lang_code
lang_prefix = lang_code.partition('-')[0]
for released_lang in self.released_langs:
released_prefix = released_lang.partition('-')[0]
if lang_prefix == released_prefix:
return released_lang
return None
def _format_accept_value(self, lang, priority=1.0):
"""
......@@ -104,12 +110,13 @@ class DarkLangMiddleware(object):
if accept is None or accept == '*':
return
new_accept = ", ".join(
self._format_accept_value(lang, priority)
for lang, priority
in dark_parse_accept_lang_header(accept)
if self._is_released(lang)
)
new_accept = []
for lang, priority in dark_parse_accept_lang_header(accept):
fuzzy_code = self._fuzzy_match(lang.lower())
if fuzzy_code:
new_accept.append(self._format_accept_value(fuzzy_code, priority))
new_accept = ", ".join(new_accept)
request.META['HTTP_ACCEPT_LANGUAGE'] = new_accept
......
......@@ -4,8 +4,10 @@ Tests of DarkLangMiddleware
from django.contrib.auth.models import User
from django.http import HttpRequest
import ddt
from django.test import TestCase
from mock import Mock
import unittest
from dark_lang.middleware import DarkLangMiddleware
from dark_lang.models import DarkLangConfig
......@@ -23,6 +25,7 @@ def set_if_set(dct, key, value):
dct[key] = value
@ddt.ddt
class DarkLangMiddlewareTests(TestCase):
"""
Tests of DarkLangMiddleware
......@@ -82,6 +85,10 @@ class DarkLangMiddlewareTests(TestCase):
def test_wildcard_accept(self):
self.assertAcceptEquals('*', self.process_request(accept='*'))
def test_malformed_accept(self):
self.assertAcceptEquals('', self.process_request(accept='xxxxxxxxxxxx'))
self.assertAcceptEquals('', self.process_request(accept='en;q=1.0, es-419:q-0.8'))
def test_released_accept(self):
self.assertAcceptEquals(
'rel;q=1.0',
......@@ -123,14 +130,17 @@ class DarkLangMiddlewareTests(TestCase):
)
def test_accept_released_territory(self):
# We will munge 'rel-ter' to be 'rel', so the 'rel-ter'
# user will actually receive the released language 'rel'
# (Otherwise, the user will actually end up getting the server default)
self.assertAcceptEquals(
'rel-ter;q=1.0, rel;q=0.5',
'rel;q=1.0, rel;q=0.5',
self.process_request(accept='rel-ter;q=1.0, rel;q=0.5')
)
def test_accept_mixed_case(self):
self.assertAcceptEquals(
'rel-TER;q=1.0, REL;q=0.5',
'rel;q=1.0, rel;q=0.5',
self.process_request(accept='rel-TER;q=1.0, REL;q=0.5')
)
......@@ -140,11 +150,85 @@ class DarkLangMiddlewareTests(TestCase):
enabled=True
).save()
# Since we have only released "rel-ter", the requested code "rel" will
# fuzzy match to "rel-ter", in addition to "rel-ter" exact matching "rel-ter"
self.assertAcceptEquals(
'rel-ter;q=1.0',
'rel-ter;q=1.0, rel-ter;q=0.5',
self.process_request(accept='rel-ter;q=1.0, rel;q=0.5')
)
@ddt.data(
('es;q=1.0, pt;q=0.5', 'es-419;q=1.0'), # 'es' should get 'es-419', not English
('es-AR;q=1.0, pt;q=0.5', 'es-419;q=1.0'), # 'es-AR' should get 'es-419', not English
)
@ddt.unpack
def test_partial_match_es419(self, accept_header, expected):
# Release es-419
DarkLangConfig(
released_languages=('es-419, en'),
changed_by=self.user,
enabled=True
).save()
self.assertAcceptEquals(
expected,
self.process_request(accept=accept_header)
)
def test_partial_match_esar_es(self):
# If I release 'es', 'es-AR' should get 'es', not English
DarkLangConfig(
released_languages=('es, en'),
changed_by=self.user,
enabled=True
).save()
self.assertAcceptEquals(
'es;q=1.0',
self.process_request(accept='es-AR;q=1.0, pt;q=0.5')
)
@ddt.data(
# Test condition: If I release 'es-419, es, es-es'...
('es;q=1.0, pt;q=0.5', 'es;q=1.0'), # 1. es should get es
('es-419;q=1.0, pt;q=0.5', 'es-419;q=1.0'), # 2. es-419 should get es-419
('es-es;q=1.0, pt;q=0.5', 'es-es;q=1.0'), # 3. es-es should get es-es
)
@ddt.unpack
def test_exact_match_gets_priority(self, accept_header, expected):
# Release 'es-419, es, es-es'
DarkLangConfig(
released_languages=('es-419, es, es-es'),
changed_by=self.user,
enabled=True
).save()
self.assertAcceptEquals(
expected,
self.process_request(accept=accept_header)
)
@unittest.skip("This won't work until fallback is implemented for LA country codes. See LOC-86")
@ddt.data(
'es-AR', # Argentina
'es-PY', # Paraguay
)
def test_partial_match_es_la(self, latin_america_code):
# We need to figure out the best way to implement this. There are a ton of LA country
# codes that ought to fall back to 'es-419' rather than 'es-es'.
# http://unstats.un.org/unsd/methods/m49/m49regin.htm#americas
# If I release 'es, es-419'
# Latin American codes should get es-419
DarkLangConfig(
released_languages=('es, es-419'),
changed_by=self.user,
enabled=True
).save()
self.assertAcceptEquals(
'es-419;q=1.0',
self.process_request(accept='{};q=1.0, pt;q=0.5'.format(latin_america_code))
)
def assertSessionLangEquals(self, value, request):
"""
Assert that the 'django_language' set in request.session is equal to value
......@@ -224,6 +308,6 @@ class DarkLangMiddlewareTests(TestCase):
).save()
self.assertAcceptEquals(
'zh-CN;q=1.0, zh-TW;q=0.5, zh-HK;q=0.3',
'zh-cn;q=1.0, zh-tw;q=0.5, zh-hk;q=0.3',
self.process_request(accept='zh-Hans;q=1.0, zh-Hant-TW;q=0.5, zh-HK;q=0.3')
)
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