=================== 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 :django:setting:`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 :django:setting:`INSTALLED_APPS` setting. For example, :mod:`mezzanine.forms` extends models from :mod:`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 :django:setting:`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 :mod:`mezzanine.core.translation` depending on what you are extending from. For example, to improve the model from :doc:`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 :class:`mezzanine.pages.translation.TranslatedPage` is not referenced in any way. This is due to the fact that :class:`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 :class:`mezzanine.core.models.Slugged` or :class:`mezzanine.core.models.Displayable`, you will need to subclass their translation registration. An example of this is the :mod:`mezzanine.blog` app in its :mod:`.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 :mod:`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 :django:setting:`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 :django:setting:`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 :django:setting:`MIGRATION_MODULES` and then run:: $ python manage.py makemigrations Have a look at :ref:`field-injection-caveats` for a better introduction to :django:setting:`MIGRATION_MODULES`. Translation for Injected Fields =============================== If you added fields in Mezzanine's models through :ref:`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* :mod:`mezzanine.pages` in :django:setting:`INSTALLED_APPS` but *before* any app that contains models that subclass :class:`mezzanine.pages.models.Page` (such as :mod:`mezzanine.forms`, :mod:`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 :ref:`USE_MODELTRANSLATION` set to ``True`` or ``False``. Mezzanine enforces the value to ``False`` if django-modeltranslation is not installed. The :ref:`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 :ref:`USE_MODELTRANSLATION` set to ``False``, the ``translation.py`` module will just be ignored. The :ref:`USE_MODELTRANSLATION` setting is also available in the template's ``settings`` variable. Have a look at the ``includes/language_selector.html`` template in :mod:`mezzanine.core` for a working example.