Skip to content

Commit

Permalink
Handle if lang code in settings is None (#66)
Browse files Browse the repository at this point in the history
* Handle if lang code in settings is None
* Make requests fail if languages are incorrect
* bump langcodes version to support actual code validation
* Invalid languages now report a 404 correctly

Co-authored-by: Samuel Spencer <theodore.therone@gmail.com>
  • Loading branch information
s-i-l-k-e and LegoStormtroopr authored Feb 26, 2022
1 parent 6e631b4 commit ff2903a
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 239 deletions.
33 changes: 32 additions & 1 deletion garnett/middleware.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from django.conf import settings
from django.http import Http404
from django.utils.module_loading import import_string
from django.utils.translation import gettext as _

import logging
import langcodes
from langcodes import Language

from .utils import get_language_from_request, is_valid_language
from .utils import is_valid_language, get_default_language
from .context import set_field_language

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -86,3 +89,31 @@ def __call__(self, request):
)

return self.get_response(request)


def get_language_from_request(request) -> Language:
opt_order = getattr(
settings,
"GARNETT_REQUEST_LANGUAGE_SELECTORS",
[
"garnett.selectors.header",
"garnett.selectors.query",
"garnett.selectors.cookie",
],
)
for opt in opt_order:
func = import_string(opt)
if lang := func(request):
try:
return Language.get(lang)
except langcodes.tag_parser.LanguageTagError:
raise Http404(
_(
"The provided language %(lang_code)s is not a valid language code"
)
% {
"lang_code": lang,
}
)

return get_default_language()
55 changes: 33 additions & 22 deletions garnett/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import List, Union
from typing import List, Union, Optional

import langcodes.tag_parser
from django.conf import settings
from django.utils.module_loading import import_string
from django.core.exceptions import ImproperlyConfigured
from langcodes import Language

Expand Down Expand Up @@ -68,31 +68,42 @@ def get_current_blank_override() -> bool:
return _ctx_force_blank.get(False)


def get_safe_language(lang_code: str) -> Optional[Language]:
"""Return language if language for lang code exists, otherwise none"""
try:
return Language.get(lang_code)
except langcodes.tag_parser.LanguageTagError:
return None


def validate_language_list(langs) -> List[Language]:
"""
Validate and clean a potential list of languages.
This may return an empty list if the provided languages are invalid
"""
if type(langs) is not list:
return []

languages = []
for lang_code in langs:
if language := get_safe_language(lang_code):
languages.append(language)

if languages:
return languages


def get_languages() -> List[Language]:
langs = getattr(
settings, "GARNETT_TRANSLATABLE_LANGUAGES", [get_default_language()]
)
if callable(langs):
langs = langs()
if type(langs) == list:
return [Language.get(lang) for lang in langs]
raise ImproperlyConfigured(
"GARNETT_TRANSLATABLE_LANGUAGES must be a list or a callable that returns a list"
)

languages = validate_language_list(langs)

def get_language_from_request(request) -> Language:
opt_order = getattr(
settings,
"GARNETT_REQUEST_LANGUAGE_SELECTORS",
[
"garnett.selectors.header",
"garnett.selectors.query",
"garnett.selectors.cookie",
],
)
for opt in opt_order:
func = import_string(opt)
if lang := func(request):
return Language.get(lang)
return get_default_language()
if not languages:
raise ImproperlyConfigured(
"GARNETT_TRANSLATABLE_LANGUAGES must be a list of languages or a callable that returns a list of languages"
)
return languages
Loading

0 comments on commit ff2903a

Please sign in to comment.