Browse Source

TranslatableFieldMixin.

master
Erik Stein 8 years ago
parent
commit
7602717c40
  1. 173
      shared/multilingual/utils/fields.py

173
shared/multilingual/utils/fields.py

@ -9,63 +9,42 @@ from django.utils.translation import string_concat
from shared.utils.translation import get_language, lang_suffix
class TranslatableCharField(models.CharField):
def get_translated_value(name):
def translated_value(obj):
language = get_language()
val = obj.__dict__["%s%s" % (name, lang_suffix(language))]
if not val:
val = obj.__dict__["%s%s" % (name, lang_suffix(settings.LANGUAGE_CODE))]
return val
return translated_value
def __init__(self, verbose_name=None, **kwargs):
self._blank = kwargs.get("blank", False)
self._editable = kwargs.get("editable", True)
super(TranslatableCharField, self).__init__(verbose_name, **kwargs)
class TranslatableFieldMixin:
"""
Make a Field subclass translatable, i.e. it automatically provides field duplicates
for each language defined in settings.LANGUAGES.
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
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
localized_field = models.CharField(
string_concat(self.verbose_name, " (%s)" % lang_code),
name=self.name,
primary_key=self.primary_key,
max_length=self.max_length,
unique=self.unique,
blank=_blank,
null=False, # intentionally ignored
db_index=self.db_index,
rel=self.rel,
default=self.default or "",
editable=self._editable,
serialize=self.serialize,
choices=self.choices,
help_text=self.help_text,
db_column=None,
db_tablespace=self.db_tablespace
)
Usage:
localized_field.contribute_to_class(
cls,
"%s%s" % (name, lang_suffix(lang_code)),
)
class TranslatableRichTextField(TranslatableFieldMixin, RichTextField):
base_class = RichTextField
extra_parameter_names = ['config_name', 'extra_plugins', 'external_plugin_resources']
"""
def translated_value(self):
# For empty / non-existing translation fall back to main field
language = get_language()
val = self.__dict__["%s%s" % (name, lang_suffix(language))]
if not val:
val = self.__dict__["%s%s" % (name, lang_suffix(settings.LANGUAGE_CODE))]
return val
setattr(cls, name, property(translated_value))
class TranslatableTextField(models.TextField):
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(TranslatableTextField, self).__init__(verbose_name, **kwargs)
super().__init__(verbose_name, **kwargs)
def contribute_to_class(self, cls, name, private_only=False):
for lang_code, lang_name in settings.LANGUAGES:
@ -74,23 +53,36 @@ class TranslatableTextField(models.TextField):
else:
_blank = True
localized_field = models.TextField(
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),
name=self.name,
primary_key=self.primary_key,
max_length=self.max_length,
unique=self.unique,
blank=_blank,
null=False, # intentionally ignored
db_index=self.db_index,
rel=self.rel,
default=self.default or "",
editable=self._editable,
serialize=self.serialize,
choices=self.choices,
help_text=self.help_text,
db_column=None,
db_tablespace=self.db_tablespace
**params
)
localized_field.contribute_to_class(
@ -98,61 +90,18 @@ class TranslatableTextField(models.TextField):
"%s%s" % (name, lang_suffix(lang_code)),
)
def translated_value(self):
language = get_language()
val = self.__dict__["%s%s" % (name, lang_suffix(language))]
if not val:
val = self.__dict__["%s%s" % (name, lang_suffix(settings.LANGUAGE_CODE))]
return val
setattr(cls, name, property(get_translated_value(name)))
setattr(cls, name, property(translated_value))
class TranslatableCharField(TranslatableFieldMixin, models.CharField):
pass
class TranslatableJSONField(JSONField):
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
class TranslatableTextField(TranslatableFieldMixin, models.TextField):
pass
localized_field = JSONField(
string_concat(self.verbose_name, " (%s)" % lang_code),
name=self.name,
primary_key=self.primary_key,
max_length=self.max_length,
unique=self.unique,
blank=_blank,
null=False, # intentionally ignored
db_index=self.db_index,
rel=self.rel,
default=self.default or "",
editable=self._editable,
serialize=self.serialize,
choices=self.choices,
help_text=self.help_text,
db_column=None,
db_tablespace=self.db_tablespace,
encoder=self.encoder
)
localized_field.contribute_to_class(
cls,
"%s%s" % (name, lang_suffix(lang_code)),
)
class TranslatableJSONField(TranslatableFieldMixin, JSONField):
extra_parameter_names = ['encoder']
def translated_value(self):
language = get_language()
val = self.__dict__["%s%s" % (name, lang_suffix(language))]
if not val:
val = self.__dict__["%s%s" % (name, lang_suffix(settings.LANGUAGE_CODE))]
return val
setattr(cls, name, property(translated_value))

Loading…
Cancel
Save