War in Ukraine¶
On February 24th, 2022, Russia invaded Ukraine. I’m sole maintainer of this project staying in safe place, but i don’t know how long it would be safe.
Russian military shelling our cities, targeting civilian population.
Help Ukraine:
Talk to your politics, talk to your friends. Send heavy weapons to Ukraine. Close the sky.
Modeltranslation¶
The modeltranslation application is used to translate dynamic content of existing Django models to an arbitrary number of languages without having to change the original model classes. It uses a registration approach (comparable to Django’s admin app) to be able to add translations to existing or new projects and is fully integrated into the Django admin backend.
The advantage of a registration approach is the ability to add translations to models on a per-app basis. You can use the same app in different projects, may they use translations or not, and you never have to touch the original model class.
Features¶
- Add translations without changing existing models or views
- Translation fields are stored in the same table (no expensive joins)
- Supports inherited models (abstract and multi-table inheritance)
- Handle more than just text fields
- Django admin integration
- Flexible fallbacks, auto-population and more!
For the latest documentation, visit https://django-modeltranslation.readthedocs.io/en/latest/.
Table of Contents¶
Installation¶
Requirements¶
Which Modeltranslation version is required for given Django-Python combination to work?
Python | Django | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
version | 1.8 | 1.9 | 1.10 | 1.11 | 2.0 | 2.1 | 2.2 | 3.0 | 3.2 | 4.0 | 4.1 | 4.2 |
2.7 | 0.9+ | 0.11+ | 0.12+ | 0.13+ | ||||||||
3.2 | 0.9+ | |||||||||||
3.3 | 0.9+ | |||||||||||
3.4 | 0.9+ | 0.11+ | 0.12+ | 0.13+ | 0.13+ | |||||||
3.5 | 0.9+ | 0.11+ | 0.12+ | 0.13+ | 0.13+ | 0.13+ | ||||||
3.6 | 0.13+ | 0.13+ | 0.13+ | 0.15+ | 0.15+ | 0.17+ | 0.17+ | 0.17+ | 0.18+ | |||
3.7 | 0.13+ | 0.13+ | 0.15+ | 0.15+ | 0.17+ | 0.17+ | 0.17+ | 0.18+ | ||||
3.8 | 0.13+ | 0.13+ | 0.15+ | 0.15+ | 0.17+ | 0.17+ | 0.17+ | 0.18+ | ||||
3.9 | 0.13+ | 0.13+ | 0.15+ | 0.15+ | 0.17+ | 0.17+ | 0.17+ | 0.18+ | ||||
3.10 | 0.13+ | 0.13+ | 0.15+ | 0.15+ | 0.17+ | 0.17+ | 0.17+ | 0.18+ | ||||
3.11 | 0.13+ | 0.13+ | 0.15+ | 0.15+ | 0.17+ | 0.17+ | 0.17+ | 0.18+ |
(-X
denotes “up to version X”, whereas X+
means “from version X upwards”)
Using Pip¶
$ pip install django-modeltranslation
Setup¶
To setup the application please follow these steps. Each step is described in detail in the following sections:
Add
modeltranslation
to theINSTALLED_APPS
variable of your project’ssettings.py
.Set
USE_I18N = True
insettings.py
.Configure your
LANGUAGES
insettings.py
.Create a
translation.py
in your app directory and registerTranslationOptions
for every model you want to translate.Sync the database using
python manage.py makemigrations
andpython manage.py migrate
.Note
This only applies if the models registered in
translation.py
haven’t been synced to the database before. If they have, please read Committing fields to database.
Configuration¶
Required Settings¶
The following variables have to be added to or edited in the project’s
settings.py
:
INSTALLED_APPS
¶
Make sure that the modeltranslation
app is listed in your
INSTALLED_APPS
variable:
INSTALLED_APPS = (
...
'modeltranslation',
'django.contrib.admin', # optional
....
)
Important
If you want to use the admin integration, modeltranslation
must be put
before django.contrib.admin
(only applies when using Django 1.7 or
above).
Important
If you want to use the django-debug-toolbar
together with modeltranslation, use explicit setup.
Otherwise tweak the order of INSTALLED_APPS
: try to put debug_toolbar
as first entry in
INSTALLED_APPS
(in Django < 1.7) or after modeltranslation
(in Django >= 1.7). However,
only explicit setup is guaranteed to succeed.
LANGUAGES
¶
The LANGUAGES
variable must contain all languages used for translation. The
first language is treated as the default language.
Modeltranslation uses the list of languages to add localized fields to the
models registered for translation. To use the languages de
and en
in
your project, set the LANGUAGES
variable like this (where de
is the
default language):
gettext = lambda s: s
LANGUAGES = (
('de', gettext('German')),
('en', gettext('English')),
)
Note
The gettext
lambda function is not a feature of modeltranslation, but
rather required for Django to be able to (statically) translate the verbose
names of the languages using the standard i18n
solution.
Note
If, for some reason, you don’t want to translate objects to exactly the same languages as
the site would be displayed into, you can set MODELTRANSLATION_LANGUAGES
(see below).
For any language in LANGUAGES
not present in MODELTRANSLATION_LANGUAGES
, the default
language will be used when accessing translated content. For any language in
MODELTRANSLATION_LANGUAGES
not present in LANGUAGES
, probably nobody will see translated
content, since the site wouldn’t be accessible in that language.
Warning
Modeltranslation does not enforce the LANGUAGES
setting to be defined
in your project. When it isn’t present (and neither is MODELTRANSLATION_LANGUAGES
), it
defaults to Django’s
global LANGUAGES setting
instead, and that are quite a few languages!
Advanced Settings¶
Modeltranslation also has some advanced settings to customize its behaviour.
MODELTRANSLATION_DEFAULT_LANGUAGE
¶
New in version 0.3.
Default: None
To override the default language as described in LANGUAGES,
you can define a language in MODELTRANSLATION_DEFAULT_LANGUAGE
. Note that
the value has to be in settings.LANGUAGES
, otherwise an
ImproperlyConfigured
exception will be raised.
Example:
MODELTRANSLATION_DEFAULT_LANGUAGE = 'en'
MODELTRANSLATION_LANGUAGES
¶
New in version 0.8.
Default: same as LANGUAGES
Allow to set languages the content will be translated into. If not set, by default all
languages listed in LANGUAGES
will be used.
Example:
LANGUAGES = (
('en', 'English'),
('de', 'German'),
('pl', 'Polish'),
)
MODELTRANSLATION_LANGUAGES = ('en', 'de')
Note
This setting may become useful if your users shall produce content for a restricted set of languages, while your application is translated into a greater number of locales.
MODELTRANSLATION_FALLBACK_LANGUAGES
¶
New in version 0.5.
Default: (DEFAULT_LANGUAGE,)
By default modeltranslation will fallback to the computed value of the
DEFAULT_LANGUAGE
. This is either the first language found in the
LANGUAGES
setting or the value defined through
MODELTRANSLATION_DEFAULT_LANGUAGE
which acts as an override.
This setting allows for a more fine grained tuning of the fallback behaviour by taking additional languages into account. The language order is defined as a tuple or list of language codes.
Example:
MODELTRANSLATION_FALLBACK_LANGUAGES = ('en', 'de')
Using a dict syntax it is also possible to define fallbacks by language.
A default
key is required in this case to define the default behaviour
of unlisted languages.
Example:
MODELTRANSLATION_FALLBACK_LANGUAGES = {'default': ('en', 'de'), 'fr': ('de',)}
Note
Each language has to be in the LANGUAGES
setting, otherwise an
ImproperlyConfigured
exception is raised.
MODELTRANSLATION_PREPOPULATE_LANGUAGE
¶
New in version 0.7.
Default: current active language
By default modeltranslation will use the current request language for prepopulating
admin fields specified in the prepopulated_fields
admin property. This is often
used to automatically fill slug fields.
This setting allows you to pin this functionality to a specific language.
Example:
MODELTRANSLATION_PREPOPULATE_LANGUAGE = 'en'
Note
The language has to be in the LANGUAGES
setting, otherwise an
ImproperlyConfigured
exception is raised.
MODELTRANSLATION_TRANSLATION_FILES
¶
New in version 0.4.
Default: ()
(empty tuple)
Modeltranslation uses an autoregister feature similar to the one in Django’s
admin. The autoregistration process will look for a translation.py
file in the root directory of each application that is in INSTALLED_APPS
.
The setting MODELTRANSLATION_TRANSLATION_FILES
is provided to extend the
modules that are taken into account.
Syntax:
MODELTRANSLATION_TRANSLATION_FILES = (
'<APP1_MODULE>.translation',
'<APP2_MODULE>.translation',
)
Example:
MODELTRANSLATION_TRANSLATION_FILES = (
'news.translation',
'projects.translation',
)
Note
Modeltranslation up to version 0.3 used a single project wide registration
file which was defined through
MODELTRANSLATION_TRANSLATION_REGISTRY = '<PROJECT_MODULE>.translation'
.
In version 0.4 and 0.5, for backwards compatibility, the module defined through this setting was
automatically added to MODELTRANSLATION_TRANSLATION_FILES
. A
DeprecationWarning
was issued in this case.
In version 0.6 MODELTRANSLATION_TRANSLATION_REGISTRY
is handled no more.
MODELTRANSLATION_CUSTOM_FIELDS
¶
Default: ()
(empty tuple)
New in version 0.3.
Modeltranslation supports the fields listed in the
Supported Fields Matrix. In most cases subclasses of the supported
fields will work fine, too. Unsupported fields will throw an
ImproperlyConfigured
exception.
The list of supported fields can be extended by defining a tuple of field
names in your settings.py
.
Example:
MODELTRANSLATION_CUSTOM_FIELDS = ('MyField', 'MyOtherField',)
Warning
This just prevents modeltranslation from throwing an
ImproperlyConfigured
exception. Any unsupported field will most
likely fail in one way or another. The feature is considered experimental
and might be replaced by a more sophisticated mechanism in future versions.
MODELTRANSLATION_AUTO_POPULATE
¶
Default: False
New in version 0.5.
This setting controls if the Multilingual Manager should automatically
populate language field values in its create
and get_or_create
method, and in model
constructors, so that these two blocks of statements can be considered equivalent:
News.objects.populate(True).create(title='-- no translation yet --')
with auto_populate(True):
q = News(title='-- no translation yet --')
# same effect with MODELTRANSLATION_AUTO_POPULATE == True:
News.objects.create(title='-- no translation yet --')
q = News(title='-- no translation yet --')
Possible modes are listed here.
MODELTRANSLATION_DEBUG
¶
Default: False
New in version 0.4.
Changed in version 0.7.
Used for modeltranslation related debug output. Currently setting it to
False
will just prevent Django’s development server from printing the
Registered xx models for translation
message to stdout.
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.py
in 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.
New 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¶
New 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)¶
New 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.LANGUAGES
orsettings.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 makemigrations
to create a new migration with the added or removed fields.python manage.py migrate
to apply the changes.
Note
Support for migrations is implemented through
fields.TranslationField.deconstruct(self)
and respects changes to the
null
option.
Required fields¶
New 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.
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',)}
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 |
No | No | No |
BigIntegerField |
No | Yes* | Yes* |
BooleanField |
No | Yes | Yes |
CharField |
Yes | Yes | Yes |
CommaSeparatedIntegerField |
No | Yes | Yes |
DateField |
No | Yes | Yes |
DateTimeField |
No | Yes | Yes |
DecimalField |
No | Yes | Yes |
EmailField |
Yes* | Yes* | Yes* |
FileField |
Yes | Yes | Yes |
FilePathField |
Yes* | Yes* | Yes* |
FloatField |
No | Yes | Yes |
ImageField |
Yes | Yes | Yes |
IntegerField |
No | Yes | Yes |
IPAddressField |
No | Yes | Yes |
GenericIPAddressField |
No | Yes | Yes |
NullBooleanField |
No | Yes | Yes |
PositiveIntegerField |
No | Yes* | Yes* |
PositiveSmallIntegerField |
No | Yes* | Yes* |
SlugField |
Yes* | Yes* | Yes* |
SmallIntegerField |
No | Yes* | Yes* |
TextField |
Yes | Yes | Yes |
TimeField |
No | Yes | Yes |
URLField |
Yes* | Yes* | Yes* |
ForeignKey |
No | No | Yes |
OneToOneField |
No | No | Yes |
ManyToManyField |
No | No | No |
* Implicitly supported (as subclass of a supported field)
Accessing Translated and Translation Fields¶
Modeltranslation changes the behaviour of the translated fields. To
explain this consider the news example from the Registering Models for Translation chapter
again. The original News
model looked like this:
class News(models.Model):
title = models.CharField(max_length=255)
text = models.TextField()
Now that it is registered with modeltranslation the model looks like this - note the additional fields automatically added by the app:
class News(models.Model):
title = models.CharField(max_length=255) # original/translated field
title_de = models.CharField(null=True, blank=True, max_length=255) # default translation field
title_en = models.CharField(null=True, blank=True, max_length=255) # translation field
text = models.TextField() # original/translated field
text_de = models.TextField(null=True, blank=True) # default translation field
text_en = models.TextField(null=True, blank=True) # translation field
The example above assumes that the default language is de
, therefore the
title_de
and text_de
fields are marked as the default translation
fields. If the default language is en
, the title_en
and text_en
fields would be the default translation fields.
Rules for Translated Field Access¶
Changed in version 0.5.
So now when it comes to setting and getting the value of the original and the translation fields the following rules apply:
Rule 1
Reading the value from the original field returns the value translated to the current language.
Rule 2
Assigning a value to the original field updates the value in the associated current language translation field.
Rule 3
If both fields - the original and the current language translation field - are updated at the same time, the current language translation field wins.
Note
This can only happen in the model’s constructor or
objects.create
. There is no other situation which can be considered changing several fields at the same time.
Examples for Translated Field Access¶
Because the whole point of using the modeltranslation app is translating
dynamic content, the fields marked for translation are somehow special when it
comes to accessing them. The value returned by a translated field is depending
on the current language setting. “Language setting” is referring to the Django
set_language view and the corresponding get_lang
function.
Assuming the current language is de
in the news example from above, the
translated title
field will return the value from the title_de
field:
# Assuming the current language is "de"
n = News.objects.all()[0]
t = n.title # returns german translation
# Assuming the current language is "en"
t = n.title # returns english translation
This feature is implemented using Python descriptors making it happen without
the need to touch the original model classes in any way. The descriptor uses
the django.utils.i18n.get_language
function to determine the current
language.
Todo
Add more examples.
Multilingual Manager¶
New in version 0.5.
Every model registered for translation is patched so that all its managers become subclasses
of MultilingualManager
(of course, if a custom manager was defined on the model, its
functions will be retained). MultilingualManager
simplifies language-aware queries,
especially on third-party apps, by rewriting query field names.
Every model’s manager is patched, not only objects
(even managers inherited from abstract base
classes).
For example:
# Assuming the current language is "de",
# these queries returns the same objects
news1 = News.objects.filter(title__contains='enigma')
news2 = News.objects.filter(title_de__contains='enigma')
assert news1 == news2
It works as follow: if the translation field name is used (title
), it is changed into the
current language field name (title_de
or title_en
, depending on the current active
language).
Any language-suffixed names are left untouched (so title_en
wouldn’t change,
no matter what the current language is).
Rewriting of field names works with operators (like __in
, __ge
) as well as with
relationship spanning. Moreover, it is also handled on Q
and F
expressions.
These manager methods perform rewriting:
filter()
,exclude()
,get()
order_by()
update()
only()
,defer()
values()
,values_list()
, with fallback mechanismdates()
select_related()
create()
, with optional auto-population feature
In order not to introduce differences between X.objects.create(...)
and X(...)
, model
constructor is also patched and performs rewriting of field names prior to regular initialization.
If one wants to turn rewriting of field names off, this can be easily achieved with
rewrite(mode)
method. mode
is a boolean specifying whether rewriting should be applied.
It can be changed several times inside a query. So X.objects.rewrite(False)
turns rewriting off.
MultilingualManager
offers one additional method: raw_values
. It returns actual values from
the database, without field names rewriting. Useful for checking translated field database value.
Auto-population¶
Changed in version 0.6.
There is special manager method populate(mode)
which can trigger create()
or
get_or_create()
to populate all translation (language) fields with values from translated
(original) ones. It can be very convenient when working with many languages. So:
x = News.objects.populate(True).create(title='bar')
is equivalent of:
x = News.objects.create(title_en='bar', title_de='bar') ## title_?? for every language
Moreover, some fields can be explicitly assigned different values:
x = News.objects.populate(True).create(title='-- no translation yet --', title_de='enigma')
It will result in title_de == 'enigma'
and other title_?? == '-- no translation yet --'
.
There is another way of altering the current population status, an auto_populate
context
manager:
from modeltranslation.utils import auto_populate
with auto_populate(True):
x = News.objects.create(title='bar')
Auto-population takes place also in model constructor, what is extremely useful when loading non-translated fixtures. Just remember to use the context manager:
with auto_populate(): # True can be ommited
call_command('loaddata', 'fixture.json') # Some fixture loading
z = News(title='bar')
print(z.title_en, z.title_de) # prints 'bar bar'
There is a more convenient way than calling populate
manager method or entering
auto_populate
manager context all the time:
MODELTRANSLATION_AUTO_POPULATE setting.
It controls the default population behaviour.
Auto-population modes¶
There are four different population modes:
False
[set by default]
Auto-population turned off
True
or'all'
[default argument to population altering methods]
Auto-population turned on, copying translated field value to all other languages (unless a translation field value is provided)
'default'
- Auto-population turned on, copying translated field value to default language field (unless its value is provided)
'required'
- Acts like
'default'
, but copy value only if the original field is non-nullable
Falling back¶
Modeltranslation provides a mechanism to control behaviour of data access in case of empty
translation values. This mechanism affects field access, as well as values()
and values_list()
manager methods.
Consider the News
example: a creator of some news hasn’t specified its German title and
content, but only English ones. Then if a German visitor is viewing the site, we would rather show
him English title/content of the news than display empty strings. This is called fallback.
news.title_en = 'English title'
news.title_de = ''
print(news.title)
# If current active language is German, it should display the title_de field value ('').
# But if fallback is enabled, it would display 'English title' instead.
# Similarly for manager
news.save()
print(News.objects.filter(pk=news.pk).values_list('title', flat=True)[0])
# As above: if current active language is German and fallback to English is enabled,
# it would display 'English title'.
There are several ways of controlling fallback, described below.
Fallback languages¶
New in version 0.5.
MODELTRANSLATION_FALLBACK_LANGUAGES setting allows to set the order of fallback
languages. By default that’s the DEFAULT_LANGUAGE
.
For example, setting
MODELTRANSLATION_FALLBACK_LANGUAGES = ('en', 'de', 'fr')
means: if current active language field value is unset, try English value. If it is also unset, try German, and so on - until some language yields a non-empty value of the field.
There is also an option to define a fallback by language, using dict syntax:
MODELTRANSLATION_FALLBACK_LANGUAGES = {
'default': ('en', 'de', 'fr'),
'fr': ('de',),
'uk': ('ru',)
}
The default
key is required and its value denote languages which are always tried at the end.
With such a setting:
- for uk the order of fallback languages is:
('ru', 'en', 'de', 'fr')
- for fr the order of fallback languages is:
('de', 'en')
- Note, that fr obviously is not a fallback, since its active language and de would be tried before en - for en and de the fallback order is
('de', 'fr')
and('en', 'fr')
, respectively - for any other language the order of fallback languages is just
('en', 'de', 'fr')
What is more, fallback languages order can be overridden per model, using TranslationOptions
:
class NewsTranslationOptions(TranslationOptions):
fields = ('title', 'text',)
fallback_languages = {'default': ('fa', 'km')} # use Persian and Khmer as fallback for News
Dict syntax is only allowed there.
New in version 0.6.
Even more, all fallbacks may be switched on or off for just some exceptional block of code using:
from modeltranslation.utils import fallbacks
with fallbacks(False):
# Work with values for the active language only
Fallback values¶
New in version 0.4.
But what if current language and all fallback languages yield no field value? Then modeltranslation will use the field’s fallback value, if one was defined.
Fallback values are defined in TranslationOptions
, for example:
class NewsTranslationOptions(TranslationOptions):
fields = ('title', 'text',)
fallback_values = _('-- sorry, no translation provided --')
In this case, if title is missing in active language and any of fallback languages, news title
will be '-- sorry, no translation provided --'
(maybe translated, since gettext is used).
Empty text will be handled in same way.
Fallback values can be also customized per model field:
class NewsTranslationOptions(TranslationOptions):
fields = ('title', 'text',)
fallback_values = {
'title': _('-- sorry, this news was not translated --'),
'text': _('-- please contact our translator (translator@example.com) --')
}
If current language and all fallback languages yield no field value, and no fallback values are defined, then modeltranslation will use the field’s default value.
Fallback undefined¶
New in version 0.7.
Another question is what do we consider “no value”, on what value should we fall back to other translations? For text fields the empty string can usually be considered as the undefined value, but other fields may have different concepts of empty or missing values.
Modeltranslation defaults to using the field’s default value as the undefined value (the empty
string for non-nullable CharFields
). This requires calling get_default
for every field
access, which in some cases may be expensive.
If you’d like to fall back on a different value or your default is expensive to calculate, provide a custom undefined value (for a field or model):
class NewsTranslationOptions(TranslationOptions):
fields = ('title', 'text',)
fallback_undefined = {
'title': 'no title',
'text': None
}
The State of the Original Field¶
Changed in version 0.5.
Changed in version 0.12.
As defined by the Rules for Translated Field Access, accessing the original field is guaranteed to work on the associated translation field of the current language. This applies to both, read and write operations.
The actual field value (which can still be accessed through
instance.__dict__['original_field_name']
) however has to be considered
undetermined once the field has been registered for translation.
Attempts to keep the value in sync with either the default or current
language’s field value has raised a boatload of unpredictable side effects in
older versions of modeltranslation.
Since version 0.12 the original field is expected to have even more undetermined value. It’s because Django 1.10 changed the way deferred fields work.
Warning
Do not rely on the underlying value of the original field in any way!
Todo
Perhaps outline effects this might have on the update_translation_field
management command.
ModelForms¶
ModelForms
for multilanguage models are defined and handled as typical ModelForms
.
Please note, however, that they shouldn’t be defined next to models
(see a note).
Editing multilanguage models with all translation fields in the admin backend is quite sensible.
However, presenting all model fields to the user on the frontend may be not the right way.
Here comes the TranslationModelForm
which strip out all translation fields:
from news.models import News
from modeltranslation.forms import TranslationModelForm
class MyForm(TranslationModelForm):
class Meta:
model = News
Such a form will contain only original fields (title, text - see example). Of course, upon saving, provided values would be set on proper attributes, depending on the user current language.
Formfields and nullability¶
New in version 0.7.1.
Note
Please remember that all translation fields added to model definition are nullable
(null=True
), regardless of the original field nullability.
In most cases formfields for translation fields behave as expected. However, there is one annoying
problem with models.CharField
- probably the most commonly translated field type.
The problem is that default formfield for CharField
stores empty values as empty strings
(''
), even if the field is nullable
(see django ticket #9590).
Thus formfields for translation fields are patched by modeltranslation. The following rules apply:
- If the original field is not nullable, an empty value is saved as
''
; - If the original field is nullable, an empty value is saved as
None
.
To deal with complex cases, these rules can be overridden per model or even per field
using TranslationOptions
:
class NewsTranslationOptions(TranslationOptions):
fields = ('title', 'text',)
empty_values = None
class ProjectTranslationOptions(TranslationOptions):
fields = ('name', 'slug', 'description',)
empty_values = {'name': '', 'slug': None}
If a field is not mentioned while using dict syntax, the default rules apply.
This configuration is especially useful for fields with unique constraints:
class Category(models.Model):
name = models.CharField(max_length=40)
slug = models.SlugField(max_length=30, unique=True)
Because the slug
field is not nullable, its translation fields would store empty values as
''
and that would result in an error when two or more Categories
are saved with
slug_en
empty - unique constraints wouldn’t be satisfied. Instead, None
should be stored,
as several None
values in the database don’t violate uniqueness:
class CategoryTranslationOptions(TranslationOptions):
fields = ('name', 'slug')
empty_values = {'slug': None}
None-checkbox widget¶
Maybe there is a situation where you want to store both - empty strings and None
values - in a field. For such a scenario there is a third configuration value: 'both'
:
class NewsTranslationOptions(TranslationOptions):
fields = ('title', 'text',)
empty_values = {'title': None, 'text': 'both'}
It results in a special widget with a None-checkbox to null a field. It’s not recommended in frontend as users may be confused what this None is. The only useful place for this widget might be the admin backend; see Formfields with None-checkbox.
To sum it up, the valid values for empty_values
are: None
, ''
and 'both'
.
Django Admin Integration¶
In order to be able to edit the translations via the django.contrib.admin
application you need to register a special admin class for the translated
models. The admin class must derive from
modeltranslation.admin.TranslationAdmin
which does some funky
patching on all your models registered for translation. Taken the
news example the most simple case would look like:
from django.contrib import admin
from news.models import News
from modeltranslation.admin import TranslationAdmin
class NewsAdmin(TranslationAdmin):
pass
admin.site.register(News, NewsAdmin)
Tweaks Applied to the Admin¶
formfield_for_dbfield¶
The TranslationBaseModelAdmin
class, which TranslationAdmin
and all
inline related classes in modeltranslation derive from, implements a special
method which is formfield_for_dbfield(self, db_field, **kwargs)
. This
method does the following:
- Copies the widget of the original field to each of its translation fields.
- Checks if the original field was required and if so makes the default translation field required instead.
get_form/get_fieldsets¶
In addition the TranslationBaseModelAdmin
class overrides get_form
and
get_fieldsets
to make the options fields
,
exclude
and fieldsets
work in a transparent way. It basically does:
- Removes the original field from every admin form by adding it to
exclude
under the hood. - Replaces the - now removed - original fields with their corresponding translation fields.
Taken the fieldsets
option as an example, where the title
field is
registered for translation but not the news
field:
class NewsAdmin(TranslationAdmin):
fieldsets = [
(u'News', {'fields': ('title', 'news',)})
]
In this case get_fieldsets
will return a patched fieldset which contains
the translation fields of title
, but not the original field:
>>> a = NewsAdmin(NewsModel, site)
>>> a.get_fieldsets(request)
[(u'News', {'fields': ('title_de', 'title_en', 'news',)})]
TranslationAdmin in Combination with Other Admin Classes¶
If there already exists a custom admin class for a translated model and you don’t want or can’t edit that class directly there is another solution.
Taken a reusable blog app which defines a model Entry
and a
corresponding admin class called EntryAdmin
. This app is not yours and you
don’t want to touch it at all.
In the most common case you simply make use of Python’s support for multiple inheritance like this:
class MyTranslatedEntryAdmin(EntryAdmin, TranslationAdmin):
pass
The class is then registered for the admin.site
(not to be confused with
modeltranslation’s translator
). If EntryAdmin
is already registered
through the blog app, it has to be unregistered first:
admin.site.unregister(Entry)
admin.site.register(Entry, MyTranslatedEntryAdmin)
Admin Classes that Override formfield_for_dbfield
¶
In a more complex setup the original EntryAdmin
might override
formfield_for_dbfield
itself:
class EntryAdmin(model.Admin):
def formfield_for_dbfield(self, db_field, **kwargs):
# does some funky stuff with the formfield here
Unfortunately the first example won’t work anymore because Python can only
execute one of the formfield_for_dbfield
methods. Since both admin classes
implement this method Python must make a decision and it chooses the first
class EntryAdmin
. The functionality from TranslationAdmin
will not be
executed and translation in the admin will not work for this class.
But don’t panic, here’s a solution:
class MyTranslatedEntryAdmin(EntryAdmin, TranslationAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(MyTranslatedEntryAdmin, self).formfield_for_dbfield(db_field, **kwargs)
self.patch_translation_field(db_field, field, **kwargs)
return field
This implements the formfield_for_dbfield
such that both functionalities
will be executed. The first line calls the superclass method which in this case
will be the one of EntryAdmin
because it is the first class inherited from.
The TranslationAdmin
capsulates its functionality in the
patch_translation_field
method and the formfield_for_dbfield
implementation of the TranslationAdmin
class simply calls it. You can copy
this behaviour by calling it from a custom admin class and that’s done in the
example above. After that the field
is fully patched for translation and
finally returned.
Admin Inlines¶
New in version 0.2.
Support for tabular and stacked inlines, common and generic ones.
A translated inline must derive from one of the following classes:
modeltranslation.admin.TranslationTabularInline
modeltranslation.admin.TranslationStackedInline
modeltranslation.admin.TranslationGenericTabularInline
modeltranslation.admin.TranslationGenericStackedInline
Just like TranslationAdmin
these classes implement a special method
formfield_for_dbfield
which does all the patching.
For our example we assume that there is a new model called Image
. The
definition is left out for simplicity. Our News
model inlines the new
model:
from django.contrib import admin
from news.models import Image, News
from modeltranslation.admin import TranslationTabularInline
class ImageInline(TranslationTabularInline):
model = Image
class NewsAdmin(admin.ModelAdmin):
list_display = ('title',)
inlines = [ImageInline,]
admin.site.register(News, NewsAdmin)
Note
In this example only the Image
model is registered in
translation.py
. It’s not a requirement that NewsAdmin
derives from
TranslationAdmin
in order to inline a model which is registered for
translation.
Complex Example with Admin Inlines¶
In this more complex example we assume that the News
and Image
models
are registered in translation.py
. The News
model has an own custom
admin class called NewsAdmin
and the Image
model an own generic stacked
inline class called ImageInline
. Furthermore we assume that NewsAdmin
overrides formfield_for_dbfield
itself and the admin class is already
registered through the news app.
Note
The example uses the technique described in TranslationAdmin in combination with other admin classes.
Bringing it all together our code might look like this:
from django.contrib import admin
from news.admin import ImageInline
from news.models import Image, News
from modeltranslation.admin import TranslationAdmin, TranslationGenericStackedInline
class TranslatedImageInline(ImageInline, TranslationGenericStackedInline):
model = Image
class TranslatedNewsAdmin(NewsAdmin, TranslationAdmin):
inlines = [TranslatedImageInline,]
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(TranslatedNewsAdmin, self).formfield_for_dbfield(db_field, **kwargs)
self.patch_translation_field(db_field, field, **kwargs)
return field
admin.site.unregister(News)
admin.site.register(News, NewsAdmin)
Using Tabbed Translation Fields¶
New in version 0.3.
Modeltranslation supports separation of translation fields via jquery-ui tabs.
The proposed way to include it is through the inner Media
class of a
TranslationAdmin
class like this:
class NewsAdmin(TranslationAdmin):
class Media:
js = (
'modeltranslation/js/force_jquery.js',
'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.24/jquery-ui.min.js',
'modeltranslation/js/tabbed_translation_fields.js',
)
css = {
'screen': ('modeltranslation/css/tabbed_translation_fields.css',),
}
Note
Here we stick to the jquery library shipped with Django. The
force_jquery.js
script is necessary when using Django’s built-in
django.jQuery
object. Otherwise the normal jQuery
object won’t
be available to the included (non-namespaced) jquery-ui library.
Standard jquery-ui theming can be used to customize the look of tabs, the provided css file is supposed to work well with a default Django admin.
As an alternative, if want to use a more recent version of jquery, you can do so
by including this in your Media
class instead:
class NewsAdmin(TranslationAdmin):
class Media:
js = (
'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js',
'http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js',
'modeltranslation/js/tabbed_translation_fields.js',
)
css = {
'screen': ('modeltranslation/css/tabbed_translation_fields.css',),
}
Tabbed Translation Fields Admin Classes¶
New in version 0.7.
To ease the inclusion of the required static files for tabbed translation fields, the following admin classes are provided:
TabbedDjangoJqueryTranslationAdmin
(aliased toTabbedTranslationAdmin
)TabbedExternalJqueryTranslationAdmin
Rather than inheriting from TranslationAdmin
, simply subclass one of these
classes like this:
class NewsAdmin(TabbedTranslationAdmin):
pass
TranslationAdmin
Options¶
TranslationAdmin.group_fieldsets
¶
New in version 0.6.
When this option is activated untranslated and translation fields are grouped
into separate fieldsets. The first fieldset contains the untranslated fields,
followed by a fieldset for each translation field. The translation field
fieldsets use the original field’s verbose_name
as a label.
Activating the option is a simple way to reduce the visual clutter one might experience when mixing these different types of fields.
The group_fieldsets
option expects a boolean. By default fields are not
grouped into fieldsets (group_fieldsets = False
).
A few simple policies are applied:
- A
fieldsets
option takes precedence over thegroup_fieldsets
option.- Other default
ModelAdmin
options likeexclude
are respected.
class NewsAdmin(TranslationAdmin):
group_fieldsets = True
Formfields with None-checkbox¶
There is the special widget which allow to choose whether empty field value should be stores as
empty string or None
(see None-checkbox widget).
In TranslationAdmin
some fields can use this widget regardless of their empty_values
setting:
class NewsAdmin(TranslationAdmin):
both_empty_values_fields = ('title', 'text')
Management Commands¶
The update_translation_fields
Command¶
In case modeltranslation was installed in an existing project and you have specified to translate fields of models which are already synced to the database, you have to update your database schema (see Committing fields to database).
Unfortunately the newly added translation fields on the model will be empty
then, and your templates will show the translated value of the fields (see
Rule 1) which will be empty in this case. To correctly initialize
the default translation field you can use the update_translation_fields
command:
$ python manage.py update_translation_fields
Taken the news example used throughout the documentation this command will copy
the value from the news object’s title
field to the translation
field title_de
. It only does so if the translation field is empty
otherwise nothing is copied.
On default, only the default language will have its translation field populated,
but you can provide a --language
option to specify any other language listed
in settings.py
.
Note
Unless you configured modeltranslation to
override the default language
the command will examine your settings.LANGUAGES
variable and the first
language declared there will be used as the default language.
All translated models (as specified in the translation files) from all apps will be populated with initial data.
Optionally, an app label and model name may be passed to populate only a subset of translated models.
$ python manage.py update_translation_fields myapp
$ python manage.py update_translation_fields myapp mymodel
The sync_translation_fields
Command¶
New in version 0.4.
$ python manage.py sync_translation_fields
This command compares the database and translated models definitions (finding new translation
fields) and provides SQL statements to alter tables. You should run this command after adding
a new language to your settings.LANGUAGES
or a new field to the TranslationOptions
of
a registered model.
However, if you are using South in your project, in most cases it’s recommended to use migration
instead of sync_translation_fields
. See Committing fields to database for detailed info and use cases.
The loaddata
Command¶
New in version 0.7.
An extended version of Django’s original loaddata
command which adds an optional
populate
keyword. If the keyword is specified, the normal loading command will be
run under the selected auto-population modes.
By default no auto-population is performed.
$ python manage.py loaddata --populate=all fixtures.json
Allowed modes are listed here. To choose False
(turn off auto-population) specify '0'
or 'false'
:
$ python manage.py loaddata --populate=false fixtures.json
$ python manage.py loaddata --populate=0 fixtures.json
Note
If populate
is not specified, the current auto-population mode is used. Current means
the one set by settings.
Moreover, this loaddata
command version can override the nasty habit of changing locale to
en-us. By default, it will retain the proper locale. To get the old behaviour back, set
settings-modeltranslation_loaddata_retain_locale to False
.
Caveats¶
Accessing Translated Fields Outside Views¶
Since the modeltranslation mechanism relies on the current language as it
is returned by the get_language
function care must be taken when accessing
translated fields outside a view function.
Within a view function the language is set by Django based on a flexible model described at How Django discovers language preference which is normally used only by Django’s static translation system.
When a translated field is accessed in a view function or in a template, it
uses the django.utils.translation.get_language
function to determine the
current language and return the appropriate value.
Outside a view (or a template), i.e. in normal Python code, a call to the
get_language
function still returns a value, but it might not what you
expect. Since no request is involved, Django’s machinery for discovering the
user’s preferred language is not activated. For this reason modeltranslation
adds a thin wrapper (modeltranslation.utils.get_language
) around the function
which guarantees that the returned language is listed in the LANGUAGES
setting.
The unittests use the django.utils.translation.trans_real
functions to
activate and deactive a specific language outside a view function.
Using in combination with django-audit-log
¶
django-audit-log
is a package that allows you to track changes to your
model instances (documentation). As django-audit-log
behind the scenes
automatically creates “shadow” models for your tracked models, you have to
remember to register these shadow models for translation as well as your
regular models. Here’s an example:
from modeltranslation.translator import register, TranslationOptions
from my_app import models
@register(models.MyModel)
@register(models.MyModel.audit_log.model)
class MyModelTranslationOptions(TranslationOptions):
"""Translation options for MyModel."""
fields = (
'text',
'title',
)
If you forget to register the shadow models, you will get an error like:
TypeError: 'text_es' is an invalid keyword argument for this function
Using in combination with django-rest-framework
¶
When creating a new viewset , make sure to override get_queryset
method, using queryset
as a property won’t work because it is being evaluated once, before any language was set.
Translating ManyToManyField
fields¶
Translated ManyToManyField
fields do not support fallbacks. This is because the field descriptor returns a Manager
when accessed. If falbacks were enabled we could find ourselves using the manager of a different language than the current one without realizing it. This can lead to using the .set()
method on the wrong language.
Due to this behavior the fallbacks on M2M fields have been disabled.
How to Contribute¶
There are various ways how you can contribute to the project.
Contributing Code¶
The preferred way for code contributions are pull requests at Github, usually created against master.
Use [Convential commits](https://www.conventionalcommits.org/en/v1.0.0/) for commit messages.
Note
In order to be properly blamed for a contribution, please verify that the email you commit with is connected to your Github account (see help.github.com for details).
Coding Style¶
Please make sure that your code follows the PEP 8 style guide. The only exception we make is to allow a maximum line length of 100. Furthermore your code has to validate against pyflakes. It is recommended to use flake8 which combines all the checks, and black for code formatting.
$ flake8 modeltranslation
$ black modeltranslation *.py
The #NOQA
mark added by flake8 should be used sparsely.
Django and Python Versions¶
We always try to support at least the two latest major versions of Django, as well as Django’s development version. While we can not guarantee the latter to be supported in early development stages of a new Django version, we aim to achieve support once it has seen its first release candidate.
The supported Python versions can be derived from the supported Django versions. Example (from the past) where we support Python 2.5, 2.6 and 2.7:
- Django 1.3 (old stable) supports Python 2.5, 2.6, 2.7
- Django 1.4 (current stable) supports Python 2.5, 2.6, 2.7
- Django 1.5 (dev) supports Python 2.6, 2.7
Python 3 is supported since 0.7 release. Although 0.6 release supported Django 1.5 (which started Python 3 compliance), it was not Python 3 ready yet.
Unittests¶
To test Modeltranslation, you can use the comprehensive test suite that comes with the package. First, make sure you have installed the project’s requirements using Poetry. Once the requirements are installed, you can run the tests using pytest. This will run all of the tests in the test suite and report any failures or errors.
$ pip install poetry
$ poetry install
$ poetry run pytest
Non trivial changes and new features should always be accompanied by a unittest. Pull requests which add unittests for uncovered code or rare edge cases are also appreciated.
Continuous Integration¶
The project uses Github Actions for continuous integration tests. Hooks provided by Github are active, so that each push and pull request is automatically run against our Github Actions Workflows, checking code against different databases, Python and Django versions. This includes automatic tracking of test coverage through Coveralls.

Contributing Documentation¶
Documentation is a crucial part of any open source project. We try to make it as useful as possible for both, new and experienced developers. If you feel that something is unclear or lacking, your help to improve it is highly appreciated.
Even if you don’t feel comfortable enough to document modeltranslation’s usage or internals, you still have a chance to contribute. None of the core committers is a native english speaker and bad grammar or misspellings happen. If you find any of these kind or just simple typos, nobody will feel offended for getting an English lesson.
The documentation is written using reStructuredText and Sphinx. You should try to keep a maximum line length of 80 characters. Unlike for code contribution this isn’t a forced rule and easily exceeded by something like a long url.
Using the Issue Tracker¶
When you have found a bug or want to request a new feature for modeltranslation, please create a ticket using the project’s issue tracker. Your report should include as many details as possible, like a traceback in case you get one.
Please do not use the issue tracker for general questions, we run a dedicated mailing list for this.
ChangeLog¶
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [0.18.12](https://github.com/deschler/django-modeltranslation/compare/v0.18.11...v0.18.12) (2023-09-08)
### Features
* Support language-specific field defaults ([2657de7](https://github.com/deschler/django-modeltranslation/commit/2657de7c2ebd6523a31ab04ba9453c715b0c34f3)), closes [#700](https://github.com/deschler/django-modeltranslation/issues/700) [#698](https://github.com/deschler/django-modeltranslation/issues/698)
### [0.18.11](https://github.com/deschler/django-modeltranslation/compare/v0.18.10...v0.18.11) (2023-07-16)
### Features
* extend update_fields with translation fields in Model.save() ([#687](https://github.com/deschler/django-modeltranslation/issues/687)) ([d86c6de](https://github.com/deschler/django-modeltranslation/commit/d86c6defc864b3493955a41f95a85fc5aa8d5649))
### [0.18.10](https://github.com/deschler/django-modeltranslation/compare/v0.18.10-beta.0...v0.18.10) (2023-06-02)
### Bug Fixes
* Add support for JSONField ([25f7305](https://github.com/deschler/django-modeltranslation/commit/25f73058f5f176a61c5368b7aee563874309687e)), closes [#685](https://github.com/deschler/django-modeltranslation/issues/685)
### [0.18.10-beta.1](https://github.com/deschler/django-modeltranslation/compare/v0.18.10-beta.0...v0.18.10-beta.1) (2023-06-02)
### Bug Fixes
* Add support for JSONField ([25f7305](https://github.com/deschler/django-modeltranslation/commit/25f73058f5f176a61c5368b7aee563874309687e)), closes [#685](https://github.com/deschler/django-modeltranslation/issues/685)
### [0.18.10-beta.1](https://github.com/deschler/django-modeltranslation/compare/v0.18.10-beta.0...v0.18.10-beta.1) (2023-06-02)
### [0.18.10-beta.0](https://github.com/deschler/django-modeltranslation/compare/v0.18.9...v0.18.10-beta.0) (2023-05-30)
### Bug Fixes
* Fix update_or_create for Django 4.2 ([d5eefa8](https://github.com/deschler/django-modeltranslation/commit/d5eefa8bd193cd8aee1cd1f97561d2a7e9dc0801)), closes [#682](https://github.com/deschler/django-modeltranslation/issues/682) [#683](https://github.com/deschler/django-modeltranslation/issues/683)
### [0.18.9](https://github.com/deschler/django-modeltranslation/compare/v0.18.8...v0.18.9) (2023-02-09)
### Bug Fixes
* Fix handling of expressions in `values()`/`values_list()` ([d65ff60](https://github.com/deschler/django-modeltranslation/commit/d65ff60007d4088b1f483edd2df85f407be3b5de)), closes [#670](https://github.com/deschler/django-modeltranslation/issues/670)
### [0.18.8](https://github.com/deschler/django-modeltranslation/compare/v0.18.8-beta.1...v0.18.8) (2023-02-01)
### [0.18.8-beta.1](https://github.com/deschler/django-modeltranslation/compare/v0.18.8-beta.0...v0.18.8-beta.1) (2023-01-27)
### Features
* Add support for ManyToManyFields 🧑🤝🧑 ([#668](https://github.com/deschler/django-modeltranslation/issues/668)) ([f69e317](https://github.com/deschler/django-modeltranslation/commit/f69e3172bc6254a4ddd8def7500632d0046b30eb))
### Bug Fixes
* **docs:** Update documentation regarding inheritance ([#665](https://github.com/deschler/django-modeltranslation/issues/665)) ([ca31a21](https://github.com/deschler/django-modeltranslation/commit/ca31a21f014b04978188562a0e0e1b58d95923e6)), closes [#663](https://github.com/deschler/django-modeltranslation/issues/663)
### [0.18.8-beta.0](https://github.com/deschler/django-modeltranslation/compare/v0.18.7...v0.18.8-beta.0) (2022-11-22)
### Bug Fixes
* Fix admin widget for fk fields ([#662](https://github.com/deschler/django-modeltranslation/issues/662)) ([fcfbd5c](https://github.com/deschler/django-modeltranslation/commit/fcfbd5ce059e4858a2c8d4803d094285282ad2c9)), closes [#660](https://github.com/deschler/django-modeltranslation/issues/660)
### [0.18.7](https://github.com/deschler/django-modeltranslation/compare/v0.18.6...v0.18.7) (2022-11-08)
### [0.18.6](https://github.com/deschler/django-modeltranslation/compare/v0.18.5...v0.18.6) (2022-11-07)
### Bug Fixes
* Fix unexpected ordering after `values()`/`values_list()` followed by `order_by()`. ([09ce0e0](https://github.com/deschler/django-modeltranslation/commit/09ce0e076ba323432275e28eb16fdb19f37df3e0)), closes [#655](https://github.com/deschler/django-modeltranslation/issues/655) [#656](https://github.com/deschler/django-modeltranslation/issues/656)
### [0.18.5](https://github.com/deschler/django-modeltranslation/compare/v0.18.4...v0.18.5) (2022-10-12)
### Features
* Support UserAdmin add_fieldsets ([d414cd3](https://github.com/deschler/django-modeltranslation/commit/d414cd3e0709622a66260088d2da0ade94a01be1)), closes [#654](https://github.com/deschler/django-modeltranslation/issues/654)
### Bug Fixes
* Fix working in strict mode. ([#649](https://github.com/deschler/django-modeltranslation/issues/649)) ([8ef8afd](https://github.com/deschler/django-modeltranslation/commit/8ef8afd2d7aad71ba185f17c0db95494616f3730))
### [0.18.4](https://github.com/deschler/django-modeltranslation/compare/v0.18.3...v0.18.4) (2022-07-22)
### Bug Fixes
* Update django compatibility ([582b612](https://github.com/deschler/django-modeltranslation/commit/582b612ab5d422bf2cd1f45a28748db60819e85c))
### [0.18.3](https://github.com/deschler/django-modeltranslation/compare/v0.18.3-beta.1...v0.18.3) (2022-07-19)
### Bug Fixes
* Remove six (old compat layer for python2) ([86b67c2](https://github.com/deschler/django-modeltranslation/commit/86b67c271e5fcba94e396acc9efd5e52ced2d1e2))
### [0.18.3-beta.1](https://github.com/deschler/django-modeltranslation/compare/v0.18.3-beta.0...v0.18.3-beta.1) (2022-07-13)
### Features
* **dev:** Migrate to pytest ([d3e2396](https://github.com/deschler/django-modeltranslation/commit/d3e2396be6757f0d0b3ee4e06777c37f17d3834b))
### [0.18.3-beta.0](https://github.com/deschler/django-modeltranslation/compare/v0.18.2...v0.18.3-beta.0) (2022-07-10)
### Features
* Support `named` argument for `values_list` ([#644](https://github.com/deschler/django-modeltranslation/issues/644)) ([39bbe82](https://github.com/deschler/django-modeltranslation/commit/39bbe821b31278b21e0bf3528d036343338bb0f7))
### [0.18.2](https://github.com/deschler/django-modeltranslation/compare/v0.18.1...v0.18.2) (2022-05-15)
### Features
* Update test matrix; Drop python 3.6, add Python 3.10 ([#638](https://github.com/deschler/django-modeltranslation/issues/638)) ([29deb95](https://github.com/deschler/django-modeltranslation/commit/29deb95bf30c0e31c6a031f754677182cdd461a2))
### [0.18.1](https://github.com/deschler/django-modeltranslation/compare/v0.18.0...v0.18.1) (2022-05-15)
### Bug Fixes
* Fix install (included missing VERSION) ([ab66e8d](https://github.com/deschler/django-modeltranslation/commit/ab66e8d2f79c5e7e6f517e53a1698f5113d711bf)), closes [#637](https://github.com/deschler/django-modeltranslation/issues/637)
## [0.18.0](https://github.com/deschler/django-modeltranslation/compare/v0.17.7...v0.18.0) (2022-05-14)
### ⚠ BREAKING CHANGES
* Replaced `VERSION` in tuple format by `__version__` as a string
### Bug Fixes
* Add django version check for default_app_config ([79d2e08](https://github.com/deschler/django-modeltranslation/commit/79d2e089eff2f6bcfd150d3ac6e165bfefa475cb))
* Fix django version detect during install ([876f2e7](https://github.com/deschler/django-modeltranslation/commit/876f2e715804e5cba9f8dde0b8a75ff3179e908c))
* Store version as plain text file to simplify bumping ([#636](https://github.com/deschler/django-modeltranslation/issues/636)) ([6b4bb73](https://github.com/deschler/django-modeltranslation/commit/6b4bb733d971363c223d9d4ff307a0f9be131315))
### [0.17.7](https://github.com/deschler/django-modeltranslation/compare/v0.17.6...v0.17.7) (2022-05-04)
### Bug Fixes
* Do not include annotation fields when selecting specific fields ([#634](https://github.com/deschler/django-modeltranslation/issues/634)) ([defc37c](https://github.com/deschler/django-modeltranslation/commit/defc37c7a539dff1e4af96e7d13856519befe585))
### [0.17.6](https://github.com/deschler/django-modeltranslation/compare/v0.17.5...v0.17.6) (2022-04-29)
### Bug Fixes
* Preserve annotate() fields in queryset ([#633](https://github.com/deschler/django-modeltranslation/issues/633)) ([6f2688f](https://github.com/deschler/django-modeltranslation/commit/6f2688f52c56107da361c7c6197bcf38d8b99f42))
### [0.17.5](https://github.com/deschler/django-modeltranslation/compare/v0.17.4...v0.17.5) (2022-01-30)
### [0.17.4](https://github.com/deschler/django-modeltranslation/compare/v0.17.3...v0.17.4) (2022-01-28)
### Features
* semi-configurable selection of elements to generate tabs in admin ([#607](https://github.com/deschler/django-modeltranslation/issues/607)) ([eb05201](https://github.com/deschler/django-modeltranslation/commit/eb052018bf930146d667be3e47f26d69afb3c2c3))
### [0.17.3](https://github.com/deschler/django-modeltranslation/compare/v0.17.2...v0.17.3) (2021-06-28)
### [0.17.2](https://github.com/deschler/django-modeltranslation/compare/v0.17.1...v0.17.2) (2021-05-31)
### Bug Fixes
* **docs:** Fixed legacy python 2 print statements ([10ec4ed](https://github.com/deschler/django-modeltranslation/commit/10ec4ed8694d949815ccf4ada679a1cb72f24675))
* **MultilingualQuerySet:** Make _clone signature match default django _clone ([c65adb0](https://github.com/deschler/django-modeltranslation/commit/c65adb058d6c60c077138e5099342f31aac1690b)), closes [#483](https://github.com/deschler/django-modeltranslation/issues/483)
### [0.17.1](https://github.com/deschler/django-modeltranslation/compare/v0.16.2...v0.17.1) (2021-04-15)
### Bug Fixes
* Fixed .latest() ORM method with django 3.2 ([eaf613b](https://github.com/deschler/django-modeltranslation/commit/eaf613be1733314ad3b639e1702b0f7423af7899)), closes [#591](https://github.com/deschler/django-modeltranslation/issues/591)
## [0.17.0](https://github.com/deschler/django-modeltranslation/compare/v0.16.2...v0.17.0) (2021-04-15)
### Features
* Add Django 3.2 support
### [0.16.2](https://github.com/deschler/django-modeltranslation/compare/v0.16.1...v0.16.2) (2021-02-18)
### Bug Fixes
* Fix loading for Inline Admin ([c8ea228](https://github.com/deschler/django-modeltranslation/commit/c8ea22877b3f4070ffb4d3d4e602d7ef09ab0860))
### [0.16.1](https://github.com/deschler/django-modeltranslation/compare/v0.16.0...v0.16.1) (2020-11-23)
### Bug Fixes
* missing jquery operator ([7c750de](https://github.com/deschler/django-modeltranslation/commit/7c750def728e163d5bde88fedd1124bd7e9a8122))
## [0.16.0](https://github.com/deschler/django-modeltranslation/compare/v0.15.2...v0.16.0) (2020-10-12)
### ⚠ BREAKING CHANGES
* **js:** It's 2020 already, drop backward compatibility with jquery-ui 1.10.
### Features
* **tabbed-translation-fields:** Make tab with errors visible by default. ([4c2e284](https://github.com/deschler/django-modeltranslation/commit/4c2e284d871044a443817aabfbe3c956799ffe06))
### Bug Fixes
* Fix error detection; add red dot for tab with errors. ([9a93cf6](https://github.com/deschler/django-modeltranslation/commit/9a93cf6b4d4ec24e754159f71cf9d9eda811673e))
* **dev:** Fix install in editable mode. ([aaa2dcf](https://github.com/deschler/django-modeltranslation/commit/aaa2dcf5987e19c2da8460bc73a0681a291f0dc5))
* **js:** It's 2020 already, drop backward compatibility with jquery-ui 1.10. ([d8f432a](https://github.com/deschler/django-modeltranslation/commit/d8f432a5cadd60871101081c87569e3d390474e6))
### [0.15.2](https://github.com/deschler/django-modeltranslation/compare/v0.15.1...v0.15.2) (2020-09-08)
### Features
* Adds a language option to the update_translation_fields commands ([ac91740](https://github.com/deschler/django-modeltranslation/commit/ac91740a5c3d718b8695514da8a0dd7b90aa1ee6)), closes [#563](https://github.com/deschler/django-modeltranslation/issues/563)
### [0.15.1](https://github.com/deschler/django-modeltranslation/compare/v0.15.0...v0.15.1) (2020-07-10)
### Bug Fixes
* **admin:** Fix custom widget initialization problem ([48e7f59](https://github.com/deschler/django-modeltranslation/commit/48e7f598955a09dc4130a0074cb953ecd05d1a01))
## [0.15.0](https://github.com/deschler/django-modeltranslation/compare/0.14.4...0.15.0) (2020-04-22)
### Features
* Use poetry as venv manager ([a5b402c](https://github.com/deschler/django-modeltranslation/commit/a5b402c51673a78a1aa160247746695070e08a2f))
* Drop old python versions (<3.6)
* Drop old django versions (<2.2)
### Bug Fixes
* add NewMultilingualManager __eq__() ([205a8f6](https://github.com/deschler/django-modeltranslation/commit/205a8f6c2f411b8b20235bbf89b88d3781919cbd))
## 0.14.0 (2019-11-14)
### Bug Fixes
* Django 3.0 support (#521)
* Tests when django files not writable (#527)
## 0.13-3 (2019-07-22)
### Bug Fixes
* Broken "Add another inline" (#475)
## 0.13-2 (2019-07-01)
### Bug Fixes
* Outdated formfield_for_dbfield signature (#510)
## 0.13-1 (2019-04-18)
* REMOVED: Python 3.5 from test matrix
* REMOVED: Django 2.0 from test matrix
* FIXED: TabbedTranslationAdmin in django 2.2 (#506)
* ADDED: Django 2.2 to test matrix
## 0.13-0 (2019-02-21)
* ADDED: Django 2.0 and 2.1 support
* ADDED: Python 3.7 support
* REMOVED: Python 3.4 from test matrix
## 0.13-beta3 (2019-02-17)
* FIXED: Patching parent model managers on multi-table inheritance (#467)
## 0.13-beta2 (2019-02-13)
* ADDED: Django 2.1 support
* ADDED: Python 3.7 support
* FIXED: JS errors in admin with new jQuery
## 0.13-beta1 (2018-04-16)
* FIXED: Reverse relations and select_related for Django 2.0.
(resolves issues #436 and #457, thanks to GreyZmeem and dmarcelino)
* FIXED: Multiple fixes for Django 2.0.
(resolves issues #436 and #451, thanks PetrDlouhy)
* ADDED: Add primary support to DISTINCT statement
(resolves issue #368, thanks Virgílio N Santos)
* CHANGED: Check if 'descendants' list has values
(resolves issue #445, thanks Emilie Zawadzki)
## 0.12.2 (2018-01-26)
* FIXED: order_by with expression
(resolves issue #398, thanks Benjamin Toueg)
## 0.12.1 (2017-04-05)
* FIXED: Issue in loaddata management command in combination with Django 1.11.
(resolves issue #401)
## 0.12 (2016-09-20)
* ADDED: Support for Django 1.10.
(resolves issue #360, thanks Jacek Tomaszewski and Primož Kerin)
* CHANGED: Original field value became more unreliable and undetermined;
please make sure you're not using it anywhere. See
http://django-modeltranslation.readthedocs.io/en/latest/usage.html#the-state-of-the-original-field
* CHANGED: Let register decorator return decorated class
(resolves issue #360, thanks spacediver)
* FIXED: Deferred classes signal connection.
(resolves issue #379, thanks Jacek Tomaszewski)
* FIXED: values_list + annotate combo bug.
(resolves issue #374, thanks Jacek Tomaszewski)
* FIXED: Several flake8 and travis related issues.
(resolves issues #363, thanks Matthias K)
## 0.11 (2016-01-31)
Released without changes.
## 0.11rc2 (2015-12-15)
* FIXED: Custom manager in migrations.
(resolves issues #330, #339 and #350, thanks Jacek Tomaszewski)
## 0.11rc1 (2015-12-07)
* ADDED: Support for Django 1.9
(resolves issue #349, thanks Jacek Tomaszewski)
## 0.10.2 (2015-10-27)
* FIXED: Proxy model inheritance for Django >=1.8
(resolves issues #304, thanks Stratos Moros)
## 0.10.1 (2015-09-04)
* FIXED: FallbackValuesListQuerySet.iterator which broke ORM datetimes
(resolves issue #324, thanks Venelin Stoykov)
## 0.10.0 (2015-07-03)
* ADDED: CSS support for bi-directional languages to TranslationAdmin
using mt-bidi class.
(resolves issue #317, thanks oliphunt)
* ADDED: A decorator to handle registration of models.
(resolves issue #318, thanks zenoamaro)
* FIXED: Handled annotation fields when using values_list.
(resolves issue #321, thanks Lukas Lundgren)
## 0.9.1 (2015-05-14)
* FIXED: Handled deprecation of _meta._fill_fields_cache() for Django 1.8
in add_translation_fields.
(resolves issue #304, thanks Mathias Ettinger and Daniel Loeb)
* FIXED: Handled deprecation of transaction.commit_unless_managed for
Django 1.8 in sync_translation_fields management command.
(resolves issue #310)
* FIXED: Fixed translatable fields discovery with the new _meta API and
generic relations for Django 1.8.
(resolves issue #309, thanks Morgan Aubert)
## 0.9 (2015-04-16)
* ADDED: Support for Django 1.8 and the new meta API.
(resolves issue #299, thanks Luca Corti and Jacek Tomaszewski)
## 0.8.1 (2015-04-02)
* FIXED: Using a queryset with select related.
(resolves issue #298, thanks Vladimir Sinitsin)
* FIXED: Added missing jquery browser plugin.
(resolves issue #270, thanks Fabio Caccamo)
* FIXED: Deprecated imports with Django >= 1.7
(resolves issue #283, thanks Alex Marandon)
## 0.8 (2014-10-06)
* FIXED: JavaScript scoping issue with two jQuery versions in tabbed
translation fields.
(resolves issue #267,
thanks Wojtek Ruszczewski)
* ADDED: Patch db_column of translation fields in migration files.
(resolves issue #264,
thanks Thom Wiggers and Jacek Tomaszewski)
* ADDED: Fallback to values and values_list.
(resolves issue #258,
thanks Jacek Tomaszewski)
## 0.8b2 (2014-07-18)
* ADDED: Explicit support for Python 3.4 (should have already worked for
older versions that supported Python 3).
(resolves issue #254)
* ADDED: Support for Django 1.7 migrations.
* FIXED: Dict iteration Exception under Python 3.
(resolves issue #256,
thanks Jacek Tomaszewski)
* FIXED: Reduce usage under Python 3.
(thanks Jacek Tomaszewski)
* FIXED: Support for AppConfigs in INSTALLED_APPS
(resolves issue #252,
thanks Warnar Boekkooi, Jacek Tomaszewski)
* FIXED: Rewrite field names in select_related. Fix deffered models registry.
Rewrite spanned queries on all levels for defer/only.
(resolves issue #248,
thanks Jacek Tomaszewski)
## 0.8b1 (2014-06-22)
* ADDED: Detect custom get_queryset on managers.
(resolves issue #242,
thanks Jacek Tomaszewski)
* ADDED: Support for Django 1.7 and the new app-loading refactor.
(resolves issue #237)
* ADDED: Added required_languages TranslationOptions
(resolves issue #143)
* FIXED: Fixed sync_translation_fields to be compatible with PostgreSQL.
(resolves issue #247,
thanks Jacek Tomaszewski)
* FIXED: Manager .values() with no fields specified behaves as expected.
(resolves issue #247)
* FIXED: Fieldset headers are not capitalized when group_fieldsets is enabled.
(resolves issue #234,
thanks Jacek Tomaszewski)
* FIXED: Exclude for nullable field manager rewriting.
(resolves issue #231,
thanks Jacek Tomaszewski)
* FIXED: Use AVAILABLE_LANGUAGES in sync_translation_fields management
command to detect missing fields.
(resolves issue #227,
thanks Mathieu Leplatre)
* FIXED: Take db_column into account while syncing fields
(resolves issue #225,
thanks Mathieu Leplatre)
* CHANGED: Moved to get_queryset, which resolves a deprecation warning.
(resolves issue #244,
thanks Thom Wiggers)
* CHANGED: Considered iframes in tabbed_translation_fields.js to support
third party apps like django-summernote.
(resolves issue #229,
thanks Francesc Arpí Roca)
* CHANGED: Removed the http protocol from jquery-ui url in admin Media class.
(resolves issue #224,
thanks Francesc Arpí Roca)
## 0.7.3 (2014-01-05)
* ADDED: Documentation for TranslationOptions fields reference and
south/sync_translation_fields.
* FIXED: Some python3 compatibility issues.
(thanks Jacek Tomaszewski,
resolves issue #220)
* FIXED: Clearing translated FileFields does not work with easy_thumbnails.
(thanks Jacek Tomaszewski,
resolves issue #219)
* FIXED: Compatibility with nested inlines.
(thanks abstraktor,
resolves issue #218)
* FIXED: Admin inlines recursion problem in Django 1.6.
(thanks Oleg Prans,
resolves issue #214)
* FIXED: Empty FileField handling.
(thanks Jacek Tomaszewski,
resolves issue #215)
## 0.7.2 (2013-11-11)
* ADDED: Documentation about empty_values.
(thanks Jacek Tomaszewski,
resolves issue #211)
* FIXED: Proxy model handling.
(thanks Jacek Tomaszewsk)
* FIXED: Abstract managers patching.
(thanks Jacek Tomaszewski,
resolves issue #212)
## 0.7.1 (2013-11-07)
Packaged from revision f7c7ea174344f3dc0cf56ac3bf6e92878ed6baea
* ADDED: Configurable formfields. The ultimate approach to nullable CharFields.
(thanks Jacek Tomaszewski,
resolves issue #211, ref #163, #187)
* FIXED: Recursion problem with fieldset handling in Django 1.6.
(thanks to Bas Peschier,
resolves issue #214)
## 0.7 (2013-10-19)
Packaged from revision 89f5e6712aaf5d5ec7e2d61940dc1a71fb08ca94
* ADDED: A setting to control which language are slug fields based on
(thanks to Konrad Wojas,
resolves issue #194)
* ADDED: A noinput option to the sync_translation_fields management command.
(thanks to cuchac,
resolves issues #179 and #184)
* ADDED: Support for Python 3.2 and 3.3.
(thanks to Karol Fuksiewicz,
resolves issue #174)
* ADDED: Convenient admin classes which already contain proper Media
definitions.
(resolves issue #171)
* ADDED: Only, defer, values, values_list, dates, raw_values methods to
MultilingualManager.
(resolves issue #166 adn #173)
* ADDED: Support for ForeignKey and OneToOneField.
(thanks to Braden MacDonald and Jacek Tomaszewski,
resolves issue #161)
* ADDED: An auto-population option to the loaddata command.
(resolves issue #160)
* ADDED: A MODELTRANSLATION_LOADDATA_RETAIN_LOCALE setting for loaddata
command to leave locale alone.
(resolves issue #151)
* FIXED: Compatibility with Django 1.6 development version.
(resolves issue #169)
* FIXED: Handling of 3rd party apps' ModelForms.
(resolves issue #167)
* FIXED: Triggering field fallback on its default value rather than empty
string only. Also enhance nullable fields in forms with proper
widgets to preserve ``None``.
(thanks to Wojtek Ruszczewski,
resolves issue #163)
* FIXED: Admin prepopulated_fields is now handled properly.
(thanks to Rafleze,
resolves issue #181 and #190)
* FIXED: Form saving when translated field is excluded (e.g. in admin)
(resolves issue #183)
* FIXED: Multilingual clones are Multilingual too.
(resolved issue #189)
* CHANGED: Every model's manager is patched as MultiLingual, not only objects.
(resolved issue #198)
* CHANGED: Display "make null" checkboxes in model forms.
* CHANGED: MODELTRANSLATION_DEBUG setting defaults to False instead of
settings.DEBUG.
* CHANGED: Drop support for Python 2.5 and Django 1.3.
## 0.6.1 (2013-03-17)
Packaged from revision fc8a3034897b8b818c74f41c43a92001e536d970
* FIXED: Joined query does not use translated fields.
(resolves issue #162)
## 0.6 (2013-03-01)
Packaged from revision ea0e2db68900371146d39dcdf88b29091ee5222f
* ADDED: A new ENABLE_FALLBACKS setting and a context manager for switching
fallbacks temporarily.
(thanks to Wojtek Ruszczewski,
resolves issue #152)
* ADDED: Major refactoring of the tabbed translation fields javascript. Adds
support for tabular inlines and includes proper handling of stacked
inlines, which have never been officially supported, but were not
actively prevented from being tabbified.
(resolves issue #66)
* ADDED: New group_fieldsets option for TranslationAdmin. When activated
translation fields and untranslated fields are automatically
grouped into fieldsets.
(based on original implementation by Chris Adams,
resolves issues #38)
* FIXED: Tests to run properly in the scope of a Django project.
(thanks to Wojtek Ruszczewski,
resolves issue #153)
* FIXED: Broken tab activation when using jquery-ui 1.10, keeping support for
older jquery-ui versions and the jquery version shipped by Django.
(thanks to Dominique Lederer,
resolves issue #146)
* FIXED: Wrong admin field css class for en-us language.
(resolves issue #141)
* FIXED: Added missing hook for admin readonly_fields.
(resolves issue #140)
* FIXED: Keys used in tabbed translation fields to group translations are not
unique for inlines.
(resolves issue #121)
* FIXED: The prepopulated_fields TranslationAdmin option only works on the
first defined field to prepopulate from and made the option aware
of the current language.
(resolves issue #57)
* CHANGED: Removed deprecated MODELTRANSLATION_TRANSLATION_REGISTRY setting.
* CHANGED: Refactored auto population manager functionality. Switched to a
populate method in favour of the old _populate keyword and added a new
contextmanager to switch the population mode on demand.
(thanks to Wojtek Ruszczewski,
resolves issue #145)
* CHANGED: Major refactoring of translation field inheritance and
TranslationOptions.
(thanks to Wojtek Ruszczewski,
resolves issues #50 and #136)
## 0.5 (2013-02-10)
Packaged from revision bedd18ea9e338b133d06f2ed5e7ebfc2e21fd276
* ADDED: Merged autodiscover tests from django-modeltranslation-wrapper.
* ADDED: Rewrite method to MultilingualManager and optimized create.
* FIXED: grouped_translations are computed twice in tabbed translations.
(thanks to Wojtek Ruszczewski,
resolves issue #135)
* FIXED: CSS classes in tabbed translation fields when fieldname has a leading
underscore.
(thanks to Wojtek Ruszczewski,
resolves issue #134)
* FIXED: Rewriting of descending ('-' prefixed) ordering fields in
MultilingualManager.
(thanks to Wojtek Ruszczewski,
resolves issue #133)
* FIXED: Download url in setup.py.
(thanks to Benoît Bryon,
resolves issue #130)
* FIXED: The update_translation_fields management command does nothing.
(resolves issue #123)
* FIXED: MultilingualQuerySet custom inheritance.
* CHANGED: Don't raise an exception if TranslationField is accessed via class
to allow descriptor introspection.
(resolves issue #131)
## 0.5b1 (2013-01-07)
Packaged from revision da928dd431fcf112e2e9c4c154c5b69e7dadc3b3.
* ADDED: Possibility to turn off query rewriting in MultilingualManager.
(thanks to Jacek Tomaszewski)
* FIXED: Fixed update_translation_fields management command.
(thanks to Jacek Tomaszewski,
resolves issues #123 and #124)
* CHANGED: Major test refactoring.
(thanks to Jacek Tomaszewski,
resolves issues #100 and #119)
## 0.5a1 (2012-12-05)
Packaged from revision da4aeba0ea20ddbee67aa49bc90af507997ac386.
* ADDED: Increased the number of supported fields. Essentially all Django
model fields and subclasses of them should work, except related
fields (ForeignKey, ManyToManyField, OneToOneField) and AutoField
which are not supported.
* ADDED: A subclass of TranslationOptions inherits fields from its bases.
(thanks to Bruno Tavares and Jacek Tomaszewski,
resolves issue #110)
* ADDED: Support for fallback languages. Allows fine grained configuration
through project settings and TranslationOptions on model basis.
(thanks to Jacek Tomaszewski,
resolves issue #104)
* ADDED: Multilingual manager which is aware of the current language.
(thanks to Jacek Tomaszewski,
resolves issues #45, #78 and #84)
* CHANGED: Version code to use a PEP386 compliant version number.
* CHANGED: Constructor rewrites fields to be language aware.
(thanks to Jacek Tomaszewski,
resolves issues #33 and #58)
* FIXED: Lacking support for readonly_fields in TranslationAdmin.
(thanks to sbrandtb,
resolves issue #111)
* FIXED: Model's db_column option is not applied to the translation field.
(resolves issue #83)
* FIXED: Admin prevents saving a cleared field. The fix deactivates rule3 and
implies the new language aware manager and constructor rewrite.
(resolves issue #85)
## 0.4.1 (2012-11-13)
Packaged from revision d9bf9709e9647fb2af51fc559bbe356010bd51ca.
* FIXED: Pypi wants to install beta version. Happened because pypi treats
0.4.0-beta2 as latest release. This also effectively resulted in a
downgrade when using 'pip --upgrade' and 0.4.0 was already installed.
(thanks to jmagnusson for the report,
resolves issue #103)
## 0.4.0 (2012-11-11)
Packaged from revision c44f9cfee59f1b440f022422f917f247e16bbc6b.
* CHANGED: Refactored tests to allow test runs with other apps. Includes a
"backport" of override_settings to ensure Django 1.3 support.
(thanks to Jacek Tomaszewski)
* CHANGED: Modeltranslation related css class prefix to 'mt'.
* FIXED: Race condition during initialization.
(resolves issue #91)
* FIXED: Tabs don't properly support two-part language codes.
(resolves issue #63)
## 0.4.0-beta2 (2012-10-17)
Packaged from revision 7b8cafbde7b14afc8e85235e9b087889a6bfa86e.
* FIXED: Release doesn't include rst files.
## 0.4.0-beta1 (2012-10-17)
Packaged from revision 09a0c4434a676c6fd753e6dcde95056c424db62e.
* CHANGED: Refactored documentation using sphinx.
(resolves issue #81)
* FIXED: Setting MODELTRANSLATION_TRANSLATION_FILES should be optional.
(resolves issue #86)
## 0.4.0-alpha1 (2012-10-12)
Packaged from revision 170.
* ADDED: Support for FileField and ImageField.
(thanks to Bruno Tavares,
resolves issue #30)
* ADDED: New management command sync_database_fields to sync the database after
a new model has been registered or a new language has been added.
(thanks to Sébastien Fievet and the authors of django-transmeta,
resolves issue #62)
* CHANGED: Excluded tabular inlines from jQuery tabs, as they are currently
not supported.
* CHANGED: Use app-level translation files in favour of a single project-level
one. Adds an autoregister feature similiar to the one provided by
Django's admin. A new setting MODELTRANSLATION_TRANSLATION_FILES keeps
backwards compatibility with older versions. See documentation for
details. This is basically a merge from both
django-modeltranslation-wrapper and hyperweek's branch at github.
(thanks to Jacek Tomaszewski, Sébastien Fievet and Maxime Haineault,
resolves issues #19, #58 and #71)
* CHANGED: Moved tests to separate folder and added tests for TranslationAdmin.
To run the tests the settings provided in model.tests.modeltranslation
have to be used (settings.LANGUAGES override doesn't work for
TranslationAdmin).
* CHANGED: Major refactoring of the admin integration. Subclassed BaseModelAdmin
and InlineModelAdmin. Patching options in init doesn't seem to be
thread safe. Instead used provided hooks like get_form, get_formset
and get_fieldsets. This should resolve several problems with the
exclude and fieldsets options and properly support options in inlines.
(resolves issue #72)
* FIXED: Non-unicode verbose field names showing up empty in forms.
(resolves issue #35)
* FIXED: Dynamic TranslationOptions model name.
* FIXED: Widgets for translated fields are not properly copied from original
fields.
(thanks to boris-chervenkov, resolves issue #74)
* FIXED: Removed XMLField test which is deprecated since Django 1.3 and
broke tests in Django 1.4.
(resolves issue #75)
## 0.3.3 (2012-02-23)
Packaged from revision 129.
* CHANGED: jQuery search path in tabbed_translation_fields.js. This allows use of
a version of jQuery other than the one provided by Django. Users who
want to force the use of Django's jQuery can include force_jquery.js.
* FIXED: Another attempt to include static files during installation.
(resolves reopened issue #61)
## 0.3.2 (2011-06-16)
Packaged from revision 122.
* FIXED: Static files not included during installation.
(resolves issue #61)
## 0.3.1 (2011-06-07)
Packaged from revision 121.
* CHANGED: Renamed media folder to static.
## 0.3 (2011-06-03)
Packaged from revision 113.
* ADDED: Support for multi-table inheritance.
(thanks to Sébastien Fievet, resolves issues #50 and #51)
* ADDED: Jquery-ui based admin support for tabbed translation fields.
(thanks to jaap and adamsc, resolves issue #39)
* ADDED: CSS class to identify a translation field and the default translation
field in admin.
(thanks to jaap)
* ADDED: Configurable default value per field instance.
(thanks to bmihelac, resolves issue #28)
* ADDED: Setting to override the default language.
(thanks to jaap, resolves issue #2)
* CHANGED: Improved performance of update_translation_fields command.
(thanks to adamsc, resolves issue #43)
* CHANGED: Factored out settings into a separate settings.py and consistently
used an app specific settings prefix.
* CHANGED: Refactored creation of translation fields and added handling of
supported fields.
(resolves issue #37)
* FIXED: Clearing the default translation field in admin does not clear the
original field.
(resolves issue #47)
* FIXED: In some setups appears "This field is required" error for the
original field.
(resolves issue #5)
* FIXED: Translations are not saved for tinymce HTMLField when using jquery
tabs.
(thanks to kottenator, resolves issue #41)
* FIXED: Fieldname isn't ensured to be string.
(resolves issue #41)
* FIXED: Kept backwards compatibility with Django-1.0.
(thanks to jaap, resolves issue #34)
* FIXED: Regression in south_field_triple caused by r55.
(thanks to jaap, resolves issue #29)
* FIXED: TranslationField pre_save does not get the default language
correctly.
(thanks to jaap, resolves issue #31)
## 0.2 (2010-06-15)
Packaged from revision 57.
* ADDED: Support for admin prepopulated_fields.
(resolves issue #21)
* ADDED: Support for admin list_editable.
(thanks carl.j.meyer, resolves issue #20)
* ADDED: Preserve the formfield widget of the translated field.
(thanks piquadrat)
* ADDED: Initial support for django-south.
(thanks andrewgodwin, resolves issue #11)
* ADDED: Support for admin inlines, common and generic.
(resolves issue #12 and issue #18)
* FIXED: Admin form validation errors with empty translated values and
unique=True.
(thanks to adamsc, resolves issue #26)
* FIXED: Mangling of untranslated prepopulated fields.
(thanks to carl.j.meyer, resolves issue #25)
* FIXED: Verbose names of translated fields are not translated.
(thanks to carl.j.meyer, resolves issue #24)
* FIXED: Race condition between model import and translation registration in
production by ensuring that models are registered for translation
before TranslationAdmin runs.
(thanks to carl.j.meyer, resolves issue #19)
* FIXED: Added workaround for swallowed ImportErrors by printing a traceback
explicitly.
(resolves issue #17)
* FIXED: Only print debug statements to stdout if the runserver or
runserver_plus management commands are used.
(resolves issue #16)
* FIXED: Removed print statements so that modeltranslation is usable with
mod_wsgi.
(resolves issue #7)
* FIXED: Broken admin fields and fieldsets.
(thanks simoncelen, resolves issue #9)
* FIXED: Creation of db fields with invalid python language code.
(resolves issue #4)
* FIXED: Tests to run from any project.
(thanks carl.j.meyer, resolves issue #6)
* FIXED: Removed unused dependency to content type which can break syncdb.
(thanks carl.j.meyer, resolves issue #1)
## 0.1 (2009-02-22)
Initial release packaged from revision 19.
Authors¶
Core Committers¶
- Peter Eschler <peschler@gmail.com> (retired)
- Dirk Eschler <eschler@gmail.com>
- Jacek Tomaszewski <jacek.tomek@gmail.com>
Contributors¶
- Carl J. Meyer
- Jaap Roes
- Bojan Mihelac
- Sébastien Fievet
- Bruno Tavares
- Zach Mathew (of django-linguo, initial author of
MultilingualManager
) - Mihai Sucan
- Benoît Bryon
- Wojtek Ruszczewski
- Chris Adams
- Dominique Lederer
- Braden MacDonald
- Karol Fuksiewicz
- Konrad Wojas
- Bas Peschier
- Oleg Prans
- Francesc Arpí Roca
- Mathieu Leplatre
- Thom Wiggers
- Warnar Boekkooi
- Alex Marandon
- Fabio Caccamo
- Vladimir Sinitsin
- Luca Corti
- Morgan Aubert
- Mathias Ettinger
- Daniel Loeb
- Stephen McDonald
- Lukas Lundgren
- zenoamaro
- oliphunt
- Venelin Stoykov
- Stratos Moros
- Benjamin Toueg
- Emilie Zawadzki
- Virgílio N Santos
- PetrDlouhy
- dmarcelino
- GreyZmeem
- And many more … (if you miss your name here, please let us know!)