I came to a dirty but practical solution for one minor project I had to develop for a client who wanted a website with i18n capabilities and also needed to have the different translations for each candidate values each in a different field, in the same model. That is, one field for each language. Here in this post I explain how to achieve it.

Let's say we have some models with some fields we want to be duplicated, one for each language. In this example, we will store english (en), spanish (es) and french (fr):

class MyObject(models.Model):
        name = models.CharField(max_length=50)
        title_en = models.CharField(max_length=50)
        title_es = models.CharField(max_length=100)
        title_fr = models.CharField(max_length=100)
        description_en = models.CharField(max_length=100)
        description_es = models.CharField(max_length=100)
        description_fr = models.CharField(max_length=100)

class MyOtherObject(models.Model):
        name = models.CharField(max_length=50)
        content_en = models.CharField(max_length=200)
        content_es = models.CharField(max_length=200)
        content_fr = models.CharField(max_length=200)

Notice we append a suffix to each field consisting of an underscore plus the language code. It is important to set the field names this way, as we are going to use a template tag that uses this suffix to find the proper translated field.

Next thing to do is add a new TRANSLATION_FIELDS setting that will contain all the field names for ALL your model fields that you have set to be translated. In our example:

TRANSLATION_FIELDS = ('title', 'description', 'content')

In your app, create the .py file inside the templatetags folder (don't forget to include an __init__.py to make it a python module) and paste this contents. For example, I am going to call it lazy_tags.py:

from django import template
from settings import TRANSLATION_FIELDS

register = template.Library()

class LocalizedContent(template.Node):
    def __init__(self, model, language_code):
        self.model = model
        self.lang = language_code

    def render(self, context):
        model = template.resolve_variable(self.model, context)
        lang = template.resolve_variable(self.lang, context)
        for f in TRANSLATION_FIELDS:
                setattr(model, f, getattr(model, '%s_%s' % (f, lang)))
            except AttributeError:
        return ''

def get_localized_content(parser, token):
    bits = list(token.split_contents())
    if len(bits) != 3:
        raise template.TemplateSyntaxError("'get_localized_content' tag takes exactly 2 arguments")
    return LocalizedContent(model=bits[1], language_code=bits[2])

In order to use the template tag, you first have to load it:

{% load lazy_tags %}

Then call the tag passing it the object and the language code you want to get the object fields translated to. If I need the spanish translation, for example:

{% get_localized_content object 'es' %}

From now on object will be populated with all the properties related with fields to be translated, but without the language code suffix. So, to get the description field, you simply do:

<p>Description: {{ obj.description }}</p>

It is convenient to use this tag altogether with the django.core.context_processors.request context processor in your settings:


This way we can automatically call the tag with the current language code for the session:

{% get_localized_content object request.LANGUAGE_CODE %}

And voilá! Straight to the point. I didn't spend much time searching for similar solutions back when I did this, so there may probably be some people that produced a similar solution. It would be nice if anybody did something better and notify it posting a comment here. Ciao djangonauts!