Translating Wagtail snippets

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.

July 12, 2020, 8:47 a.m.
Themes: Multiple languages

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)