mirror of
https://github.com/Hopiu/django-modeltranslation.git
synced 2026-04-09 00:00:58 +00:00
266 lines
10 KiB
ReStructuredText
266 lines
10 KiB
ReStructuredText
.. _usage:
|
|
|
|
Accessing Translated and Translation Fields
|
|
===========================================
|
|
|
|
The modeltranslation app 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::
|
|
|
|
class News(models.Model):
|
|
title = models.CharField(max_length=255)
|
|
text = models.TextField()
|
|
|
|
Now that it is registered with the modeltranslation app 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:
|
|
|
|
Rules for Translated Field Access
|
|
---------------------------------
|
|
|
|
.. versionchanged:: 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:
|
|
|
|
Multilingual Manager
|
|
--------------------
|
|
|
|
.. versionadded:: 0.5
|
|
|
|
Every model registered for translation is patched so that its manager becomes a subclass
|
|
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.
|
|
|
|
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()``
|
|
- ``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.
|
|
|
|
Auto-population
|
|
***************
|
|
|
|
In ``create()`` you can set special parameter ``_populate=True`` 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.create(title='bar', _populate=True)
|
|
|
|
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.create(title='-- no translation yet --', title_de='enigma', _populate=True)
|
|
|
|
It will result in ``title_de == 'nic'`` and other ``title_?? == '-- no translation yet --'``.
|
|
|
|
There is a more convenient way than passing _populate all the time:
|
|
:ref:`settings-modeltranslation_auto_populate` setting.
|
|
If ``_populate`` parameter is missing, ``create()`` will look at the setting to determine if
|
|
population should be used.
|
|
|
|
|
|
.. _fallback:
|
|
|
|
Falling back
|
|
------------
|
|
|
|
Modeltranslation provides mechanism to control behaviour of data access in case of empty
|
|
translation values.
|
|
|
|
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*.
|
|
|
|
There are several ways of controlling fallback, described below.
|
|
|
|
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``.
|
|
|
|
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.
|
|
|
|
There is also option to define 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` (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')``
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
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 field's default value.
|
|
|
|
|
|
The State of the Original Field
|
|
-------------------------------
|
|
|
|
.. versionchanged:: 0.5
|
|
|
|
As defined by the :ref:`rules`, 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.
|
|
|
|
.. 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.
|
|
|
|
|
|
.. _set_language: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#set-language-redirect-view
|