Translatable webpages in Wagtail

In this tutorial we will make a Wagtail site multilingual.

July 8, 2020, 10:02 a.m.
Themes: Multiple languages

Django offers a lot of functionality for internationalization and localization. In a previous tutorial, we have made all our models, forms, views and templates translatable. For an international site it is obviously also necessary to have the content of the site (articles etc.) available in different languages, which means that our CMS has to handle different languages. There are a few ways to deal with this. One is to make every model available in every language, another is to make every page available in every language. Both have their advantages: model translation can be used for every model, not only for pages, and page translation gives a better overview in admin over the different page trees and leaves the page models simple and untouched. We will use a combination: page translation for the pages and model translation for the non-page models that need translation.

The package that supports page translation for Wagtail is called wagtailtrans. Install it:

pip3 install wagtailtrans

and add it to requirements.txt and to INSTALLED_APPS. As the installation page is instructing us to do, check that wagtail.contrib.modeladmin and wagtail.contrib.settings are in INSTALLED_APPS as well. Add TranslationMiddleware to MIDDLEWARE as instructed:

'wagtailtrans.middleware.TranslationMiddleware', # depends on the SiteMiddleware and replaces LocaleMiddleware
# 'django.middleware.locale.LocaleMiddleware',
WAGTAILTRANS_HIDE_TRANSLATION_TREES = True

By default Wagtail will show all pages in all languages in admin. This is a bit of a clutter; by setting the parameter this is prevented, and the pages in the non-default language are still very easy to select from a submenu.

Now it's time to say goodbye to our Wagtail homepage :-( . In models.py of the home app, comment out the model. We will start with a fresh homepage that will ensure that all pages below it are translatable. Migrate the database:

python3 manage.py makemigrations
python3 manage.py migrate

Make sure you have set at least two languages in your settings file; a previous tutorial shows how. Run the server and go to the Wagtail admin, click Settings in the menu on the left and then Languages; wagtailtrans will list the languages from the settings file. Add the languages that you need to the admin overview; if necessary change the default.

Now go to Pages in the menu, and click on Pages at the top (so do not click on Home). This brings you to an overview called Root, which displays all root pages; in this case there is only one, and it is called Home. We want to create a new root, which makes the whole tree under it translatable. So click on the button 'Add child page' at the top and select 'Translatable site root page' (provided by wagtailtrans). Add a title (e.g. 'Translatable root') and in the green menu below select Publish.

We need to connect this new root page to the site. Go to Settings and then Sites. There should be one site, probably called localhost. Click it and at the setting 'Root page' click 'Choose a different root page'. Choose the new translatable root page and click Save. Now go to Pages in the menu again, you can see that the new page is the root because there is a small globe before it. Delete the other page Home to prevent confusion. Now if you click on the arrow on the right next to Translatable root, we are at the starting point of our page tree where we will add all pages, starting with a home page.

This is very well described in the Wagtail documentation, so we will discuss this briefly. We start by creating a separate app where all our CMS pages will reside:

python3 manage.py startapp cms

Add cms to INSTALLED_APPS. In models.py create a basic home page model:

from wagtail.admin.edit_handlers import FieldPanel
from wagtail.core.fields import RichTextField
from wagtailtrans.models import TranslatablePage

class HomePage(TranslatablePage):
    intro = RichTextField(blank=True)

    content_panels = TranslatablePage.content_panels + [
        FieldPanel('intro', classname='full'),
    ]

Note that we subclass the page from TranslatablePage. Now we need to create a template. By default, Wagtail will look for a template filename formed from the app and model name, separating capital letters with underscores, so in this case home_page.html. Create this template in the directory /cms/templates/cms and add this directory to the TEMPLATES parameter in settings. Put the following content in, very similar to the example in the Wagtail docs:

{% extends "base.html" %}

{% load wagtailcore_tags %}

{% block body_class %}template-homepage{% endblock %}

{% block content %}

    <div class="container-fluid mt-4">
        <div class="page-title">
            <h1>{{ page.title }}</h1>
        </div>
        <div class="page-intro">
            {{ page.intro|richtext }}
        </div>
    </div>

{% endblock %}

We need to load wagtailcore_tags because of Wagtail's filter richtext. The block parameter body_class allows giving a class name to the body of the specific page, to allow individual styling. The variable page is available in every page instance being rendered, so that we can access page.title, page.intro and any other field, attribute or method of the page. We did not need to specify the field title in the model, since it is a standard field of the Page model.

Migrate the database to add the model to it. Now we're ready to create the page in Wagtail's admin. Go to http://127.0.0.1:8000/admin, to Pages and choose the Translatable root page. Choose 'Add child page' and choose the newly created HomePage model. Type a title and a text paragraph Intro and publish the page. Now click on 'Edit in' for this page. The other languages become visible. Wagtailtrans has created a copy of the page for every language in the settings. You can translate the text in the appropriate language. Note: wagtailtrans only copies the text to all other language pages when the page is created; after that it is up to you to do that.

By default Wagtail and wagtailtrans automatically create slugs for new pages; you can view them in the tab 'promote'. The slug of language homepages should always be set to the language code (not referenced in latest docs), otherwise the root / doesn't point to any page. So change the slug for the English home page to /en/ and likewise for the other languages.

If you would like to add more pages, including StreamField and inline blocks and add some CSS, then read on.

Comment on this article (sign in first or confirm by name and email below)