Multilingual content - yet another idea

119 views
Skip to first unread message

marcin.k...@gmail.com

unread,
Jan 22, 2007, 6:33:30 PM1/22/07
to Django users
Hi,

I am developing a website that contains mainly multilingual content.
There were some questions and ideas on this list on how to achieve
it, so I thought I would share mine and see if anyone else finds it
useful. I have a working prototype, although not ready for production
use yet.

An example will explain how I use it. Take a really minimal Category
model:

class Category(models.Model):
# First, some fields that do not need translations
creator = models.ForeignKey(User)
created = models.DateTimeField(auto_now_add=True)

# And now the translatable fields
class Translation:
"""
The definition of translation model.

The multilingual machinery will automatically add these to the
Category class:
* get_name(language_id=None)
* set_name(value, language_id=None)
* get_description(language_id=None)
* set_description(value, language_id=None)
* name and description properties using the methods above
"""

name = models.CharField(blank=True, null=False, maxlength=250)
description = models.TextField(blank=True, null=False)

def __str__(self):
# note that you can use name and description fields as usual
return self.name

class Admin:
# again, field names just work
list_display = ('name', 'description')

After defining such a model you access translated fields like this:

c = Category.objects.all()[0]

# get the category name for the default language
c.name
# or
c.get_name()

# get the category name for language with id=2
c.get_name(2)

# change the name for language with id=2
c.set_name('nazwa', 2)

# change the name for the default language
c.name = 'nazwa'
# or
c.set_name('nazwa')

Internally the library creates another model, CategoryTranslation, that
maps Category and language identifiers to the translatable fields.

I don't want to paste all the code here, so I put the details, ideas,
the library itself and a sample application on my blog:
http://blog.elksoft.pl/index.php/2007/01/23/multilingual-content-in-django/

You can get the code here:
http://blog.elksoft.pl/wp-content/uploads/2007/01/multilingual_sample.zip

Let me know what you think about it.

-mk

simonbun

unread,
Jan 23, 2007, 3:05:21 AM1/23/07
to Django users
This kind of translation support is something django really needs in my
opinion. If this gets implemented together with the unicode conversion
by the time 1.0 gets rolled out, i'd be very, very happy.

I've read your blog post and i do have some remarks. I think it's
better not to put the languages in a separate table and then
referencing them with a foreign key. I have implemented something very
similar in another language some time ago, and i distinctly remember
regretting using a separate table. This is because in other parts of
the code you'll need to
lookup which language an id stands for, and that just means unnecessary
lookups.
There were other downsides to using a foreign key, but i can't recall
right now.

So i would use:
CategoryTranslation: category_id | language_code | name | description

and lookups like c.get_name('pl')

In your blog post you have on your todo list:
"another "backend", one that uses name_en, name_pl, name_de fields in
the Category model instead of creating a separate model"

I would really advise against this. The need to add a language to an
existing project is not so uncommon. This would be a major pain using
this system. Instead, as you mention yourself, some kind of caching
mechanism would alleviate enough of the database load.

ashwoods

unread,
Jan 23, 2007, 3:56:17 AM1/23/07
to Django users
i was proposing something "similar" a couple of days ago:

http://groups-beta.google.com/group/django-developers/browse_thread/thread/c01665f5093b4895

On Jan 23, 12:33 am, "marcin.kaszyn...@gmail.com"

> the library itself and a sample application on my blog:http://blog.elksoft.pl/index.php/2007/01/23/multilingual-content-in-d...
>
> You can get the code here:http://blog.elksoft.pl/wp-content/uploads/2007/01/multilingual_sample...

marcin.k...@gmail.com

unread,
Jan 23, 2007, 4:25:51 AM1/23/07
to Django users
ashwoods napisał(a):

> i was proposing something "similar" a couple of days ago

Very similar, yes. I know, I responded in
http://groups.google.com/group/django-users/browse_frm/thread/585585ec74fc1234/#

Had I noticed your thread earlier, I would have added my version there
instead of creating my own; sorry about that -- now we have three
different threads on the same subject.

-mk

ashwoods

unread,
Jan 23, 2007, 4:29:38 AM1/23/07
to Django users
as i posted in my post, maybe more than one backend would be nice, to
allow the developer the freedom of optimising the database to how he
wants, or write is own backend, without having to change a lot in the
model.

languange_code: its faster to look up a number as index as a languange
code, and to filter too. you can probably avoid a foreign key
altogether if you just define a relationship between languange_id and
the index in a settings.LANGUANGES list.
the LANGUANGES variable would be in memory anyways.

ashwoods

unread,
Jan 23, 2007, 4:31:09 AM1/23/07
to Django users
ah btw, thx marcin. but now i don't know what i am going to be doing in
febraury :)

marcin.k...@gmail.com

unread,
Jan 23, 2007, 4:38:07 AM1/23/07
to Django users
simonbun napisał(a):

> I've read your blog post and i do have some remarks. I think it's
> better not to put the languages in a separate table and then
> referencing them with a foreign key. I have implemented something very
> similar in another language some time ago, and i distinctly remember
> regretting using a separate table. This is because in other parts of
> the code you'll need to
> lookup which language an id stands for, and that just means unnecessary
> lookups.

Either that, or caching the language information too.

> So i would use:
> CategoryTranslation: category_id | language_code | name | description

I would rather have language_id instead of language_code here; it looks
cleaner (more DRY) and is slightly better with regards to performance
in
most cases.

> and lookups like c.get_name('pl')

Right, get/set_name and similar methods should accept language codes
too.

> In your blog post you have on your todo list:
> "another "backend", one that uses name_en, name_pl, name_de fields in
> the Category model instead of creating a separate model"
>
> I would really advise against this. The need to add a language to an
> existing project is not so uncommon. This would be a major pain using
> this system. Instead, as you mention yourself, some kind of caching
> mechanism would alleviate enough of the database load.

That's true. On the other hand, being able to pull all the translated
content
as a single row together with non-translatable data would make it
easier
to do ordering and filtering based on translations. It is possible to
do with
a separate table, too, but in some cases requires more complex queries.

Also, adding a language would mean a small change to all the models
with translations. It should be easy to do automatically during
syncdb:
some code that goes through a list of all installed models, finds those
that have translations configured with that backend and adds columns
as necessary.

-mk

Aidas Bendoraitis

unread,
Jan 23, 2007, 4:39:56 AM1/23/07
to django...@googlegroups.com
The problem with this kind of translation implementation is that you
can't normally sort the translated items alphabetically.

I would still propose the implementation that I suggested earlier:
http://groups.google.com/group/django-users/browse_frm/thread/e9545ee84a797e1b/de9ffbc0c79a3a17?lnk=gst&q=Aidas+Translatable&rnum=1#de9ffbc0c79a3a17

Regards,
Aidas Bendoraitis aka Archatas

marcin.k...@gmail.com

unread,
Jan 23, 2007, 6:37:26 AM1/23/07
to Django users
I had some problems with replying to this message. I'm trying again,
I hope I won't end up with two very similar messages posted.

Aidas Bendoraitis napisał(a):


> The problem with this kind of translation implementation is that you
> can't normally sort the translated items alphabetically.

Actually you can, but it requires some work with querysets and gets
complex quickly, especially when you want conditions like 'filter by
the
contents of Polish description if available and English otherwise'.

Also, it would require patching Django to support left joins. I have
a patch for that, but it is a quick hack, using syntax like
Model.objects.filter(LEFTJOIN_othertable__field=value).

If I understand correctly, I implemented exactly what you described,
storage-wise, with a different way to declare translatable fields.

-mk

marcin.k...@gmail.com

unread,
Jan 23, 2007, 6:44:09 AM1/23/07
to Django users
ashwoods napisał(a):

> ah btw, thx marcin. but now i don't know what i am going to be doing in
> febraury :)

Helping me create a working library, I hope :)

My implementation is a prototype, written in large part to see if I can
do
it without modifying Django. There are gaping holes, ie. right now the
library assumes that all translation objects are always available. On
the
other hand, I do need a working solution suitable for production use
soon,
so I am very interested in fixing this.

I think I should put it in a publicly accessible svn soon.

-mk

PS. I had some problems with sending this message. I'm trying again,

marcin.k...@gmail.com

unread,
Jan 23, 2007, 7:34:50 AM1/23/07
to Django users
Replying to myself:

> Also, it would require patching Django to support left joins.

This might not be necessary after all, I just found this:

http://groups.google.com/group/django-developers/browse_frm/thread/e071bb8bf57ec0a7/4ad039f4ea8ce50e?lnk=gst&q=left+join&rnum=3#4ad039f4ea8ce50e

Which means that the "separate table for translations" backend should
not require changes to Django core after all.

-mk

nesh

unread,
Jan 23, 2007, 8:57:11 AM1/23/07
to django...@googlegroups.com
* marcin.k...@gmail.com wrote, On 23.01.2007 13:04:
>> > Also, I suspect that some changes must be done inside Django ORM layer to support this.
>
> Using the "separate table" backend, yes, I will need left joins to do
> allow sorting and filtering by the values of translatable fields.

As I said in django-devel, I don't like solution which will add yet another table for any model that needs to be translated.

> The "separate columns for each language" backend does not require any
> changed to Django, as far as I can see. Even table updates in syncdb
> are doable without touching Django source.

If you go this way you can drop class Translation altogether, it's little awkward to require to define translatable
fields below class definition. IMHO better approach is to use (revamped ;)) I18N(Char|Text)Field.

Ideally implementation can look like this:

class Category(models.Model):
[...]
name = I18NCharField(blank=True, null=False, maxlength=250)
description = I18NTextField(blank=True, null=False)

and then Field classes can add name_[lng[0] for lng in settings.LANGUAGES] fields.

Back to the problem, I can see several use cases for the dynamic data translation:

1. Translate field content
--------------------------

Use similar approach as gettext for translation -- I'm working on this.

2. Models which contain data that depends on the language
---------------------------------------------------------

Using language field paired with some custom manager is the simplest method.
IMHO this is trivial to achieve. Simply add one field and some manager methods. OTOH if one have lot's of models like
this some level of the automation is nice to have.


3. Mixed models, translatable and not translatable data together
----------------------------------------------------------------

Your's 'separate table' or 'separate columns' approach.

This is a ideal solution if it can be implemented in the general way without constraints to other model properties
(unique, unique_together, db_index, validators, ...)

Ideally translatable model will behave like any ordinary model hiding the fact that some his fields are stored somewhere
else (in separate table or separate columns) and it will support all of the common model operations.


Any other?


--
Nebojša Đorđević - nesh, ICQ#43799892
Studio Quattro - Niš - Serbia
http://studioquattro.biz/ | http://trac.studioquattro.biz/djangoutils/
Registered Linux User 282159 [http://counter.li.org]

ashwoods

unread,
Jan 23, 2007, 9:29:35 AM1/23/07
to Django users
nesh wrote:

>>it is possible using object registry to get all translations for the object *field*, it is (a little) more complicated
to get translated *objects* though, and adding tags to get counts will
be trivial.

Multiple translation on the same page are possible, for example one can
do:

{% load i18n %}
{% get_available_languages as languages %}
{% for lng in languages %}
{% translate <object> <field> to lng %}
{% endfor %}

to display all translations for the object field.

All logic can be put into template tags (where it belongs) for template
designers.

>>end of quote...

ah those are just two examples that came out of mind. like i said
earlier, i know "translating" should be done in the templates. but what
if you want to "work" or modify the text, depending on what languange
it is. that you add text depending on the languange, or supress text.
if you want to parse all the foreign currency and convert it to euros
ONLY if the original languange is not russian, and if it is in spanish
you want to add a "(this is a noun)" string to every noun. im not
saying it should be the default way of translating, but if you want to
WORK on your data depending on the languange, that is, do more than
just filter or choose a languange, those methods would come in handy.

>> start quote:
f I understood you correctly, you want different objects for different
languages? In that case I simply use something
like this:

class Foo(models.Model):
<fields>
lang = models.CharField(choices=settings.LANGUAGES,
default=get_language, maxlength="3", db_index=True)
[...]

>> end quote.

maybe on of the backends we will do might do just this. I said earlier,
there are so many different cases, and this one cuts only for one. in
my initial post, i said that it might be good to choose which fields
are translated.

for example: i have a model that looks like this:

class EconomicData(models.Model):
country = models.ForeignKey...
economic_indicator_1 = models.Integer...
....
....
economic_indicator_145 = models.integer...
...
...
economic_indicator_2032 = models.integer...
economic_survey = models.TextField..
economic_description = models.CharField...

and say, this class, with over 2032 numerical fields, only needs two
fields to be translated, survey and description. so if u do it like u
proposed above, your going to have a big database where most of the
translation rows are empty. not so good.

so what we "want" in _some_ cases is to have a "child" object where
only fields we want to translate are there.

or maybe in another "backend", we may choose to do:

class EconomicData(...
....
....
economic_survey_en = models.TextField..
economic_description_en = models.CharField...
economic_survey_de
economic_description_de


this would not be my ideal way of doing it, but it would give more
(database) performance, for less flexibility.
but if we code the Translation class allowing more than one "backend",
we can give the developers choice, and flexibility, only having to
change the backend or using one backend for some models and another
backend for others. if you are going to have a lots of models, maybe u
prefer this method (less tables), but if you have few models but maybe
adding a lot of languanges, etc... you may prefer the other. :)

important is that each backend offers the same methods, (filtering,
ordering by languange, getting one "translation" but returning the
original if it is empty or non existant), so that the user does not
have to use different methods in the Model depending on what backend he
is using.

start quote:
One drawback of having translation tied to the objects are that
translations are not reusable -- if you translate some
content you can't reuse that for another object with the same data. I
use central translation repository (table) for all
translated data so if someone already translated same message (for
another object) it can be reused (and also it will
check for django gettext translation).
end quote:

yes, the translations are not reusable if used as above. as i said
earlier, it just depends on the type of application we are using. thats
why it is good if we have more than one backend :) the examples above
are good if: the content of one languange is completly independent of
the other, or if you are doing very "loose" translations, which i think
applies to most ML _content_.

For a more literal sentence to sentence or text to text translation, a
backend that supports a unique translation table/or flat files would of
course be better. but i think this is mostly used when translating
apps, but not in a typical CMS content use.

That is the difference between LinguaPlone
(http://plone.org/products/linguaplone) and placeless translations
http://plone.org/products/pts in plone.

Linguaplone (the product for handling ML _content_) just keeps track
of the relation between objects, and makes adding (for the end user) ML
content easy. It does it non-intrusive (it doesnt modify your original
objects). if you deinstall all your objects are still there, only the
relation between them are gone. (and come back if u reinstall). it
would be nice if we can manage that. (its a little more difficult in a
DBS as in zodb, it all depends how we manage child/parent
relationships)

ok, now i need to study a bit :)

cheers, ashley

Aidas Bendoraitis

unread,
Jan 23, 2007, 9:47:26 AM1/23/07
to django...@googlegroups.com
If the translatable fields are in the same table but with different
extensions, it will be unstable to add more languages dynamically (as
ALTER TABLE is not recommended in SQL on the production server).

Extending model manager seems the most djangoish way to me to
implement translatable content.

Replying to Marcin, I'll try to play around with JOINS this evening.
Somewhy I believe that there is nothing complex with taking the
different value if the necessary one doesn't exist -- maybe just one
CASE WHEN, IF, or IFNULL. Or maybe the translation of the default
language shouldn't be retrieved at all? Shouldn't the untranslated
field just return an empty value and then the template could suggest a
link to the original text reporting about the missing translation?

Regards,
Aidas Bendoraitis aka Archatas

ashwoods

unread,
Jan 23, 2007, 9:54:34 AM1/23/07
to Django users

> fields below class definition. IMHO better approach is to use (revamped ;)) I18N(Char|Text)Field.
>
> Ideally implementation can look like this:
>
> class Category(models.Model):
> [...]
> name = I18NCharField(blank=True, null=False, maxlength=250)
> description = I18NTextField(blank=True, null=False)
>
> and then Field classes can add name_[lng[0] for lng in settings.LANGUAGES] fields.

well, where we define which translation fields is actually arbitrary.
we would still need a Translation class to
do non-field configurations (like define the backend, you should be
able to choose this per-model).
or, what languanges you want to force, ok, that can be done in the
fields too. but i like that translation class because you don't really
have to "touch" the original model, and makes converting existing
applications to be translatable a bit easier.

there are other reasons for me too. the model fields already have:
model definition information. model admin interface display
information. then the model translation information (if you want I18n,
if you want to force that languange or default it, if it can be a
parent languange or not, etc...) like i said, this is not only about
where to store the information. we want the admin interface to offer
some extra goodies too, to make adding ML content easier. so there will
be a couple of extra translation settings for each field that have to
do for translation.

then i might want to add a Node class, that does the same thing as the
Translation class to a model, but to offer an easy way of making a
model hierarchical. i can do that now. but i want a generic easy way of
applying it to all my models. and i will probably do that with a Admin,
Translation, Hierarchy class syntax. so it might make sense to group
things a bit unless you want really chunky and neverending field
definitions in the original model.


>
> Use similar approach as gettext for translation -- I'm working on this.
>
> 2. Models which contain data that depends on the language
> ---------------------------------------------------------
>
> Using language field paired with some custom manager is the simplest method.
> IMHO this is trivial to achieve. Simply add one field and some manager methods. OTOH if one have lot's of models like
> this some level of the automation is nice to have.
>

agreed, but if we are going to have mixed models, might as well make
the syntax the same for both and have a backend that manages this
transparently for the user.


> Ideally translatable model will behave like any ordinary model hiding the fact that some his fields are stored somewhere
> else (in separate table or separate columns) and it will support all of the common model operations.
>

well, these are more or less the cases i described in my first post.
and this last sentence of yours is our goal :) in other words, some
sort of linguaplone for django models. :)

ashwoods

unread,
Jan 23, 2007, 10:00:32 AM1/23/07
to Django users
well, i dont like the translatable fields with different extensions
either. but maybe someone else might (for his reasons, maybe a
performance matter (although i don't know how much the difference would
be really). the only thing I am advocating is to write everything
uncoupled so that if someone _wants_ to write a backend that arranges
things like this, he can, without having to alter the model and view
code.


> Shouldn't the untranslated
> field just return an empty value and then the template could suggest a
> link to the original text reporting about the missing translation?

how i would use it in my site is on the top i would have a text saying
that the translation is not available, and then display the original
below. (a direct "languange" link would "change" languange in the
session, maybe changing the UI languange too)

soo a shortcut to do this would be neat, but can also be done with two
separate queries.

marcin.k...@gmail.com

unread,
Jan 23, 2007, 1:31:14 PM1/23/07
to Django users
nesh napisał(a):

> > The "separate columns for each language" backend does not require any
> > changed to Django, as far as I can see. Even table updates in syncdb
> > are doable without touching Django source.
>
> If you go this way you can drop class Translation altogether, it's little awkward to require to define translatable
> fields below class definition. IMHO better approach is to use (revamped ;)) I18N(Char|Text)Field.

I like the Translation class because it is generic: it allows me to
make any field translatable.

I can easily imagine models with language-dependent:

* URLFields: "Producer's web page describing the product in this
language",
* EmailField: "The right contact address for queries in this
language",
* SlugField: slug to use when accessing this version of an object; I
want /en/category-name-1/
and /pl/nazwa-kategorii-1/ point to the same Category object, but in
different languages,
* ImageField: an image of something containing localized text,
* XMLField: XML documents with localized content,

This is off the top of my head after a quick look at the model
documentation page,
there are probably more use cases I can not think of right now. It
will also work with
fields that are not in Django core.

> 2. Models which contain data that depends on the language
> ---------------------------------------------------------
>
> Using language field paired with some custom manager is the simplest method.
> IMHO this is trivial to achieve. Simply add one field and some manager methods. OTOH if one have lot's of models like
> this some level of the automation is nice to have.

It is only that simple if you do not need to track the connection
between different
language versions of the same content. In that case I agree, it is
trivial, but this
means we are not talking about translations anymore, only separate
pieces of
data in different languages.

The connection is the added value I need here.

> 3. Mixed models, translatable and not translatable data together
> ----------------------------------------------------------------
>
> Your's 'separate table' or 'separate columns' approach.
>
> This is a ideal solution if it can be implemented in the general way without constraints to other model properties
> (unique, unique_together, db_index, validators, ...)

These two cases are the same to me. Case 2 simply contains the minimum
non-translatable information: a "master" ID shared between all the
translations,
allowing me to find all the translations of the same content.

Good point about unique and unique_together, I haven't thought about it
yet.

> Ideally translatable model will behave like any ordinary model hiding the fact that some his fields are stored somewhere
> else (in separate table or separate columns) and it will support all of the common model operations.

My thoughts exactly :)

-mk

marcin.k...@gmail.com

unread,
Jan 23, 2007, 1:37:02 PM1/23/07
to Django users
Aidas Bendoraitis napisał(a):

> Replying to Marcin, I'll try to play around with JOINS this evening.
> Somewhy I believe that there is nothing complex with taking the
> different value if the necessary one doesn't exist -- maybe just one
> CASE WHEN, IF, or IFNULL. Or maybe the translation of the default
> language shouldn't be retrieved at all? Shouldn't the untranslated
> field just return an empty value and then the template could suggest a
> link to the original text reporting about the missing translation?

On second thought, you are correct. Left joins let you
put all the translations in a single row and create an illusion
of one big table with translations in different columns, so you
can use any condition and operation you need.

A short drive to a meeting was what I needed to look at
it from this perspective :)

-mk

Aidas Bendoraitis

unread,
Jan 23, 2007, 1:55:16 PM1/23/07
to django...@googlegroups.com
This is exactly what I had in mind :)

I am installing python, svn, and Django on my personal machine and
will do a couple of experiments regarding multilingual content at my
spare time the next days.

Regards,
Aidas Bendoraitis aka Archatas

ashwoods

unread,
Jan 23, 2007, 2:10:27 PM1/23/07
to Django users
yahoo! this is great :D

mk, why don't you just create a project at google code and put what you
have in svn there?

ashley

On Jan 23, 7:55 pm, "Aidas Bendoraitis" <aidas.bendorai...@gmail.com>
wrote:


> This is exactly what I had in mind :)
>
> I am installing python, svn, and Django on my personal machine and
> will do a couple of experiments regarding multilingual content at my
> spare time the next days.
>
> Regards,
> Aidas Bendoraitis aka Archatas
>

marcin.k...@gmail.com

unread,
Jan 23, 2007, 3:42:18 PM1/23/07
to Django users
ashwoods napisał(a):

> mk, why don't you just create a project at google code and put what you
> have in svn there?

Cool, I did not know Google provided public project hosting.

I created a project and uploaded the source code from
my example. See http://code.google.com/p/django-multilingual/

I did not change anything yet, only moved the files around,
so all the bugs and problems are there. I will be working on
it in the nearest future.

If anyone is interested in helping then please send me an
email at marcin.k...@gmail.com and I will add you
to the list of project members. Google Code only
allows adding gmail accounts, so you need to have one.
I believe it is not a problem, but if it is let me know.

So that would be the "release early" part, now please help
me release often :)

-mk

marcin.k...@gmail.com

unread,
Jan 25, 2007, 8:39:51 PM1/25/07
to Django users
Hi,

I had some time to work on the library today. Man, am I learning
about Django :)

So far everything seems to be working out nicely. Changes made since
the previous version:

Translations are cached now and only saved when the master object is.
This makes them behave more like real fields now.

All the data for an object with translatable fields is being read in a
single row using left joins, as Aidas suggested, so ordering and
filtering should not be that difficult after all. There is a problem
with admin views, as they only allow sorting by fields. I am not sure
yet, but perhaps 'proxy fields' for the translatable content would be
a good idea here. They would behave much like normal fields but use
the objects in translation cache to store and retrieve values. This
would also make it easier to use the automatic change views.

The library installs a custom manager in the master model, so you can
not set your own manager now. I think it would be a better idea to
use a wrapper around the manager provided by the developer (or
django.db.models.Manager by default).

The more I work on this the more I doubt that the 'different columns'
backend will be necessary. It would potentially mean a bit faster
read and much faster save operations, but in practice the vast
majority of operations are reads. It would be cool to check the
actual speed difference in reads, but I will have no time to measure
it before getting the library to work with the current backend. And
finishing the service I need the library for now.

There is still a lot to do:

a) make ordering and filtering work in QuerySet methods (probably by
creating a new QuerySet subclass in MultilingualModelManager), so
that order_by('name') works like order_by('name_en') or
order_by('name_pl') depending on the default language; same goes
for filter(name__like='asd') and similar operations,

b) make ordering and filtering work in admin (if done properly,
perhaps with the proxy fields, it might make fix the previous issue
as well),

c) make it possible to request a QuerySet yielding objects with a
specified default language,

d) make admin change views work (they work reliably only for objects
created via the admin interface),

e) make it possible to use custom managers in translatable models
again by using a manager wrapper,

f) clean up: move the language list to settings and move most of the
code out of multilanguage.models. Actually the only reason to use
this file is the very last line, that overrides ModelBase.__new__
when Django loads the multilingual application. I would gladly get
rid of this hack, but it will require changing Django to send a
pre_new signal just before ModelBase creates the new class. I will
submit a ticket for it as soon as I have a working patch, but it
has lower priority than the rest.

...and probably more. I could use some help, testing, comments and
ideas now :) The code is at
http://code.google.com/p/django-multilingual/

-mk

ashwoods

unread,
Jan 28, 2007, 11:23:04 AM1/28/07
to Django users
i'll be testing it tonight :)

On Jan 26, 2:39 am, "marcin.kaszyn...@gmail.com"

daev

unread,
Jan 28, 2007, 1:03:11 PM1/28/07
to Django users
I have trouble in admin list view. Fields under translation has
incorrect column header in list.

marcin.k...@gmail.com

unread,
Jan 28, 2007, 5:39:59 PM1/28/07
to Django users
On 28 Sty, 17:23, "ashwoods" <ashwo...@gmail.com> wrote:
> i'll be testing it tonight :)

Cool :)

I just committed a version that does ordering and sorting
on the translated fields using the database api, so now it
is possible to:

* order_by('name'),
* order_by('name_en'),
* filter(name__contains='blah'),
* filter(name_pl__contains='blah'),

and so on. There is still a lot to do, though -- in particular,
I think that making sorting work in admin will require
patching the admin views after all.

-mk

marcin.k...@gmail.com

unread,
Jan 28, 2007, 5:50:15 PM1/28/07
to Django users
Hi daev,

On 28 Sty, 19:03, "daev" <daeva...@gmail.com> wrote:
> I have trouble in admin list view. Fields under translation has
> incorrect column header in list.

you are right, there is a problem with column headers.

Unfortunately there is no way around it right now. I changed
the library so that you see the correct column header when
you put get_field_name instead of name in list_display, but that
is all I can do for now.

I added a ticket for that, for more detailed explanation see:
http://code.google.com/p/django-multilingual/issues/detail?id=7

Thanks :)
-mk

marcin.k...@gmail.com

unread,
Jan 29, 2007, 4:04:08 PM1/29/07
to Django users
Replying to myself again:

On 28 Sty, 23:50, "marcin.kaszyn...@gmail.com"

<marcin.kaszyn...@gmail.com> wrote:
> > I have trouble in admin list view. Fields under translation has

> > incorrect column header in list.you are right, there is a problem with column headers.


>
> Unfortunately there is no way around it right now.

Well, I was wrong and there was a way around it. I just committed
a new version that displays correct column headers in admin list view.
It does not require any workarounds anymore.

-mk

marcin.k...@gmail.com

unread,
Jan 31, 2007, 9:51:09 AM1/31/07
to Django users
Hi,

the library is getting very close to being actually usable in real
projects.

There were several changes in the last few days. It is now possible
to:

1. use language codes in methods that until now accepted only language
IDs;

2. create query sets with default language set, so that the following
tests pass:

>>> c_en = Category.objects.all().for_language('en')
>>> c_pl = Category.objects.all().for_language('pl')
>>> c_en.get(name__contains='1').name
'category 1'
>>> c_pl.get(name__contains='1').name
'kategoria 1'

>>> [c.name for c in c_en.order_by('name')]
['category 2', 'category 1']
>>> [c.name for c in c_pl.order_by('-name')]
['kategoria 2', 'kategoria 1']

Objects created using such a queryset also have a default language
set:

>>> c = c_en.get(id=1)
>>> c.name = 'test'
>>> (c.name, c.name_en, c.name_pl)
('test', 'test', 'kategoria 1')

>>> c = c_pl.get(id=1)
>>> c.name = 'test'
>>> (c.name, c.name_en, c.name_pl)
('test', 'category 1', 'test')

3. order the admin list view according to the value of translatable
column; this requires a small and generic patch to Django, see
http://code.djangoproject.com/ticket/3397

You can still use the library without any changes to Django source,
the only difference will be that translatable columns will not be
sortable. I hope the patch will be included, though, because there
are more use cases for the patch than django-multilingual :)

4. use the translatable fields to create filters spanning multiple
tables, like `somemodel.filter(category__name__contains='2')`,

5. assign directly to translatable fields in different language
versions. These two have the same effect:

c.set_name('category name', 'en')
c.name_en = 'category name'

The last big piece missing is a better inline editor for translated
content. Right now it is still a hack that works correctly mostly for
instances created by the admin interface. I hope to have this working
soon.

-mk

daev

unread,
Feb 1, 2007, 3:52:15 AM2/1/07
to Django users
> <marcin.kaszyn...@gmail.com> wrote:
>
> Well, I was wrong and there was a way around it. I just committed
> a new version that displays correct column headers in admin list view.
> It does not require any workarounds anymore.
>
> -mk
Thanks. But i still have this problem. Even after update my work copy
of code

I want to say some word about usage of your workaround:
-i move LANGUAGES into settings file and make it tuple of tuble not
lists. Why do you not do so?:)
-i write MultilangualMiddleware. It check request language code and
set default language. It helps me not to rewrite my existing code.
And i want to thank you. Your code very helps me

PS: Sorry for my English

marcin.k...@gmail.com

unread,
Feb 1, 2007, 8:07:26 AM2/1/07
to Django users
On 1 Lut, 09:52, "daev" <daeva...@gmail.com> wrote:
> Thanks. But i still have this problem. Even after update my work copy
> of code

Strange. Could you send me your model?

Also, could you try the Category model from testproject? It works for
me
and shows fields' verbose_names in column headers.

> I want to say some word about usage of your workaround:
> -i move LANGUAGES into settings file and make it tuple of tuble not
> lists. Why do you not do so?:)

Frankly, it is because I did not find a good name for it and did not
want
to create something temporary. But you are right, I should do that
soon :)

Same goes for tuples vs lists. To me the difference here is mainly
cosmetic, but I agree that tuples are a bit better choice for data
that
should not be modified.

> -i write MultilangualMiddleware. It check request language code and
> set default language. It helps me not to rewrite my existing code.

Great. That was the purpose of set_default_language since the
beginning,
I just did not get to writing the middleware yet. I do want to add
something
like this to the library, would you mind sharing your solution?

Which reminds me, I need to change set_default_language to use
threadlocals. Right now the library is broken for multithreaded
applications.

> And i want to thank you. Your code very helps me

Glad to hear that. Now help me test it :)

-mk

Aidas Bendoraitis

unread,
Feb 1, 2007, 8:15:11 AM2/1/07
to django...@googlegroups.com
Regarding the list of available languages, I think that the
translation system should use the settings, provided by default
(LANGUAGE_CODE and LANGUAGES) instead of ids or other list variables.
http://www.djangoproject.com/documentation/settings/#language-code

Regards,
Aidas Bendoraitis

marcin.k...@gmail.com

unread,
Feb 1, 2007, 9:32:00 AM2/1/07
to Django users
On 1 Lut, 14:15, "Aidas Bendoraitis" <aidas.bendorai...@gmail.com>
wrote:

> Regarding the list of available languages, I think that the
> translation system should use the settings, provided by default
> (LANGUAGE_CODE and LANGUAGES) instead of ids or other list variables.http://www.djangoproject.com/documentation/settings/#language-code

This might be a good idea. Partially.

The library still needs to have language IDs internally to make all
the joins fast, but they should probably be hidden from application
developer. I already started changing the code in this direction: it
supports using language codes everywhere now, including
set_default_language and .for_language functions.

My plan is to add a model similar to ContentType that would map
language codes to IDs. It would be managed completely by the library,
because any changes to it should happen during application
initialization to be effective. Right now changing the list of
languages might break things, as language IDs are based on language
position in the list, but with such a mapping it would be possible to
add and remove languages without losing information. It would also
allow for different sites using the same data presented in different
languages.

But I am not so sure that the two lists of languages should be
identical. The Django setting is for interface translations and mine
is for content. It is very common to have interface available in more
languages than content. There are also performance concerns: each
language handled by D-M means another join in every query and another
set of fields added to every instance of a translatable model.

Another thing to consider is the admin interface. I want to create an
editor for translated content that is easy to use; this means
different things for sites with small number of translations (2-4
languages, which probably means most multilingual sites) and for
sites with 30 languages or so (which is the default length of the
LANGUAGES setting).

Perhaps I should just add another tuple, say, MODEL_LANGUAGES, that
would just contain codes of languages that should be handled by django-
multilingual. The language names would be taken from Django LANGUAGES
setting and the mapping to IDs would be hidden from user. Adding or
removing a language code to MODEL_LANGUAGES would just work like you
would expect: all translations for that model would simply appear or
hide.

How does it sound? I do appreciate all suggestions.

-mk

ashwoods

unread,
Feb 1, 2007, 2:30:40 PM2/1/07
to Django users
im having problems making the testproject work. i get a
'multilingual_tags' is not a valid tag library: Could not load
template library from django.templatetags.multilingual_tags, cannot
import name get_language_code
although i copied mult..tags to django.templatetags. never used
templatetags myself, i might be missing something.
i am a newbie after all.

although, i just commited to svn a patch for reading the languanges
from the settings.py file :)

take care,
ashley

On Jan 28, 11:39 pm, "marcin.kaszyn...@gmail.com"

marcin.k...@gmail.com

unread,
Feb 1, 2007, 3:33:36 PM2/1/07
to Django users
On 1 Lut, 20:30, "ashwoods" <ashwo...@gmail.com> wrote:
> im having problems making the testproject work. i get a
> 'multilingual_tags' is not a valid tag library: Could not load
> template library from django.templatetags.multilingual_tags, cannot
> import name get_language_code

Make sure you have the current source code :) I fixed this problem
yesterday.

> although i copied mult..tags to django.templatetags. never used
> templatetags myself, i might be missing something.

You should not copy the file anywhere, the problem was caused by my
cleaning up the code and not doing enough testing before commits.

Remember to remove the copy you made or you might run into problems
with Django not picking the right version of multilingual_tags.

> although, i just commited to svn a patch for reading the languanges
> from the settings.py file :)

Thanks! Although I do think we will have to improve the
configuration, as Aidas suggested.

The more I think about it the more I like the idea with storing
language IDs in the database, but only reading (or creating) them
during application startup. I have to fix the admin page first,
though.

-mk

marcin.k...@gmail.com

unread,
Feb 5, 2007, 12:41:51 PM2/5/07
to Django users
Hi daev,

On 1 Lut, 09:52, "daev" <daeva...@gmail.com> wrote:

> Thanks. But i still have this problem. Even after update my work copy
> of code

you were right, there was a bug that would cause incorrect table
headers for fields without verbose_name explicitely set in model
definition. I found and fixed it today. I also improved the inline
editor in admin -- it could still use some work, but at least works
correctly for all cases now.

In the meantime I started using the library in a real project and
found out that the inner, magical Translation class does not work too
well in practice, because without d-m loaded the Translation
definition is simply ignored without a warning. This happens, among
others, in "manage.py shell" if you forget to import
multilingual.models before loading the models you want to actually
use.

I changed the syntax a bit to make the dependency explicit and make
sure that django-multilingual gets imported in every model that needs
translations:

import multilingual
[...]
class Article(models.Model):
[...]
class Translation(multilingual.Translation):
title = models.CharField(verbose_name=_("The title"),
blank=True, null=False, maxlength=250)

This does not look as nice, but you get used to it quickly and get
much more usable models as a result. The code that makes it all
possible is still messy though.

-mk

Reply all
Reply to author
Forward
0 new messages