django-translated-fields – localized model fields without magic
There are many ways to save and retrieve multilingual content in a database; countless blog posts, emails and software packages have been written discussing or helping with this problem.
Two main approaches exist to tackle the problem:
- Use a table for the language-independent content, and a table for language-specific content. The latter most often has a foreign key to the former and a language field. There will be a record in the latter table for each record in the former, or less if some dataset isn’t available in all languages. django-hvad, django-parler and also FeinCMS 1’s translations module follow this approach.
- Use only one table, but use several fields to store the localized data. django-modeltranslation is probably the best known app implementing this approach.
(Other ways of course exist. Among the more interesting packages (to me) are django-nece using Postgres’ JSONB fields and django-vinaigrette using gettext.)
Why write another package?
The features they provide are at costly to implement and hard to maintain. For example, django-modeltranslation supports adding translations to third party apps which themselves do not support any translations, but to do this it has to not only provide properties for attribute access on models, but also hook into querying, into form generation, into model admin classes, and implement generic fallback logic etc. so that the current language is respected everywhere transparently.
This does not only sound complex, it is! And the efforts and ingenuity that went into supporting those features have to be respected – I certainly do.
But, couldn’t I just help out instead of adding another package solving the same problem?. Yes, that I could. But time is limited, and even taking future maintenance into account it sometimes is easier – and more fun – to rewrite than to refactor, especially if you’re not trying to solve the exact same problem.
django-translated-fields
And that’s where django-translated-fields enters the fray.
While other packages contain thousands of lines of code, this package contains a good-enough solution in less than 50 lines of code, when ignoring the translated_attributes
class decorator which is orthogonal to the TranslatedField
class. Lines of code is not the only interesting metric of course, but it is a very good predictor of maintenance cost.
Of course the package has significantly less features than any of the other packages mentioned above, but it hits the sweet spot where its features are sufficient for most of our projects.
And living in a country with four official languages (and english isn’t even one of those) it should be easy to believe that after a few years you’ll have plenty of experience providing users and customers with ways to work with multilingual content, and knowing what is necessary and what isn’t.