Skip to content
This repository has been archived by the owner on Aug 26, 2022. It is now read-only.

Commit

Permalink
fix bug 647796 - better accept-language logic
Browse files Browse the repository at this point in the history
  • Loading branch information
groovecoder committed Mar 8, 2013
1 parent aaeca80 commit 2a8d335
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 31 deletions.
37 changes: 37 additions & 0 deletions apps/devmo/tests/test_middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from nose.tools import eq_
from test_utils import TestCase

from devmo.urlresolvers import get_best_language


class BestLanguageTests(TestCase):
def test_english_only(self):
best = get_best_language('en-us, en;q=0.8')
eq_('en-US', best)

def test_en_GB(self):
"""Stick with English if you can."""
best = get_best_language('en-gb, fr;q=0.8')
eq_('en-US', best)

def test_not_worst_choice(self):
"""Try not to fall back to 'es' here."""
best = get_best_language('en-gb, en;q=0.8, fr-fr;q=0.6, es;q=0.2')
eq_('en-US', best)

def test_fr_FR(self):
best = get_best_language('fr-FR, es;q=0.8')
eq_('fr', best)

def test_non_existent(self):
best = get_best_language('xy-YY, xy;q=0.8')
eq_(False, best)

def test_prefix_matching(self):
"""en-US is a better match for en-gb, es;q=0.2 than es."""
best = get_best_language('en-gb, es;q=0.2')
eq_('en-US', best)

def test_serbian(self):
"""sr -> sr-CYRL, not sr-LATN."""
eq_('sr-CYRL', get_best_language('sr'))
42 changes: 27 additions & 15 deletions apps/devmo/urlresolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,30 @@
_prefixes = {}


def get_best_language(accept_lang):
"""Given an Accept-Language header, return the best-matching language."""

LUM = settings.LANGUAGE_URL_MAP
NSL = settings.NON_SUPPORTED_LOCALES
LC = settings.LANGUAGE_CODE
langs = dict(LUM)
# Add in non-supported first to allow overriding prefix behavior.
langs.update((k.lower(), v if v else LC) for k, v in NSL.items() if
k.lower() not in langs)
langs.update((k.split('-')[0], v) for k, v in LUM.items() if
k.split('-')[0] not in langs)
ranked = parse_accept_lang_header(accept_lang)
for lang, _ in ranked:
lang = lang.lower()
if lang in langs:
return langs[lang]
pre = lang.split('-')[0]
if pre in langs:
return langs[pre]
# Couldn't find any acceptable locale.
return False


def set_url_prefix(prefix):
"""Set the ``prefix`` for the current thread."""
_prefixes[currentThread()] = prefix
Expand Down Expand Up @@ -83,22 +107,10 @@ def get_language(self):
return settings.LANGUAGE_URL_MAP[lang]

if self.request.META.get('HTTP_ACCEPT_LANGUAGE'):
ranked_languages = parse_accept_lang_header(
best = get_best_language(
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 = find_supported(lang[0])
if supported:
break

if len(supported):
return settings.LANGUAGE_URL_MAP[supported[0].lower()]
if best:
return best

return settings.LANGUAGE_CODE

Expand Down
42 changes: 27 additions & 15 deletions apps/sumo/urlresolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,30 @@
_locals = threading.local()


def get_best_language(accept_lang):
"""Given an Accept-Language header, return the best-matching language."""

LUM = settings.LANGUAGE_URL_MAP
NSL = settings.NON_SUPPORTED_LOCALES
LC = settings.LANGUAGE_CODE
langs = dict(LUM)
# Add in non-supported first to allow overriding prefix behavior.
langs.update((k.lower(), v if v else LC) for k, v in NSL.items() if
k.lower() not in langs)
langs.update((k.split('-')[0], v) for k, v in LUM.items() if
k.split('-')[0] not in langs)
ranked = parse_accept_lang_header(accept_lang)
for lang, _ in ranked:
lang = lang.lower()
if lang in langs:
return langs[lang]
pre = lang.split('-')[0]
if pre in langs:
return langs[pre]
# Couldn't find any acceptable locale.
return False


def set_url_prefixer(prefixer):
"""Set the Prefixer for the current thread."""
_locals.prefixer = prefixer
Expand Down Expand Up @@ -103,22 +127,10 @@ def get_language(self):
return settings.LANGUAGE_URL_MAP[lang]

if self.request.META.get('HTTP_ACCEPT_LANGUAGE'):
ranked_languages = parse_accept_lang_header(
best = get_best_language(
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 = find_supported(lang[0])
if supported:
break

if len(supported):
return settings.LANGUAGE_URL_MAP[supported[0].lower()]
if best:
return best

return settings.LANGUAGE_CODE

Expand Down
17 changes: 16 additions & 1 deletion settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,21 @@
'xx-testing': 'x-testing',
}

# Locales that are known but unsupported. Keys are the locale, values
# are an optional fallback locale, or None, to use the LANGUAGE_CODE.
NON_SUPPORTED_LOCALES = {
'af': None,
'an': 'es',
'br': 'fr',
'csb': 'pl',
'lij': 'it',
'nb-NO': 'no',
'nn-NO': 'no',
'oc': 'fr',
'sr': 'sr-CYRL', # Override the tendency to go sr->sr-LATN.
'sv-SE': 'sv',
}

try:
DEV_LANGUAGES = [
loc.replace('_','-') for loc in os.listdir(path('locale'))
Expand Down Expand Up @@ -1073,4 +1088,4 @@ def read_only_mode(env):
GRAPHITE_PREFIX = 'devmo'
GRAPHITE_TIMEOUT = 1

ES_DISABLED = True
ES_DISABLED = True

0 comments on commit 2a8d335

Please sign in to comment.