Mix of Python and Django utility functions, classed etc.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

182 lines
5.7 KiB

from copy import copy
import os
from collections import OrderedDict
from contextlib import contextmanager
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist, FieldDoesNotExist
from django.template.loader import select_template
from django.utils import translation
from django.views.generic import TemplateView
from django.views.i18n import set_language
FALLBACK_LANGUAGE_CODE = getattr(settings, 'FALLBACK_LANGUAGE_CODE', 'en')
def _normalize_language_code(language_code):
"""
8 years ago
Makes sure the language code is not an empty string.
"""
return (
language_code or
translation.get_language() or
settings.LANGUAGE_CODE or
FALLBACK_LANGUAGE_CODE
)
def get_language(language_code=None):
return _normalize_language_code(language_code).split("-")[0]
def get_language_order(languages=None):
"""
Returns a copy of settings.LANGUAGES with the active language at the first position.
"""
languages = languages or list(OrderedDict(settings.LANGUAGES).keys())
languages.insert(0, languages.pop(languages.index(get_language())))
return languages
# TODO Deprecated 'fieldname' parameter, use 'field_name'
def lang_suffix(language_code=None, field_name=None, fieldname=None):
"""
Returns the suffix appropriate for adding to field names for selecting
the current language.
If fieldname is given, returns the suffixed fieldname.
"""
language_code = _normalize_language_code(language_code or get_language()).split("-")[0]
return "{}_{}".format(field_name or fieldname or "", language_code)
class DirectTemplateView(TemplateView):
extra_context = None
def get_context_data(self, **kwargs):
context = super(DirectTemplateView, self).get_context_data(**kwargs)
if self.extra_context is not None:
for key, value in self.extra_context.items():
if callable(value):
context[key] = value()
else:
context[key] = value
return context
class I18nDirectTemplateView(DirectTemplateView):
def get_template_names(self):
t_name, t_ext = os.path.splitext(self.template_name)
lang = translation.get_language()
template = select_template([
"%s.%s%s" % (t_name, lang, t_ext),
self.template_name
])
return [template.template.name]
def get_translation(obj, relation_name='translations', language_code=None):
language_code = _normalize_language_code(language_code).split("-")[0]
try:
return getattr(obj, relation_name).get(language=language_code)
except ObjectDoesNotExist:
# FIXME Fetch best possible language from settings.LANGUAGES
try:
return getattr(obj, relation_name).get(language=(language_code == 'en' and 'de' or 'en'))
except ObjectDoesNotExist:
return None
def get_translated_field(obj, field_name, language_code=None):
"""
Tries to get the model attribute corresponding to the current
selected language by appending "_<language_code>" to the attribute
name and returning the value.
On AttributeError try to return the other language or the attribute
without the language suffix.
If the attribute is empty or null, try to return the value of
the other language's attribute.
If there is an attribute with the name without any language code
extension, return the value of this.
Best return value:
field_name + lang_suffix for current language
If empty or field does not exist:
if default language and field_name
field_name
else
field_name + lang_suffix other language
"""
# TODO Implement multiple languages
language_code = _normalize_language_code(language_code).split("-")[0]
is_default_language = bool(language_code == settings.LANGUAGE_CODE.split("-")[0])
if language_code == 'de':
other_language_code = 'en'
else:
other_language_code = 'de'
def has_db_field(field_name):
try:
# Only try to access database fields to avoid recursion
obj._meta.get_field(field_name)
return True
except FieldDoesNotExist:
return False
translated_field_name = '%s_%s' % (field_name, language_code)
other_translated_field_name = '%s_%s' % (field_name, other_language_code)
rv = ""
if hasattr(obj, translated_field_name):
rv = getattr(obj, translated_field_name)
if not rv:
if is_default_language and has_db_field(field_name):
rv = getattr(obj, field_name)
elif hasattr(obj, other_translated_field_name):
rv = getattr(obj, other_translated_field_name)
if not rv and has_db_field(field_name):
rv = getattr(obj, field_name)
# FIXME Raise error if neither field exists
return rv
@contextmanager
def active_language(lang='de'):
translation.activate(lang)
yield
translation.deactivate()
def set_language_get(request):
"""
set_language per GET request,
"""
request = copy(request)
request.POST = request.GET
request.method = 'POST'
return set_language(request)
class I18nUrlMixin(object):
"""
View Mixin.
Makes the url pattern name available in the template context.
Usage:
class ViewClass(I18nUrlMixin, TemplateView):
...
url(r'<your_pattern>', ViewClass.as_view(view_name='my-wonderful-view', name='my-wonderful-view'),
"""
view_name = None
def get_context_data(self, **kwargs):
if 'view_name' not in kwargs and self.view_name:
kwargs['view_name'] = self.view_name
context = super().get_context_data(**kwargs)
return context