django‎ > ‎

django-metalingual

Releases:

Revision 5 10 May 2010
Added caching support.
Bug fixes.

Revision 4 4 Dec 2009
Added support for temporary disabling of translations a model.
class MyModel(models.Model):
    def do_something_without(self):
        self._meta.get_field('metaLingual').disabled = True
        # do stuff here without metaLingual
        # ...
        # done, so re-enable metaLingual.
       
self._meta.get_field('metaLingual').disabled = False
Code re-factored.

Revision 3 1 Dec 2009
Better default language selection behaviour.
i.e. if 'en_GB'
is the default language and translations exist for 'de_DE', but the user's locale is set to 'de_AT', it will show the translation for 'de_DE'.

Revision 2 30 Nov 2009
Minor code re-factoring & minor bug fixes.

Revision 1 11 Nov 2009
Initial release.

A simple aid for multilingual django models.

Some basic  requirements for multilingual database content.

It should...
  • ... be possible to add an arbitrary number of languages without making structural database changes per language. i.e. a column per language is not an option
  • ... fully support south --auto schema migrations.
  • ... have a straight forward syntax
I liked the approach django-transmeta took so I used it's code to get started.
Since I plan on only ever doing queries on content in the original language, it doesn't matter where or how the translations are stored. Searching via DB queries is therefore not supported... but this should probably be done via a search engine anyway. :-P

Example model:

from django.db import models

class Item(models.Model):
    title = models.CharField(max_length=50)
    description = models.TextField()
    price = models.FloatField()

    class Meta:
        ordering = ['title']


To add multilingual support do this:

from django.db import models
from metalingual import MetaLingual

class Item(models.Model):
    __metaclass__ = MetaLingual # 1
    metaLingual = models.TextField(editable=False) # 2
    
    title = models.CharField(max_length=50)
    description = models.TextField()
    price = models.FloatField()

    class Meta:
        ordering = ['title']
        translate = ['title', 'description'] # 3

So we made 3 changes to the model:
  1. added a metaclass: This class mainly adds a little hook into your model to transparently add and retrieve translations.
  2. added a 'metaLingual' text field. We'll save all translations related to the model for each field and for each language here. It'll be saved as JSON, but you'll never see or need to use this. MetaLingual takes care of it for you.
  3. added  'translate = []' line to the class Meta. Here you specify what columns should be translatable.
... and it now supports translations for any fields marked to translate, for an arbitrary number of languages.

Here we create an Item:
>>> from mysite.models import Item
>>> item = Item()
>>> item.title = u"Edam Cheese"
>>> item.description = u"A delicious young hard cheese."
>>> item.price = 2.99
>>> item.save()

Let's assume that we have chosen English as your default language in the settings.py file. When storing translations, the default language always get's saved in the usual django way. i.e. in the column "title" and "description".

Now let's add a German translation:
>>> item.title_de = u"Edamer Käse"
>>> item.description_de = u"Ein leckere junger Hartkäse"
>>> item.save()

Now we have the item in English and German. You can access any translation by it's field name and append the language:
>>> item.title_en
u"Edam Cheese"


>>> item.title_de
u"Edamer Käse"


>>> item.description_en

u"A delicious young hard cheese."

>>> item.description_de
u"Ein leckere junger Hartkäse"


Accessing the title or description with specifying a language will return whatever language django thinks is correct. i.e. if your browser is set to German:
>>> item.title
u"Edamer Käse"


>>> item.description

u"Ein leckere junger Hartkäse"

But if the browser is set to English:
>>> item.title
u"Edam Cheese"


>>> item.description
u"A delicious young hard cheese."


What this as done in the background is stored the default language in the models 'title' and 'description' fields, and stored all translations in the models 'metaLingual' field, as JSON.
Remember, you don't need to know about this field, since you can read and write translations by using title_de or description_de.
>>> item.metaLingual
u"{'title': {'de': '
Edamer Käse'}, 'description': {'de': 'Ein leckere junger Hartkäse'}}"

MetaLingual also supports using full language codes such as de_DE, de_AT, zh_TW, en_UK and en_US, the only condition is that these are supported by settings.LANGUAGES.
Django sets this field for you, but you can override it to limit the supported translations you want to have.

LANGUAGES = (
    ('en', u'English'),
    ('de', u'Deutsch')
)

The only required setting by MetaLingual is telling it what the default language is. You do so by assigning a callable that returns the language code. It it's simplest form:
METALINGUAL_DEFAULT_LANGUAGE = lambda: 'en'

You can also use a function:

def get_default_language():
    # code here to get the site's default language in some customised way. i.e. from an external file or network location
    # or even from the database.
    return 'en'


METALINGUAL_DEFAULT_LANGUAGE = get_default_language

To temporary disable translation for a model:

class MyModel(models.Model):
    def do_something_without(self):
        self._meta.get_field('metaLingual').disabled = True
        # do stuff here without metaLingual
        # ...
        # done, so re-enable metaLingual.
       
self._meta.get_field('metaLingual').disabled = False

What's not supported:

  • admin interface integration (patches are most welcome!!)


ċ
metalingual.py
(10k)
Tim Kersten,
10 May 2010, 06:31
Comments