General documentation improvements.

This commit is contained in:
deschler 2014-07-20 01:58:00 +02:00
parent ca453533e4
commit 756de544aa
7 changed files with 112 additions and 105 deletions

View file

@ -2,7 +2,7 @@
Modeltranslation
================
The modeltranslation application can be used to translate dynamic content of
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
@ -21,11 +21,12 @@ model class.
Features
========
- Add translations without changing existing models
- Fast, because translation fields are stored in the same table
- Supports inherited models
- Django admin support
- Unlimited number of target languages
- 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!
Project Home

View file

@ -30,7 +30,7 @@ formfield_for_dbfield
The ``TranslationBaseModelAdmin`` class, which ``TranslationAdmin`` and all
inline related classes in modeltranslation derive from, implements a special
method which is ``def formfield_for_dbfield(self, db_field, **kwargs)``. This
method which is ``formfield_for_dbfield(self, db_field, **kwargs)``. This
method does the following:
1. Copies the widget of the original field to each of its translation fields.
@ -78,7 +78,7 @@ 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 (fictional) reusable blog app which defines a model ``Entry`` and a
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.

View file

@ -8,19 +8,19 @@ Management Commands
The ``update_translation_fields`` Command
-----------------------------------------
In case the modeltranslation app was installed on an existing project and you
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 :ref:`db-fields`).
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``
:ref:`Rule 1 <rules>`) which will be empty in this case. To correctly initialize
the default translation field you can use the ``update_translation_fields``
command:
.. code-block:: console
$ ./manage.py update_translation_fields
$ 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 default translation
@ -47,11 +47,12 @@ The ``sync_translation_fields`` Command
.. code-block:: console
$ ./manage.py sync_translation_fields
$ 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
new language or deciding to translate new field in a ``TranslationOptions``.
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 :ref:`db-fields` for detailed info and use cases.
@ -62,28 +63,29 @@ The ``loaddata`` Command
.. versionadded:: 0.7
It is just extension to original ``loaddata`` command which adds an optional ``populate`` keyword.
If specified, then normal loading command will be run under selected auto-population modes.
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.
.. code-block:: console
$ ./manage.py loaddata --populate=all fixtures.json
$ python manage.py loaddata --populate=all fixtures.json
Allowed modes are listed :ref:`here <auto-population-modes>`. To choose ``False``
(turn off auto-population) specify ``'0'`` or ``'false'``:
.. code-block:: console
$ ./manage.py loaddata --populate=false fixtures.json
$ ./manage.py loaddata --populate=0 fixtures.json
$ python manage.py loaddata --populate=false fixtures.json
$ python manage.py loaddata --populate=0 fixtures.json
.. note::
If ``populate`` is not specified, then current auto-population mode is used. *Current* means
If ``populate`` is not specified, the current auto-population mode is used. *Current* means
the one set by :ref:`settings <settings-modeltranslation_auto_populate>`.
Moreover, this ``loaddata`` command version can override the nasty habit of changing locale to
`en-us`. By default, it will retain proper locale. To get back to old behaviour, set
`en-us`. By default, it will retain the proper locale. To get the old behaviour back, set
:ref:`settings-modeltranslation_loaddata_retain_locale` to ``False``.

View file

@ -4,7 +4,8 @@ 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 :ref:`a note <register-precautions>`).
Please note, however, that they shouldn't be defined next to models
(see :ref:`a note <register-precautions>`).
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.
@ -37,18 +38,18 @@ In most cases formfields for translation fields behave as expected. However, the
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 field is nullable
(``''``), even if the field is nullable
(see django `ticket #9590 <http://code.djangoproject.com/ticket/9590>`_).
Thus formfields for translation fields are patched by `MT`. Following rules apply:
Thus formfields for translation fields are patched by modeltranslation. The following rules apply:
.. _formfield_rules:
- If original field is not nullable, empty value would be saved as ``''``;
- If original field is nullable, empty value would be saved as ``None``.
- 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``)::
using ``TranslationOptions``::
class NewsTranslationOptions(TranslationOptions):
fields = ('title', 'text',)
@ -68,9 +69,9 @@ This configuration is especially useful for fields with unique constraints::
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 error when 2 or more ``Categories`` are saved with
``''`` 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 database don't violate uniqueness::
as several ``None`` values in the database don't violate uniqueness::
class CategoryTranslationOptions(TranslationOptions):
fields = ('name', 'slug')
@ -82,15 +83,15 @@ as several ``None`` values in database don't violate uniqueness::
None-checkbox widget
********************
Maybe there is a situation when somebody want to store in a field both empty strings and ``None``
values. For such a scenario there is third configuration value: ``'both'``::
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 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. Probably only useful place for this widget is admin
backend; see :ref:`admin-formfield`.
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 :ref:`admin-formfield`.
To sum up, only valid ``empty_values`` values are: ``None``, ``''`` and ``'both'``.
To sum it up, the valid values for ``empty_values`` are: ``None``, ``''`` and ``'both'``.

View file

@ -59,20 +59,20 @@ Setup
To setup the application please follow these steps. Each step is described
in detail in the following sections:
1. Add the ``modeltranslation`` app to the ``INSTALLED_APPS`` variable of your
1. Add ``modeltranslation`` to the ``INSTALLED_APPS`` variable of your
project's ``settings.py``.
#. Set ``USE_I18N = True`` in ``settings.py``.
2. Set ``USE_I18N = True`` in ``settings.py``.
#. Configure your ``LANGUAGES`` in ``settings.py``.
3. Configure your ``LANGUAGES`` in ``settings.py``.
#. Create a ``translation.py`` in your app directory and register
4. Create a ``translation.py`` in your app directory and register
``TranslationOptions`` for every model you want to translate.
#. Sync the database using ``./manage.py syncdb`` (note that this only applies
if the models registered in the ``translation.py`` did not have been
synced to the database before. If they did - read :ref:`further down <db-fields>` what to do
in that case.
5. Sync the database using ``python manage.py syncdb``.
.. note:: This only applies if the models registered in ``translation.py`` haven't been
synced to the database before. If they have, please read :ref:`db-fields`.
Configuration
@ -94,6 +94,7 @@ Make sure that the ``modeltranslation`` app is listed in your
INSTALLED_APPS = (
...
'modeltranslation',
'django.contrib.admin', # optional
....
)
@ -102,9 +103,9 @@ Make sure that the ``modeltranslation`` app is listed in your
before ``django.contrib.admin``.
.. important::
If you want to use the ``django-debug-toolbar`` together with `MT`, put ``debug_toolbar``
as first entry in ``INSTALLED_APPS`` or use
`explicit setup
If you want to use the ``django-debug-toolbar`` together with
modeltranslation, put ``debug_toolbar`` as first entry in
``INSTALLED_APPS`` or use `explicit setup
<http://django-debug-toolbar.readthedocs.org/en/latest/installation.html#explicit-setup>`_.
.. _settings-languages:
@ -115,10 +116,10 @@ Make sure that the ``modeltranslation`` app is listed in your
The ``LANGUAGES`` variable must contain all languages used for translation. The
first language is treated as the *default language*.
The modeltranslation application 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)::
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 = (
@ -144,7 +145,7 @@ and ``en`` in your project, set the ``LANGUAGES`` variable like this (where
in your project. When it isn't present (and neither is ``MODELTRANSLATION_LANGUAGES``), it
defaults to Django's
`global LANGUAGES setting <https://github.com/django/django/blob/master/django/conf/global_settings.py>`_
instead, and that are quite a number of languages!
instead, and that are quite a few languages!
Advanced Settings
@ -379,4 +380,4 @@ Default: ``True``
Control if the ``loaddata`` command should leave the settings-defined locale alone. Setting it
to ``False`` will result in previous behaviour of ``loaddata``: inserting fixtures to database
under `en-us` locale.
under ``en-us`` locale.

View file

@ -12,7 +12,7 @@ steps:
1. Create a ``translation.py`` in your app directory.
2. Create a translation option class for every model to translate.
3. Register the model and the translation option class at the
3. Register the model and the translation option class at
``modeltranslation.translator.translator``.
The modeltranslation application reads the ``translation.py`` file in your
@ -33,9 +33,9 @@ Instead of a news, this could be any Django model class::
title = models.CharField(max_length=255)
text = models.TextField()
In order to tell the modeltranslation app to translate the ``title`` and
``text`` field, create a ``translation.py`` file in your news app directory and
add the following::
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 news.models import News
@ -86,7 +86,7 @@ say it in code::
Of course multiple inheritance and inheritance chains (A > B > C) also work as
expected.
.. note:: When upgrading from a previous modeltranslation version, please
.. 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).
@ -137,17 +137,18 @@ 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 `MT` code executes. In normal circumstances it shouldn't
affect anything - as long as ``models.py`` contain only models' related code.
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 when a ``ModelForm`` is declared in ``models.py`` just after
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 ``ModelForm`` will be created before
`MT` 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).
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 `MT` (and as sensible design, anyway),
Generally, for seamless integration with modeltranslation (and as sensible design anyway),
the ``models.py`` should contain only bare models and model related logic.
.. _db-fields:
@ -168,22 +169,22 @@ fields) and apply it. If not, you can use a little helper:
:ref:`commands-sync_translation_fields` 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 third-party app that is using South,
things get more complicated. In order to be able to update the app in future,
If you are adding translation fields to a third-party app that is using South,
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 ``SOUTH_MIGRATION_MODULES`` setting,
and passing ``--delete-ghost-migrations`` flag, 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 below.
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 below.
To populate the default translation fields added by the modeltranslation application
with values from existing database fields, you
can use the ``update_translation_fields`` command below. See
To populate the default translation fields added by modeltranslation with
values from existing database fields, you can use the
``update_translation_fields`` command below. See
:ref:`commands-update_translation_fields` for more info on this.
@ -194,14 +195,14 @@ Required fields
.. versionadded:: 0.8
By default, all translation fields are optional (not required). It can be changed using special
attribute on ``TranslationOptions``, though::
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 quite self-explanatory: for German and English, all translation fields are required. For other
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::
@ -216,7 +217,7 @@ For German, all fields (both ``title`` and ``text``) are required; for all other
.. 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
``full_clean()`` model method.
the ``full_clean()`` model method.
The required fields are still ``null=True``, though.

View file

@ -3,7 +3,7 @@
Accessing Translated and Translation Fields
===========================================
The modeltranslation app changes the behaviour of the translated fields. To
Modeltranslation changes the behaviour of the translated fields. To
explain this consider the news example from the :ref:`registration` chapter
again. The original ``News`` model looked like this::
@ -11,7 +11,7 @@ again. The original ``News`` model looked like this::
title = models.CharField(max_length=255)
text = models.TextField()
Now that it is registered with the modeltranslation app the model looks
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):
@ -160,21 +160,22 @@ Moreover, some fields can be explicitly assigned different values::
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::
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 tooks place also in model constructor, what is extremely useful when loading
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
call_command('loaddata', 'fixture.json') # Some fixture loading
z = News(title='bar')
print z.title_en, z.title_de # prints 'bar bar'
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:
@ -186,7 +187,7 @@ It controls the default population behaviour.
Auto-population modes
^^^^^^^^^^^^^^^^^^^^^
There are 4 different population modes:
There are four different population modes:
``False``
[set by default]
@ -212,17 +213,17 @@ There are 4 different population modes:
Falling back
------------
Modeltranslation provides mechanism to control behaviour of data access in case of empty
Modeltranslation provides a mechanism to control behaviour of data access in case of empty
translation values. This mechanism affects field access.
Consider ``News`` example: a creator of some news hasn't specified it's german title and content,
but only english ones. Then if a german visitor is viewing site, we would rather show him english
title/content of the news than display empty strings. This is called *fallback*. ::
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 title_de field value ('').
# 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.
There are several ways of controlling fallback, described below.
@ -234,17 +235,17 @@ Fallback languages
.. versionadded:: 0.5
:ref:`settings-modeltranslation_fallback_languages` setting allows to set order of *fallback
languages*. By default it is only ``DEFAULT_LANGUAGE``.
:ref:`settings-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 yield non-empty value of the field.
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 option to define fallback by language, using dict syntax::
There is also an option to define a fallback by language, using dict syntax::
MODELTRANSLATION_FALLBACK_LANGUAGES = {
'default': ('en', 'de', 'fr'),
@ -255,11 +256,11 @@ There is also option to define fallback by language, using dict syntax::
The ``default`` key is required and its value denote languages which are always tried at the end.
With such a setting:
- for `uk` (Ukrainian) order of fallback languages is: ``('ru', 'en', 'de', 'fr')``
- for `fr` order of fallback languages is: ``('de', 'en')`` - `fr` obviously is not fallback, since
it's active language; and `de` would be tried before `en`
- for `en` and `de` fallback order is ``('de', 'fr')`` and ``('en', 'fr')``, respectively
- for any other language order of fallback languages is just ``('en', 'de', 'fr')``
- 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``::
@ -286,7 +287,7 @@ Fallback values
.. versionadded:: 0.4
But what if current language and all fallback languages yield no field value? Then modeltranslation
will use field's *fallback value*, if one was defined.
will use the field's *fallback value*, if one was defined.
Fallback values are defined in ``TranslationOptions``, for example::
@ -308,7 +309,7 @@ Fallback values can be also customized per model field::
}
If current language and all fallback languages yield no field value, and no fallback values are
defined, then modeltranslation will use field's default value.
defined, then modeltranslation will use the field's default value.
.. _fallback_undef:
@ -319,13 +320,13 @@ Fallback undefined
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 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 fallback on a different value or your default is expensive to calculate, provide
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):