Collection of helpers for multilingual websites.
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.
 
 
 

108 lines
3.5 KiB

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.conf import settings
from django.contrib.postgres.fields import JSONField
from django.db import models
from django.utils.translation import string_concat
from shared.utils.translation import get_language, lang_suffix
def get_translated_value(name):
def translated_value(obj):
language = get_language()
val = obj.__dict__[lang_suffix(language, name)]
# FIXME Try all available languages, not only the default one
if not val:
val = obj.__dict__[lang_suffix(settings.LANGUAGE_CODE, name)]
return val
return translated_value
class TranslatableFieldMixin:
"""
Make a Field subclass translatable, i.e. it automatically provides field duplicates
for each language defined in settings.LANGUAGES.
Parameters:
base_class
optional, is None first base class which is a subclass of Django's Field class is used
extra_parameter_names
optional, attributes of the original field to be copied to the localized fields
Usage:
class TranslatableRichTextField(TranslatableFieldMixin, RichTextField):
base_class = RichTextField
extra_parameter_names = ['config_name', 'extra_plugins', 'external_plugin_resources']
"""
base_class = None
extra_parameter_names = []
def __init__(self, verbose_name=None, **kwargs):
self._blank = kwargs.get("blank", False)
self._editable = kwargs.get("editable", True)
super().__init__(verbose_name, **kwargs)
def contribute_to_class(self, cls, name, private_only=False):
for lang_code, lang_name in settings.LANGUAGES:
if lang_code == settings.LANGUAGE_CODE:
_blank = self._blank
else:
_blank = True
params = {
'blank': _blank,
'choices': self.choices,
'db_column': None,
'db_index': self.db_index,
'db_tablespace': self.db_tablespace,
'default': self.default or "",
'editable': self._editable,
'help_text': self.help_text,
'max_length': self.max_length,
'name': self.name,
'null': False, # intentionally ignored
'primary_key': self.primary_key,
'rel': self.rel,
'serialize': self.serialize,
'unique': self.unique,
}
for n in self.extra_parameter_names:
params[n] = getattr(self, n, None)
# TODO Move this logic to a meta class?
if not self.base_class:
# Get first base class which is a subclass of Django's Field
self.base_class = [f for f in self.__class__.__bases__
if issubclass(f, models.Field)][0]
localized_field = self.base_class(
string_concat(self.verbose_name, " (%s)" % lang_code),
**params
)
localized_field.contribute_to_class(
cls,
"%s%s" % (name, lang_suffix(lang_code)),
)
setattr(cls, name, property(get_translated_value(name)))
class TranslatableCharField(TranslatableFieldMixin, models.CharField):
pass
class TranslatableTextField(TranslatableFieldMixin, models.TextField):
pass
class TranslatableJSONField(TranslatableFieldMixin, JSONField):
extra_parameter_names = ['encoder']