So long, and thanks for the fish.
Warning : As it is, django-babelfish should be considered as a developpment version.
Download the sources and made it available within your python path
.
Copy, or symlink, the files in media
in your own media directory.
Theses files are used in the admin to build and style the translations fields
in the admin forms.
Defines the supported languages in a LANGUAGES
setting in your settings.py
.
LANGUAGES = (
("en", "English"),
("fr", "French"),
)
There's no need to add babelfish
to your INSTALLED_APPS
, but
if you want to quickly try BabelFish you can add it, and then you'll
make available in the admin the BabelFishDemoModel
class. This class
demonstrate how a translatable model interact with the admin.
The class babelfish.models.BabelFishDemoModel
demonstrate how to setup a class
to made it available for BabelFish translation. But to save you the time to search in the sources,
I'll describe the setup below.
from django.db import models
from babelfish.models import BabelFishModel, BabelFishField
class MyTranslatableModel ( BabelFishModel ):
translate_fields = ('name','description')
bf_translations = BabelFishField( translate_fields )
name = models.CharField( "Name", max_length=100 )
slug = models.CharField( "Slug", max_length=100 )
description = models.TextField("Description")
- Make your model extend
BabelFishModel
. - Define a
translate_fields
tuple in your class with the name of fields to translate. - Define a
bf_translations
field of typeBabelFishField
in your class, passtranslate_fields
as its first argument. The field need to know which fields are concerned in order to allow the form's field and the widget to know the fields as well. That's why this field cannot be defined inBabelFishModel
since Django create form's field for a class before the__init__
of this class. - Sync your database using the
./manage.py syncdb
command to create the corresponding column.
The BabelFishField
is a TextField
which store all the translations for the translatable fields
in a dict
serialized using JSON.
This way there's no need to sync the database when adding a new language or when making a new field in your model available for translation.
In the same way, making a model translatable doesn't break its fixtures, since the column name for the translatable fields doesn't change. That means that you doesn't have to bother to make a model translatable unless you need it, and once you need it, the change will not break all your previous content.
>>> m = MyTranslatableModel( name="This is my name", description="This is my description", slug="sample" )
>>> m.name
"This is my name"
>>> m.description
"This is my description"
>>> m.name_fr # translations are available with the lang suffix
"This is my name" # if no translations are defined, the default is returned
>>> m.name_fr = "Ceci est mon nom"
>>> m.description_fr = "Ceci est ma description"
>>> m.name_fr
"Ceci est mon nom"
>>> m.translate('fr') # call translate with a language code to swap the instance
>>> m.name
"Ceci est mon nom"
>>> m.description
"Ceci est ma description"
>>> m.name = "Mon nom est personne" # setting the field on a translated instance set the translations
>>> m.name
"Mon nom est personne"
>>> m.name_fr
"Mon nom est personne"
>>> m.translate() # calling translate without argument reset the instance
>>> m.name
"This is my name"
>>> m.name_it # will raise an error if the it language is not defined in LANGUAGES
>>> m.slug_fr # will raise an since slug is not translatable
BabelFishModel
support a custom Meta
argument auto_translate
which enable models to be automatically
translated when instanciated. However, models instance use in the the admin site should never be translated (see below).
Django BabelFish provides several middlewares with different behaviors.
UserAgentLangMiddleware
simply define thedjango.utils.translation
language on the language provided by the user's browser lang meta.DefaultLangMiddleware
implements a more flexible behavior, if there's no language specified in the current user's session the language is set with the user agent meta and stored in the session. If the request carry aGET
parameter namedlang
the language is set on this parameter, the session is updated as well. In the other cases, the value in session is used.
All theses middlewares support automatic models translation, and prevent models to be translated in the admin.
Models should never translated in the admin to avoid issues with models saving, since the automatic translation is done
in the __init__
. The fact that a model is automatically translated at init will produce that admin's forms will not set the default
as wanted but the translations for the current language (see API). In consequences, all middlewares exclude admin pages from automatic translations.
To achieve that feature, the middlewares checks wether the current PATH_INFO
match the pattern defined in ADMIN_URLS_PATTERN
("^/admin/"
by default) and activate the ALLOW_AUTO_TRANSLATE
settings accordingly. You can set the ADMIN_URLS_PATTERN
in your project's settings.py
.
Models are automatically translated only if both their auto_translate
meta is set to True
and if the ALLOW_AUTO_TRANSLATE
is also True
.
from django.contrib import admin
from babelfish.admin import BabelFishAdmin
class MyTranslatableAdmin ( BabelFishAdmin ):
list_display=("name","slug",)
fieldsets = [
( _(u'BabelFish'), {'fields': ['bf_translations',] }),
( _(u'Content'), {'f ields': ['name','slug','description'] }),
]
admin.site.register( MyTranslatableModel, MyTranslatableAdmin )
As you can notice, I explicitely add the bf_translations
to the fieldsets. It
will allow the BabelFishWidget
to be rendered and the setup script will have the
required setup.
Actually, the BabelFishWidget
display, instead of the TextField
widget, a table
with statistics for translations in the current instance.
The widgets to edit translations are cloned by the babelfish.js
script from the
original widget of each translatable fields.