Execute the following steps to define the multilingual character field and multilingual text field:
- Open the model_fields.py file, and create the base multilingual field, as follows:
# myproject/apps/core/model_fields.py
from django.conf import settings
from django.db import models
from django.utils.translation import get_language
from django.utils import translation
class MultilingualField(models.Field):
SUPPORTED_FIELD_TYPES = [models.CharField, models.TextField]
def __init__(self, verbose_name=None, **kwargs):
self.localized_field_model = None
for model in MultilingualField.SUPPORTED_FIELD_TYPES:
if issubclass(self.__class__, model):
self.localized_field_model = model
self._blank = kwargs.get("blank", False)
self._editable = kwargs.get("editable", True)
super().__init__(verbose_name, **kwargs)
@staticmethod
def localized_field_name(name, lang_code):
lang_code_safe = lang_code.replace("-", "_")
return f"{name}_{lang_code_safe}"
def get_localized_field(self, lang_code, lang_name):
_blank = (self._blank
if lang_code == settings.LANGUAGE_CODE
else True)
localized_field = self.localized_field_model(
f"{self.verbose_name} ({lang_name})",
name=self.name,
primary_key=self.primary_key,
max_length=self.max_length,
unique=self.unique,
blank=_blank,
null=False, # we ignore the null argument!
db_index=self.db_index,
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)
return localized_field
def contribute_to_class(self, cls, name,
private_only=False,
virtual_only=False):
def translated_value(self):
language = get_language()
val = self.__dict__.get(
MultilingualField.localized_field_name(
name, language))
if not val:
val = self.__dict__.get(
MultilingualField.localized_field_name(
name, settings.LANGUAGE_CODE))
return val
# generate language-specific fields dynamically
if not cls._meta.abstract:
if self.localized_field_model:
for lang_code, lang_name in settings.LANGUAGES:
localized_field = self.get_localized_field(
lang_code, lang_name)
localized_field.contribute_to_class(
cls,
MultilingualField.localized_field_name(
name, lang_code))
setattr(cls, name, property(translated_value))
else:
super().contribute_to_class(
cls, name, private_only, virtual_only)
- In the same file, subclass the base field for character and text field forms, as follows:
class MultilingualCharField(models.CharField, MultilingualField):
pass
class MultilingualTextField(models.TextField, MultilingualField):
pass
- Create an admin.py file in the core app, and add the following content:
# myproject/apps/core/admin.py
from django.conf import settings
def get_multilingual_field_names(field_name):
lang_code_underscored = settings.LANGUAGE_CODE.replace("-",
"_")
field_names = [f"{field_name}_{lang_code_underscored}"]
for lang_code, lang_name in settings.LANGUAGES:
if lang_code != settings.LANGUAGE_CODE:
lang_code_underscored = lang_code.replace("-", "_")
field_names.append(
f"{field_name}_{lang_code_underscored}"
)
return field_names
Now, we'll consider an example of how to use the multilingual fields in your app, as follows:
- First, set multiple languages in the settings for your project. Let's say, our website will support all official languages of the European Union, with English being the default language:
# myproject/settings/_base.py
LANGUAGE_CODE = "en"
# All official languages of European Union
LANGUAGES = [
("bg", "Bulgarian"), ("hr", "Croatian"),
("cs", "Czech"), ("da", "Danish"),
("nl", "Dutch"), ("en", "English"),
("et", "Estonian"), ("fi", "Finnish"),
("fr", "French"), ("de", "German"),
("el", "Greek"), ("hu", "Hungarian"),
("ga", "Irish"), ("it", "Italian"),
("lv", "Latvian"), ("lt", "Lithuanian"),
("mt", "Maltese"), ("pl", "Polish"),
("pt", "Portuguese"), ("ro", "Romanian"),
("sk", "Slovak"), ("sl", "Slovene"),
("es", "Spanish"), ("sv", "Swedish"),
]
- Then, open the models.py file from the myproject.apps.ideas app, and create the multilingual fields for the Idea model, as follows:
# myproject/apps/ideas/models.py
from django.db import models
from django.utils.translation import gettext_lazy as _
from myproject.apps.core.model_fields import (
MultilingualCharField,
MultilingualTextField,
)
class Idea(models.Model):
title = MultilingualCharField(
_("Title"),
max_length=200,
)
content = MultilingualTextField(
_("Content"),
)
class Meta:
verbose_name = _("Idea")
verbose_name_plural = _("Ideas")
def __str__(self):
return self.title
- Create an admin.py file for the ideas app:
# myproject/apps/ideas/admin.py
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from myproject.apps.core.admin import get_multilingual_field_names
from .models import Idea
@admin.register(Idea)
class IdeaAdmin(admin.ModelAdmin):
fieldsets = [
(_("Title and Content"), {
"fields": get_multilingual_field_names("title") +
get_multilingual_field_names("content")
}),
]