Multi-Lingual Sites¶
Mezzanine provides optional support for django-modeltranslation which enables content editors to provide multi-lingual content to support sites in multiple languages.
Note
Mezzanine only provides the integration of django-modeltranslation. For dedicated assistance, please check out the documentation for django-modeltranslation: documentation or its code.
Translation Fields in Mezzanine¶
In order to enable translation fields for Mezzanine content, you will
need to install django-modeltranslation and activate the app in your
settings.py
. Once you have installed django-modeltranslation,
you can enable support for it by setting the USE_MODELTRANSLATION
setting to True
in your project’s settings.py
module, and
also defining at least two entries in the LANGUAGES
setting.
For new projects, manage.py createdb
will take care of creating
extra columns in the database for each language. For current or
older projects, you can catch up by running
manage.py sync_translation_fields
and then
manage.py update_translation_fields
.
Note
A django-modeltranslation setting that can help managing the
transition for content partially in several languages is
MODELTRANSLATION_FALLBACK_LANGUAGES
. This setting allows you
to avoid having empty content when the translation is not provided
for a specific language. Please consult django-modeltranslation’s
documentation
for more detail.
Translation Fields for Custom Applications¶
For models that don’t inherit from Mezzanine’s models, again please consult
django-modeltranslation’s documentation.
To start with, you’ll need to provide a translation.py
module,
containing classes describing which of your model fields you wish to
translate, as well as registering your models using the
modeltranslation.translator.translator.register
method.
For models that extends Mezzanine capabilities, there are two rules:
Firstly, the app in which your model is defined must be listed after
the app it is extending from in your INSTALLED_APPS
setting. For example, mezzanine.forms
extends models from
mezzanine.pages
and should appear after it.
Note
If your app defines both models that need to be translated and
static content or templates that override default ones from
Mezzanine, you’ll need to split your app to distinguish
between presentation and content. This is due to conflicting
ideas with translated model inheritance, and template or static
file overriding, in regard to the order of INSTALLED_APPS`
Secondly, for an external app, create a translation.py
module
at the root of your app. The content of this file might benefit
from mezzanine.core.translation
depending on what you are
extending from. For example, to improve the model from
Content Architecture and provide translatable fields:
from django.db import models
from mezzanine.pages.models import Page
class Author(Page):
dob = models.DateField("Date of birth")
trivia = models.TextField("Trivia")
class Book(models.Model):
author = models.ForeignKey("Author")
cover = models.ImageFiled(upload_to="authors")
title = models.CharField("Title", max_length=200)
A corresponding translation.py
module in this app would look like:
from modeltranslation.translator import translator, TranslationOptions
from .models import Author, Book
class TranslatedAuthor(TranslationOptions):
fields = ('trivia',)
class TranslatedBook(TranslationOptions):
fields = ('title',)
translator.register(Author, TranslatedAuthor)
translator.register(Book, TranslatedBook)
In this case, please note mezzanine.pages.translation.TranslatedPage
is not referenced in any way. This is due to the fact that
mezzanine.pages.models.Page
is not abstract, and thus has its own
table in the database. The fields have already been registered for
translation and django-modeltranslation will happily handle it for you.
If you want to extend an abstract model, such as
mezzanine.core.models.Slugged
or
mezzanine.core.models.Displayable
, you will need to subclass their
translation registration. An example of this is the mezzanine.blog
app
in its translation.py
module:
from modeltranslation.translator import translator
from mezzanine.core.translation import (TranslatedSlugged,
TranslatedDisplayable,
TranslatedRichText)
from mezzanine.blog.models import BlogCategory, BlogPost
class TranslatedBlogPost(TranslatedDisplayable, TranslatedRichText):
fields = ()
class TranslatedBlogCategory(TranslatedSlugged):
fields = ()
translator.register(BlogPost, TranslatedBlogPost)
translator.register(BlogCategory, TranslatedBlogCategory)
You don’t add translatable fields in your model beside those
already defined inside Mezzanine’s models. You need to extend from
mezzanine.core.translation
classes, so django-modeltranslation
is aware of the abstract fields it will have to manage.
After that, you can manage.py createdb
for a new project or
manage.py sync_translation_fields
and then
manage.py update_translation_fields
for an existing one.
Translation Fields and Migrations¶
Mezzanine is shipped with its own migration files but these do not take
translation fields into account. These fields are created by every
project’s LANGUAGES
setting and thus can’t be provided by default.
If you want to both manage migrations for your project and enable
translation fields, there are two possibilities.
Either you disable translation fields while managing your migrations as usual and then catch up by adding the missing fields if any:
# edit settings.py to set USE_MODELTRANSLATION = False
$ python manage.py makemigrations
$ python manage.py migrate
# edit settings.py to set USE_MODELTRANSLATION back to True
$ python manage.py sync_translation_fields
This way, your migration files will never contains references to your
specific LANGUAGES
setting.
Or you create migration files including all the translation fields
for your project. This way you won’t need to rely on the
manage.py sync_translation_fields
command anymore. You will
need to define a custom MIGRATION_MODULES
and then run:
$ python manage.py makemigrations
Have a look at Field Injection Caveats for a better introduction
to MIGRATION_MODULES
.
Translation for Injected Fields¶
If you added fields in Mezzanine’s models through
EXTRA_MODEL_FIELDS and want to add translations, you will need
to create a custom app that will hold the necessary translation.py
module.
Adding a translation field to all of Mezzanine’s content type would look like:
EXTRA_MODEL_FIELDS = (
(
"mezzanine.pages.models.Page.quote",
"TextField",
("Page's Quote",),
{"blank": True},
),
)
The app containing the corresponding translation.py
module should
be defined after mezzanine.pages
in INSTALLED_APPS
but
before any app that contains models that subclass
mezzanine.pages.models.Page
(such as mezzanine.forms
,
mezzanine.galleries
or cartridge.shop
). The translation.py
file itself would be:
from modeltranslation.translator import translator
from mezzanine.pages.translation import TranslatedPage
from mezzanine.pages.models import Page
class TranslatedInjectedPage(TranslatedPage):
fields = ('quote',),
translator.unregister(Page)
translator.register(Page, TranslatedInjectedPage)
Redistributable Applications for Mezzanine¶
If you want to provide translation support for your Mezzanine app,
make sure it works with both USE_MODELTRANSLATION set to True
or False
. Mezzanine enforces the value to False
if
django-modeltranslation is not installed.
The USE_MODELTRANSLATION setting can therefore be used to check
against, when extra steps are required (such as saving an instance of
a model in every language). In the case of a project with
USE_MODELTRANSLATION set to False
, the translation.py
module will just be ignored.
The USE_MODELTRANSLATION setting is also available in the
template’s settings
variable. Have a look at the
includes/language_selector.html
template in mezzanine.core
for a working example.