General documentation touchups. Used wikir compatible syntax for literal blocks. Fixed internal links.

This commit is contained in:
Dirk Eschler 2010-08-30 09:54:31 +00:00
parent 951b0699cb
commit ab03291848

View file

@ -1,16 +1,8 @@
.. _ref-topics-modeltranslation:
==================
Modeltranslation
==================
.. admonition:: About this document
This document provides an introduction to the modeltranslation application.
.. currentmodule:: modeltranslation.models
.. moduleauthor:: Peter Eschler <peschler@googlemail.com>,
Dirk Eschler <eschler@gmail.com>
================
Modeltranslation
================
The modeltranslation application can be used to translate dynamic content of
existing models to an arbitrary number of languages without having to change
@ -23,6 +15,11 @@ models on a per-project 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.
*Authors*
- Peter Eschler <peschler@googlemail.com>
- Dirk Eschler <eschler@gmail.com>
.. contents::
@ -66,7 +63,9 @@ The following variables have to be added to or edited in the project's
**settings.INSTALLED_APPS**
Make sure that the ``modeltranslation`` app is listed in your
``INSTALLED_APPS`` variable::
``INSTALLED_APPS`` variable:
::
INSTALLED_APPS = (
...
@ -85,7 +84,9 @@ 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 settings.LANGUAGES variable like this
(where ``de`` is the default language)::
(where ``de`` is the default language):
::
gettext = lambda s: s
LANGUAGES = (
@ -101,6 +102,7 @@ modeltranslation app, but rather required for Django to be able to
**settings.MODELTRANSLATION_DEFAULT_LANGUAGE**
*New in development version*
To override the default language as described in settings.LANGUAGES, define
``MODELTRANSLATION_DEFAULT_LANGUAGE``. Note that the value has to be in
settings.LANGUAGES, otherwise an exception will be raised.
@ -111,10 +113,34 @@ In order to be able to import the project's ``translation.py`` registration
file the ``MODELTRANSLATION_TRANSLATION_REGISTRY`` must be set to a value in
the form ``<PROJECT_MODULE>.translation``. E.g. if your project is located in a
folder named ``myproject`` the ``MODELTRANSLATION_TRANSLATION_REGISTRY`` must
be set like this::
be set like this:
::
MODELTRANSLATION_TRANSLATION_REGISTRY = "myproject.translation"
**settings.MODELTRANSLATION_CUSTOM_FIELDS**
*New in development version*
``Modeltranslation`` officially supports ``CharField`` and ``TextField``.
In most cases subclasses of these fields will work fine, too. Other fields
aren't supported and will throw an ``ImproperlyConfigured`` exception.
The list of supported fields can be extended. Just define a tuple of field
names in your settings.py like this:
::
MODELTRANSLATION_CUSTOM_FIELDS = ('MyField', 'MyOtherField',)
.. note:: This just prevents ``modeltranslation`` from throwing an
``ImproperlyConfigured`` exception. Any non text-like 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.
Registering models and their fields for translation
---------------------------------------------------
@ -143,12 +169,13 @@ option class must be registered with the
.. note:: In contrast to the Django admin application which looks for
``admin.py`` files in the project **and** application directories,
the modeltranslation app looks only for one ``translation.py`` file in
the project directory.
the modeltranslation app looks only for one ``translation.py`` file in the project directory.
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::
Instead of a news, this could be any Django model class:
::
class News(models.Model):
title = models.CharField(max_length=255)
@ -156,7 +183,9 @@ Instead of a news, this could be any Django model class::
In order to tell the ``modeltranslation`` app to translate the ``title`` and
``text`` field, create a ``translation.py`` file in your project directory and
add the following::
add the following:
::
from modeltranslation.translator import translator, TranslationOptions
from some.news.models import News
@ -175,10 +204,13 @@ 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.
Changes automatically applied to the model class
------------------------------------------------
After registering the ``News`` model for transaltion an SQL dump of the
News app will look like this::
News app will look like this:
::
$ ./manage.py sqlall news
BEGIN;
@ -229,7 +261,9 @@ Accessing translated and translation fields
===========================================
The ``modeltranslation`` app changes the behaviour of the translated fields. To
explain this consider the News example again. The original ``News`` model
looked like this::
looked like this:
::
class News(models.Model):
title = models.CharField(max_length=255)
@ -288,7 +322,9 @@ 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::
translated ``title`` field will return the value from the ``title_de`` field:
::
# Assuming the current language is "de"
n = News.objects.all()[0]
@ -303,28 +339,10 @@ the ``django.utils.i18n.get_language`` function to determine the current
language.
Supported fields
----------------
``Modeltranslation`` officially supports CharField and TextField.
*New in development version*
In most cases subclasses of these fields will work fine, too. Other fields
aren't supported and will throw an ``ImproperlyConfigured`` exception.
The list of supported fields can be extended. Just define a tuple of field
names in your settings.py like this::
MODELTRANSLATION_CUSTOM_FIELDS = ('MyField', 'MyOtherField',)
*Note:* This just prevents ``modeltranslation`` from throwing an
``ImproperlyConfigured`` exception. Any non text-like 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.
Set a default value
-------------------
*New in development version*
TODO
@ -333,7 +351,9 @@ Django admin backend integration
In order to be able to edit the translations via the admin backend 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::
patching on all your models registered for translation:
::
from django.contrib import admin
from modeltranslation.admin import TranslationAdmin
@ -357,21 +377,27 @@ following:
the default translation field required instead.
TranslationAdmin in combination with other admin classes
--------------------------------------------------------
.. _translationadmin_in_combination_with_other_admin_classes:
!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 the News example let's say there is a ``NewsAdmin`` class defined by the
News app itself. This app is not yours or you don't want to touch it at all,
but it has this nice admin class::
but it has this nice admin class:
::
class NewsAdmin(model.Admin):
def formfield_for_dbfield(self, db_field, **kwargs):
# does some funky stuff with the formfield here
So a first attempt might be to create your own admin class which subclasses
``NewsAdmin`` and ``TranslationAdmin`` to combine stuff like so::
``NewsAdmin`` and ``TranslationAdmin`` to combine stuff like so:
::
class MyTranslatedNewsAdmin(NewsAdmin, TranslationAdmin):
pass
@ -382,7 +408,9 @@ Python must make a decision and it chooses the first class ``NewsAdmin``. 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::
But don't panic, here's a solution:
::
class MyTranslatedNewsAdmin(NewsAdmin, TranslationAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
@ -404,6 +432,7 @@ custom admin class and that's done in the example above. After that the
Inlines
-------
*New in 0.2*
Support for tabular and stacked inlines, common and generic ones.
A translated inline must derive from one of the following classes:
@ -420,67 +449,71 @@ patching.
For our example we assume that there is new model called Image. It's
definition is left out for simplicity. Our News model inlines the new model:
{{{
from django.contrib import admin
from modeltranslation.admin import TranslationTabularInline
::
class ImageInline(TranslationTabularInline):
model = Image
from django.contrib import admin
from modeltranslation.admin import TranslationTabularInline
class NewsAdmin(admin.ModelAdmin):
list_display = ('title',)
inlines = [ImageInline,]
class ImageInline(TranslationTabularInline):
model = Image
admin.site.register(News, NewsAdmin)
}}}
class NewsAdmin(admin.ModelAdmin):
list_display = ('title',)
inlines = [ImageInline,]
*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.
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.
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 and
the Image model an own generic stacked inline class. It uses the technique
described in [InstallationAndUsage#TranslationAdmin_in_combination_with_other_admin_classes TranslationAdmin in combination with other admin classes].:
described in `TranslationAdmin in combination with other admin classes`__.:
{{{
from django.contrib import admin
from modeltranslation.admin import TranslationAdmin, TranslationGenericStackedInline
__ translationadmin_in_combination_with_other_admin_classes_
class TranslatedImageInline(ImageInline, TranslationGenericStackedInline):
model = Image
::
class TranslatedNewsAdmin(NewsAdmin, TranslationAdmin):
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
from django.contrib import admin
from modeltranslation.admin import TranslationAdmin, TranslationGenericStackedInline
inlines = [TranslatedImageInline,]
class TranslatedImageInline(ImageInline, TranslationGenericStackedInline):
model = Image
admin.site.register(News, NewsAdmin)
}}}
class TranslatedNewsAdmin(NewsAdmin, TranslationAdmin):
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
inlines = [TranslatedImageInline,]
admin.site.register(News, NewsAdmin)
Using tabbed translation fields
-------------------------------
*New in development version*
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 = (
'/static/modeltranslation/js/force_jquery.js',
'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js',
'/static/modeltranslation/js/tabbed_translation_fields.js',
)
css = {
'screen': ('/static/modeltranslation/css/tabbed_translation_fields.css',),
}
}}}
::
class NewsAdmin(TranslationAdmin):
class Media:
js = (
'/static/modeltranslation/js/force_jquery.js',
'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js',
'/static/modeltranslation/js/tabbed_translation_fields.js',
)
css = {
'screen': ('/static/modeltranslation/css/tabbed_translation_fields.css',),
}
The `force_jquery.js` script is necessary when using Django's built-in
`django.jQuery` object. This and the static urls used are just an example and
@ -499,7 +532,9 @@ 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 below) which will be empty in this case. To correctly initialize the
default translation field you can use the ``update_translation_fields``
command::
command:
::
manage.py update_translation_fields
@ -517,7 +552,9 @@ populated with initial data.
Caveats
=======
Consider the following example (assuming the default lanuage is ``de``)::
Consider the following example (assuming the default lanuage is ``de``):
::
>>> n = News.objects.create(title="foo")
>>> n.title
@ -531,7 +568,9 @@ normally updates the associated default translation field (``title_de``) is not
called. Therefor the call to ``n.title_de`` returns an empty value.
Now assign the title, which triggers the descriptor and the default translation
field is updated::
field is updated:
::
>>> n.title = 'foo'
>>> n.title_de