Django and Wagtail offer excellent possibilities for translation. However if we create model instances (snippets) in our editor, translation is less obvious. This tutorial offers a way around this.
Text in models, views, forms, templates can be translated by using Django's translation options. The content of Wagtail pages can be translated in other ways. Snippet models in Wagtail are neither, so we need to find a way to translate text that we add to snippets in our editor. In earlier tutorials we have used snippets, when defining themes or when creating a menu. To translate pages we have relied on wagtailtrans; it would be great if we could also use this package for snippets as well. Although there are thoughts on this, this is not yet possible.
A solution would be to use the trans
template tag in our template, e.g. {% trans item.title %}
, where item
is a snippet instance. The disadvantage is that Django's translation-string-detecting utility makemessages
will not detect these variables, as mentioned in the Django docs. That means that you would have to manually put in all possible values of all variables in the translation file, every time when such a file is generated. This is clearly suboptimal.
Our method will be to the package django-modeltranslation. I should mention that there is a drawback: translating the model fields needs to be done in Django admin. We would obviously prefer to have this in Wagtail admin. The related package wagtail-modeltranslation does have Wagtail admin integration, but by default it translates Wagtail's Page model, which adds a lot of unnecessary fields, and there is no easy way to prevent this. Forking it and adding a simple switch for this is an option, but has its drawbacks too. So we'll go with django-modeltranslation for now:
pip3 install django-modeltranslation
adding it to our requirements.txt
and putting modeltranslation
in our INSTALLED_APPS
. In some configurations (including mine) it will only work when putting this before django.contrib.admin
, so that's what we'll do. Check that USE_I18N = True
in your settings and that LANGUAGES
defines the languages you need. Now create a file translation.py
in your app and add the models you want to translate, in our case:
from modeltranslation.translator import register, TranslationOptions
from .models import Theme, MenuItem, Menu
@register(Theme)
class ThemeTranslationOptions(TranslationOptions):
fields = ('name',)
@register(MenuItem)
class MenuItemTranslationOptions(TranslationOptions):
fields = ('link_title',)
@register(Menu)
class MenuTranslationOptions(TranslationOptions):
fields = ('title',)
We have to add these models to admin, so that they can be edited there. We will organize our menu items as inlines of our menus:
from .models import Theme, MenuItem, Menu
from django.contrib import admin
from modeltranslation.admin import TranslationAdmin, TranslationTabularInline
class ThemeAdmin(TranslationAdmin):
model = Theme
class MenuItemInline(TranslationTabularInline):
model = MenuItem
class MenuAdmin(TranslationAdmin):
model = Menu
inlines = [MenuItemInline,]
admin.site.register(Theme, ThemeAdmin)
admin.site.register(Menu, MenuAdmin)
Now we migrate the database. This will add extra fields for every language and for every field specified in translation.py
. After having done that, we update the database with the help of the command update_translation_fields
:
python3 manage.py update_translation_fields
Now we are ready to visit Django admin and see our snippets, add translations to them, or even add new items.
If you're interested to build a language switch in your navigation, read on.
Comment on this article (sign in first or confirm by name and email below)