.. _registration:

Registering Models for Translation
==================================

Modeltranslation can translate model fields of any model class. For each model
to translate a translation option class containing the fields to translate is
registered with a special object called the ``translator``.

Registering models and their fields for translation requires the following
steps:

1. Create a ``translation.py`` in your app directory.
2. Create a translation option class for every model to translate.
3. Register the model and the translation option class at the
   ``modeltranslation.translator.translator``.

The modeltranslation application reads the ``translation.py`` file in your
app directory thereby triggering the registration of the translation
options found in the file.

A translation option is a class that declares which fields of a model to
translate. The class must derive from
``modeltranslation.translator.TranslationOptions`` and it must provide a
``fields`` attribute storing the list of fieldnames. The option class must be
registered with the ``modeltranslation.translator.translator`` instance.

To illustrate this let's have a look at a simple example using a ``News``
model. The news in this example only contains a ``title`` and a ``text`` field.
Instead of a news, this could be any Django model class::

    class News(models.Model):
        title = models.CharField(max_length=255)
        text = models.TextField()

In order to tell the modeltranslation app to translate the ``title`` and
``text`` field, create a ``translation.py`` file in your news app directory and
add the following::

    from modeltranslation.translator import translator, TranslationOptions
    from news.models import News

    class NewsTranslationOptions(TranslationOptions):
        fields = ('title', 'text',)

    translator.register(News, NewsTranslationOptions)

Note that this does not require to change the ``News`` model in any way, it's
only imported. The ``NewsTranslationOptions`` derives from
``TranslationOptions`` and provides the ``fields`` attribute. Finally the model
and its translation options are registered at the ``translator`` object.

At this point you are mostly done and the model classes registered for
translation will have been added some auto-magical fields. The next section
explains how things are working under the hood.


``TranslationOptions`` fields inheritance
-----------------------------------------

.. versionadded:: 0.5

A subclass of any ``TranslationOptions`` will inherit fields from its bases
(similar to the way Django models inherit fields, but with a different syntax). ::

    from modeltranslation.translator import translator, TranslationOptions
    from news.models import News, NewsWithImage

    class NewsTranslationOptions(TranslationOptions):
        fields = ('title', 'text',)

    class NewsWithImageTranslationOptions(NewsTranslationOptions):
        fields = ('image',)

    translator.register(News, NewsTranslationOptions)
    translator.register(NewsWithImage, NewsWithImageTranslationOptions)

The above example adds the fields ``title`` and ``text`` from the
``NewsTranslationOptions`` class to ``NewsWithImageTranslationOptions``, or to
say it in code::

    assert NewsWithImageTranslationOptions.fields == ('title', 'text', 'image')

Of course multiple inheritance and inheritance chains (A > B > C) also work as
expected.

.. note:: When upgrading from a previous modeltranslation version, please
    review your ``TranslationOptions`` classes and see if introducing `fields
    inheritance` broke the project (if you had always subclassed
    ``TranslationOptions`` only, there is no risk).


Changes Automatically Applied to the Model Class
------------------------------------------------

After registering the ``News`` model for translation a SQL dump of the news
app will look like this:

.. code-block:: console

    $ ./manage.py sqlall news
    BEGIN;
    CREATE TABLE `news_news` (
        `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
        `title` varchar(255) NOT NULL,
        `title_de` varchar(255) NULL,
        `title_en` varchar(255) NULL,
        `text` longtext NULL,
        `text_de` longtext NULL,
        `text_en` longtext NULL,
    )
    ;
    CREATE INDEX `news_news_page_id` ON `news_news` (`page_id`);
    COMMIT;

Note the ``title_de``, ``title_en``, ``text_de`` and ``text_en`` fields which
are not declared in the original ``News`` model class but rather have been
added by the modeltranslation app. These are called *translation fields*. There
will be one for every language in your project's ``settings.py``.

The name of these additional fields is build using the original name of the
translated field and appending one of the language identifiers found in the
``settings.LANGUAGES``.

As these fields are added to the registered model class as fully valid Django
model fields, they will appear in the db schema for the model although it has
not been specified on the model explicitly.

If you are starting a fresh project and have considered your translation needs
in the beginning then simply sync your database and you are ready to use
the translated models.

In case you are translating an existing project and your models have already
been synced to the database you will need to alter the tables in your database
and add these additional translation fields. Note that all added fields are
declared ``blank=True`` and ``null=True`` no matter if the original field is
required or not. In other words - all translations are optional. To populate
the default translation fields added by the modeltranslation application you
can use the ``update_translation_fields`` command below. See
:ref:`commands-update_translation_fields` for more infos on this.


.. _supported_field_matrix:

Supported Fields Matrix
-----------------------

While the main purpose of modeltranslation is to translate text-like fields,
translating other fields can be useful in several situations. The table lists
all model fields available in Django and gives an overview about their current
support status:

=============================== === === ===
Model Field                     0.4 0.5 0.7
=============================== === === ===
``AutoField``                   |n| |n| |n|
``BigIntegerField``             |n| |i| |i|
``BooleanField``                |n| |y| |y|
``CharField``                   |y| |y| |y|
``CommaSeparatedIntegerField``  |n| |y| |y|
``DateField``                   |n| |y| |y|
``DateTimeField``               |n| |y| |y|
``DecimalField``                |n| |y| |y|
``EmailField``                  |i| |i| |i|
``FileField``                   |y| |y| |y|
``FilePathField``               |i| |i| |i|
``FloatField``                  |n| |y| |y|
``ImageField``                  |y| |y| |y|
``IntegerField``                |n| |y| |y|
``IPAddressField``              |n| |y| |y|
``GenericIPAddressField``       |n| |y| |y|
``NullBooleanField``            |n| |y| |y|
``PositiveIntegerField``        |n| |i| |i|
``PositiveSmallIntegerField``   |n| |i| |i|
``SlugField``                   |i| |i| |i|
``SmallIntegerField``           |n| |i| |i|
``TextField``                   |y| |y| |y|
``TimeField``                   |n| |y| |y|
``URLField``                    |i| |i| |i|
``ForeignKey``                  |n| |n| |y|
``OneToOneField``               |n| |n| |y|
``ManyToManyField``             |n| |n| |n|
=============================== === === ===

.. |y| replace:: Yes
.. |i| replace:: Yes\*
.. |n| replace:: No
.. |u| replace:: ?

\* Implicitly supported (as subclass of a supported field)
