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:
Create a
translation.pyin your app directory.Create a translation option class for every model to translate.
Register the model and the translation option class at
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 modeltranslation to translate the title and text fields,
create a translation.py file in your news app directory and add the
following:
from modeltranslation.translator import translator, TranslationOptions
from .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.
Added in version 0.10.
If you prefer, register is also available as a decorator, much like the
one Django introduced for its admin in version 1.7. Usage is similar to the
standard register, just provide arguments as you normally would, except
the options class which will be the decorated one:
from modeltranslation.translator import register, TranslationOptions
from news.models import News
@register(News)
class NewsTranslationOptions(TranslationOptions):
fields = ('title', 'text',)
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¶
Added in version 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).
When dealing with abstract base classes, this can be handy:
from modeltranslation.translator import translator, TranslationOptions
from news.models import News, NewsWithImage
class AbstractNewsTranslationOptions(TranslationOptions):
fields = ('title', 'text',)
class NewsWithImageTranslationOptions(AbstractNewsTranslationOptions):
fields = ('image',)
translator.register(News, NewsTranslationOptions)
translator.register(NewsWithImage, NewsWithImageTranslationOptions)
The above example adds the fields title and text from the
AbstractNewsTranslationOptions 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.
However, if the base class is not abstract, inheriting the TranslationOptions will
cause errors, because the base TranslationOptions already took care of adding
fields to the model. The example below illustrates how to add translation fields to a
child model with a non-abstract base:
from modeltranslation.translator import translator, TranslationOptions
from news.models import News, NewsWithImage
class NewsTranslationOptions(TranslationOptions):
fields = ('title', 'text',)
class NewsWithImageTranslationOptions(TranslationOptions):
fields = ('image',)
translator.register(News, NewsTranslationOptions)
translator.register(NewsWithImage, NewsWithImageTranslationOptions)
This will add the translated fields title and text to the News model and further add
the translated field image to the NewsWithImage model.
Note
When upgrading from a previous modeltranslation version (<0.5), 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:
$ ./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 names of these additional fields are built 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.
Precautions regarding registration approach¶
Be aware that registration approach (as opposed to base-class approach) to models translation has a few caveats, though (despite many pros).
First important thing to note is the fact that translatable models are being patched - that means
their fields list is not final until the modeltranslation code executes. In normal circumstances
it shouldn’t affect anything - as long as models.py contain only models’ related code.
For example: consider a project where a ModelForm is declared in models.py just after
its model. When the file is executed, the form gets prepared - but it will be frozen with
old fields list (without translation fields). That’s because the ModelForm will be created
before modeltranslation would add new fields to the model (ModelForm gather fields info at class
creation time, not instantiation time). Proper solution is to define the form in forms.py,
which wouldn’t be imported alongside with models.py (and rather imported from views file or
urlconf).
Generally, for seamless integration with modeltranslation (and as sensible design anyway),
the models.py should contain only bare models and model related logic.
Committing fields to database¶
If you are starting a fresh project and have considered your translation needs
in the beginning then simply sync your database (./manage.py syncdb or
./manage.py schemamigration myapp --initial if using South)
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. If you are using South, you’re done: simply create a new migration (South will detect newly added translation fields) and apply it. If not, you can use a little helper: The sync_translation_fields Command which can execute schema-ALTERing SQL to add new fields. Use either of these two solutions, not both.
If you are adding translation fields to a third-party app,
things get more complicated. In order to be able to update the app in the future,
and to feel comfortable, you should use the sync_translation_fields command.
Although it’s possible to introduce new fields in a migration, it’s nasty and
involves copying migration files, using MIGRATION_MODULES setting,
so we don’t recommend it. Invoking sync_translation_fields is plain easier.
Note that all added fields are by default declared blank=True and
null=True no matter if the original field is required or not. In other
words - all translations are optional, unless an explicit option is
provided - see Required fields.
To populate the default translation fields added by modeltranslation with
values from existing database fields, you can use the
update_translation_fields command. See
The update_translation_fields Command for more info on this.
Migrations (Django 1.7)¶
Added in version 0.8.
Modeltranslation supports the migration system introduced by Django 1.7. Besides the normal workflow as described in Django’s Migration docs, you should do a migration whenever one of the following changes have been made to your project:
Added or removed a language through
settings.LANGUAGESorsettings.MODELTRANSLATION LANGUAGES.Registered or unregistered a field through
TranslationOptions.fields.
It doesn’t matter if you are starting a fresh project or change an existing one, it’s always:
python manage.py makemigrationsto create a new migration with the added or removed fields.python manage.py migrateto apply the changes.
Note
Support for migrations is implemented through
fields.TranslationField.deconstruct(self) and respects changes to the
null option.
Required fields¶
Added in version 0.8.
By default, all translation fields are optional (not required). This can be
changed using a special attribute on TranslationOptions:
class NewsTranslationOptions(TranslationOptions):
fields = ('title', 'text',)
required_languages = ('en', 'de')
It’s quite self-explanatory: for German and English, all translation fields are required. For other languages - optional.
A more fine-grained control is available:
class NewsTranslationOptions(TranslationOptions):
fields = ('title', 'text',)
required_languages = {'de': ('title', 'text'), 'default': ('title',)}
For German, all fields (both title and text) are required; for all other languages - only
title is required. The 'default' is optional.
Note
Requirement is enforced by blank=False. Please remember that it will trigger validation only
in modelforms and admin (as always in Django). Manual model validation can be performed via
the full_clean() model method.
The required fields are still null=True, though.
Added in version 0.19.4.
To set required_languages for all models, use MODELTRANSLATION_REQUIRED_LANGUAGES setting, which accepts the same values as required_languages class variable.
Per-Language Field Options (field_options)¶
Added in version (0.20).
By default, modeltranslation generates one translation field per language by
cloning the original field. Some database-level attributes (most notably
db_collation) make linguistic sense only for a specific language, so
copying the base-field’s value to every generated field is semantically
incorrect.
field_options lets you pass arbitrary keyword arguments to the generated
field objects on a per-language basis, without having to write manual
AlterField migrations afterwards.
Basic usage¶
Declare field_options as a class attribute on your TranslationOptions subclass:
class NewsTranslationOptions(TranslationOptions):
fields = ('title', 'text')
field_options = {
'title': {
'en': {'db_collation': 'en-x-icu'},
'de': {'db_collation': 'de-x-icu'},
},
}
The 'default' key¶
If you want the same kwargs for every language except a few, use the special
'default' key. It acts as a fallback for any language that does not have
its own explicit entry:
field_options = {
'title': {
'de': {'db_collation': 'de-x-icu'},
'default': {'db_collation': 'und-x-icu'}, # all other languages
},
}
Explicit language entries always win over 'default'.
Multiple kwargs¶
Any attribute that can be set on a Django model field after construction is accepted. You can combine several in one entry:
field_options = {
'title': {
'de': {
'db_collation': 'de-x-icu',
'db_comment': 'German title with ICU collation',
},
},
}
Language code format¶
Language codes in field_options must match the values in your
LANGUAGES / MODELTRANSLATION_LANGUAGES setting exactly (e.g. 'pt-br'
or 'pt_BR' depending on your configuration).
TranslationOptions attributes reference¶
Quick cheatsheet with links to proper docs sections and examples showing expected syntax.
Classes inheriting from TranslationOptions can have following attributes defined:
- TranslationOptions.fields(required)¶
List of translatable model fields. See Registering Models for Translation.
Some fields can be implicitly added through inheritance, see TranslationOptions fields inheritance.
- TranslationOptions.fallback_languages¶
Control order of languages for fallback purposes. See Fallback languages.
fallback_languages = {'default': ('en', 'de', 'fr'), 'uk': ('ru',)}
- TranslationOptions.fallback_values¶
Set the value that should be used if no fallback language yielded a value. See Fallback values.
fallback_values = _('-- sorry, no translation provided --') fallback_values = {'title': _('Object not translated'), 'text': '---'}
- TranslationOptions.fallback_undefined¶
Set what value should be considered “no value”. See Fallback undefined.
fallback_undefined = None fallback_undefined = {'title': 'no title', 'text': None}
- TranslationOptions.empty_values¶
Override the value that should be saved in forms on empty fields. See Formfields and nullability.
empty_values = '' empty_values = {'title': '', 'slug': None, 'desc': 'both'}
- TranslationOptions.required_languages¶
Control which translation fields are required. See Required fields.
required_languages = ('en', 'de') required_languages = {'de': ('title','text'), 'default': ('title',)}
- TranslationOptions.field_options¶
Pass arbitrary keyword arguments to the generated field objects on a per-language basis. See _field_options.
field_options = { 'title': { 'it': {'db_collation': 'it-x-icu'}, 'en': {'db_collation': 'en-x-icu'}, 'de': {'db_collation': 'de-x-icu'}, } }
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 |
|---|---|---|---|
|
No |
No |
No |
|
No |
Yes* |
Yes* |
|
No |
Yes |
Yes |
|
Yes |
Yes |
Yes |
|
No |
Yes |
Yes |
|
No |
Yes |
Yes |
|
No |
Yes |
Yes |
|
No |
Yes |
Yes |
|
Yes* |
Yes* |
Yes* |
|
Yes |
Yes |
Yes |
|
Yes* |
Yes* |
Yes* |
|
No |
Yes |
Yes |
|
Yes |
Yes |
Yes |
|
No |
Yes |
Yes |
|
No |
Yes |
Yes |
|
No |
Yes |
Yes |
|
No |
Yes |
Yes |
|
No |
Yes* |
Yes* |
|
No |
Yes* |
Yes* |
|
Yes* |
Yes* |
Yes* |
|
No |
Yes* |
Yes* |
|
Yes |
Yes |
Yes |
|
No |
Yes |
Yes |
|
Yes* |
Yes* |
Yes* |
|
No |
No |
Yes |
|
No |
No |
Yes |
|
No |
No |
No |
* Implicitly supported (as subclass of a supported field)