|
@@ -1,679 +0,0 @@
|
|
|
-====================
|
|
|
-Internationalisation
|
|
|
-====================
|
|
|
-
|
|
|
-.. contents::
|
|
|
- :local:
|
|
|
- :depth: 3
|
|
|
-
|
|
|
-.. _multi_language_content:
|
|
|
-
|
|
|
-Multi-language content
|
|
|
-======================
|
|
|
-
|
|
|
-Overview
|
|
|
---------
|
|
|
-
|
|
|
-Out of the box, Wagtail assumes all content will be authored in a single language.
|
|
|
-This document describes how to configure Wagtail for authoring content in
|
|
|
-multiple languages.
|
|
|
-
|
|
|
-.. note::
|
|
|
- Wagtail provides the infrastructure for creating and serving content in multiple languages.
|
|
|
- There are two options for managing translations across different languages in the admin interface:
|
|
|
- :ref:`wagtail.contrib.simple_translation<simple_translation>` or the more advanced `wagtail-localize <https://github.com/wagtail/wagtail-localize>`_ (third-party package).
|
|
|
-
|
|
|
-This document only covers the internationalisation of content managed by Wagtail.
|
|
|
-For information on how to translate static content in template files, JavaScript
|
|
|
-code, etc, refer to the `Django internationalisation docs <https://docs.djangoproject.com/en/3.1/topics/i18n/translation/>`_.
|
|
|
-Or, if you are building a headless site, refer to the docs of the frontend framework you are using.
|
|
|
-
|
|
|
-Wagtail's approach to multi-lingual content
|
|
|
--------------------------------------------
|
|
|
-
|
|
|
-This section provides an explanation of Wagtail's internationalisation approach.
|
|
|
-If you're in a hurry, you can skip to `Configuration`_.
|
|
|
-
|
|
|
-In summary:
|
|
|
-
|
|
|
-- Wagtail stores content in a separate page tree for each locale
|
|
|
-- It has a built-in ``Locale`` model and all pages are linked to a ``Locale`` with the ``locale`` foreign key field
|
|
|
-- It records which pages are translations of each other using a shared UUID stored in the ``translation_key`` field
|
|
|
-- It automatically routes requests through translations of the site's homepage
|
|
|
-- It uses Django's ``i18n_patterns`` and ``LocaleMiddleware`` for language detection
|
|
|
-
|
|
|
-Page structure
|
|
|
-^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-Wagtail stores content in a separate page tree for each locale.
|
|
|
-
|
|
|
-For example, if you have two sites in two locales, then you will see four
|
|
|
-homepages at the top level of the page hierarchy in the explorer.
|
|
|
-
|
|
|
-This approach has some advantages for the editor experience as well:
|
|
|
-
|
|
|
-- There is no default language for editing, so content can be authored in any
|
|
|
- language and then translated to any other.
|
|
|
-- Translations of a page are separate pages so they can be published at
|
|
|
- different times.
|
|
|
-- Editors can be given permission to edit content in one locale and not others.
|
|
|
-
|
|
|
-How locales and translations are recorded in the database
|
|
|
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-All pages (and any snippets that have translation enabled) have a ``locale`` and
|
|
|
-``translation_key`` field:
|
|
|
-
|
|
|
-- ``locale`` is a foreign key to the ``Locale`` model
|
|
|
-- ``translation_key`` is a UUID that's used to find translations of a piece of content.
|
|
|
- Translations of the same page/snippet share the same value in this field
|
|
|
-
|
|
|
-These two fields have a 'unique together' constraint so you can't have more than
|
|
|
-one translation in the same locale.
|
|
|
-
|
|
|
-Translated homepages
|
|
|
-^^^^^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-When you set up a site in Wagtail, you select the site's homepage in the 'root page'
|
|
|
-field and all requests to that site's root URL will be routed to that page.
|
|
|
-
|
|
|
-Multi-lingual sites have a separate homepage for each locale that exist as siblings
|
|
|
-in the page tree. Wagtail finds the other homepages by looking for translations of
|
|
|
-the site's 'root page'.
|
|
|
-
|
|
|
-This means that to make a site available in another locale, you just need to
|
|
|
-translate and publish its homepage in that new locale.
|
|
|
-
|
|
|
-If Wagtail can't find a homepage that matches the user's language, it will fall back
|
|
|
-to the page that is selected as the 'root page' on the site record, so you can use
|
|
|
-this field to specify the default language of your site.
|
|
|
-
|
|
|
-Language detection and routing
|
|
|
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-For detecting the user's language and adding a prefix to the URLs
|
|
|
-(``/en/``, ``/fr-fr/``, for example), Wagtail is designed to work with Django's
|
|
|
-built-in internationalisation utilities such as ``i18n_patterns`` and
|
|
|
-`LocaleMiddleware`. This means that Wagtail should work seamlessly with any
|
|
|
-other internationalised Django applications on your site.
|
|
|
-
|
|
|
-Locales
|
|
|
-~~~~~~~
|
|
|
-
|
|
|
-The locales that are enabled on a site are recorded in the ``Locale`` model in
|
|
|
-``wagtailcore``. This model has just two fields: ID and ``language_code`` which
|
|
|
-stores the `BCP-47 language tag <https://en.wikipedia.org/wiki/IETF_language_tag>`_
|
|
|
-that represents this locale.
|
|
|
-
|
|
|
-The locale records can be set up with an :ref:`optional management UI <enabling_locale_management>` or created
|
|
|
-in the shell. The possible values of the ``language_code`` field are controlled
|
|
|
-by the ``WAGTAIL_CONTENT_LANGUAGES`` setting.
|
|
|
-
|
|
|
-.. note:: Read this if you've changed ``LANGUAGE_CODE`` before enabling internationalisation
|
|
|
-
|
|
|
- On initial migration, Wagtail creates a ``Locale`` record for the language that
|
|
|
- was set in the ``LANGUAGE_CODE`` setting at the time the migration was run. All
|
|
|
- pages will be assigned to this ``Locale`` when Wagtail's internationalisation is disabled.
|
|
|
-
|
|
|
- If you have changed the ``LANGUAGE_CODE`` setting since updating to Wagtail 2.11,
|
|
|
- you will need to manually update the record in the ``Locale`` model too before
|
|
|
- enabling internationalisation, as your existing content will be assigned to the old code.
|
|
|
-
|
|
|
-Configuration
|
|
|
--------------
|
|
|
-
|
|
|
-In this section, we will go through the minimum configuration required to enable
|
|
|
-content to be authored in multiple languages.
|
|
|
-
|
|
|
-.. contents::
|
|
|
- :local:
|
|
|
- :depth: 1
|
|
|
-
|
|
|
-.. _enabling_internationalisation:
|
|
|
-
|
|
|
-Enabling internationalisation
|
|
|
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-To enable internationalisation in both Django and Wagtail, set the following
|
|
|
-settings to ``True``:
|
|
|
-
|
|
|
-.. code-block:: python
|
|
|
-
|
|
|
- # my_project/settings.py
|
|
|
-
|
|
|
- USE_I18N = True
|
|
|
- WAGTAIL_I18N_ENABLED = True
|
|
|
-
|
|
|
-In addition, you might also want to enable Django's localisation support. This
|
|
|
-will make dates and numbers display in the user's local format:
|
|
|
-
|
|
|
-.. code-block:: python
|
|
|
-
|
|
|
- # my_project/settings.py
|
|
|
-
|
|
|
- USE_L10N = True
|
|
|
-
|
|
|
-Configuring available languages
|
|
|
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-Next we need to configure the available languages. There are two settings
|
|
|
-for this that are each used for different purposes:
|
|
|
-
|
|
|
-- ``LANGUAGES`` - This sets which languages are available on the frontend of the site.
|
|
|
-- ``WAGTAIL_CONTENT_LANGUAGES`` - This sets which the languages Wagtail content
|
|
|
- can be authored in.
|
|
|
-
|
|
|
-You can set both of these settings to the exact same value. For example, to
|
|
|
-enable English, French, and Spanish:
|
|
|
-
|
|
|
-.. code-block:: python
|
|
|
-
|
|
|
- # my_project/settings.py
|
|
|
-
|
|
|
- WAGTAIL_CONTENT_LANGUAGES = LANGUAGES = [
|
|
|
- ('en', "English"),
|
|
|
- ('fr', "French"),
|
|
|
- ('es', "Spanish"),
|
|
|
- ]
|
|
|
-
|
|
|
-.. note::
|
|
|
-
|
|
|
- Whenever ``WAGTAIL_CONTENT_LANGUAGES`` is changed, the ``Locale`` model needs
|
|
|
- to be updated as well to match.
|
|
|
-
|
|
|
- This can either be done with a data migration or with the optional locale
|
|
|
- management UI described in the next section.
|
|
|
-
|
|
|
-You can also set these to different values. You might want to do this if you
|
|
|
-want to have some programmatic localisation (like date formatting or currency,
|
|
|
-for example) but use the same Wagtail content in multiple regions:
|
|
|
-
|
|
|
-.. code-block:: python
|
|
|
-
|
|
|
- # my_project/settings.py
|
|
|
-
|
|
|
- LANGUAGES = [
|
|
|
- ('en-GB', "English (Great Britain)"),
|
|
|
- ('en-US', "English (United States)"),
|
|
|
- ('en-CA', "English (Canada)"),
|
|
|
- ('fr-FR', "French (France)"),
|
|
|
- ('fr-CA', "French (Canada)"),
|
|
|
- ]
|
|
|
-
|
|
|
- WAGTAIL_CONTENT_LANGUAGES = [
|
|
|
- ('en-GB', "English"),
|
|
|
- ('fr-FR', "French"),
|
|
|
- ]
|
|
|
-
|
|
|
-When configured like this, the site will be available in all the different
|
|
|
-locales in the first list, but there will only be two language trees in
|
|
|
-Wagtail.
|
|
|
-
|
|
|
-All the ``en-`` locales will use the "English" language tree, and the ``fr-``
|
|
|
-locales will use the "French" language tree. The differences between each locale
|
|
|
-in a language would be programmatic. For example: which date/number format to
|
|
|
-use, and what currency to display prices in.
|
|
|
-
|
|
|
-.. _enabling_locale_management:
|
|
|
-
|
|
|
-Enabling the locale management UI (optional)
|
|
|
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-An optional locale management app exists to allow a Wagtail administrator to
|
|
|
-set up the locales from the Wagtail admin interface.
|
|
|
-
|
|
|
-To enable it, add ``wagtail.locales`` into ``INSTALLED_APPS``:
|
|
|
-
|
|
|
-.. code-block:: python
|
|
|
-
|
|
|
- # my_project/settings.py
|
|
|
-
|
|
|
- INSTALLED_APPS = [
|
|
|
- # ...
|
|
|
- 'wagtail.locales',
|
|
|
- # ...
|
|
|
- ]
|
|
|
-
|
|
|
-Adding a language prefix to URLs
|
|
|
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-To allow all of the page trees to be served at the same domain, we need
|
|
|
-to add a URL prefix for each language.
|
|
|
-
|
|
|
-To implement this, we can use Django's built-in
|
|
|
-`i18n_patterns <https://docs.djangoproject.com/en/3.1/topics/i18n/translation/#language-prefix-in-url-patterns>`_
|
|
|
-function, which adds a language prefix to all of the URL patterns passed into it.
|
|
|
-This activates the language code specified in the URL and Wagtail takes this into
|
|
|
-account when it decides how to route the request.
|
|
|
-
|
|
|
-In your project's ``urls.py`` add Wagtail's core URLs (and any other URLs you
|
|
|
-want to be translated) into an ``i18n_patterns`` block:
|
|
|
-
|
|
|
-.. code-block:: python
|
|
|
-
|
|
|
- # /my_project/urls.py
|
|
|
-
|
|
|
- ...
|
|
|
-
|
|
|
- from django.conf.urls.i18n import i18n_patterns
|
|
|
-
|
|
|
- # Non-translatable URLs
|
|
|
- # Note: if you are using the Wagtail API or sitemaps,
|
|
|
- # these should not be added to `i18n_patterns` either
|
|
|
- urlpatterns = [
|
|
|
- path('django-admin/', admin.site.urls),
|
|
|
-
|
|
|
- path('admin/', include(wagtailadmin_urls)),
|
|
|
- path('documents/', include(wagtaildocs_urls)),
|
|
|
- ]
|
|
|
-
|
|
|
- # Translatable URLs
|
|
|
- # These will be available under a language code prefix. For example /en/search/
|
|
|
- urlpatterns += i18n_patterns(
|
|
|
- path('search/', search_views.search, name='search'),
|
|
|
- path("", include(wagtail_urls)),
|
|
|
- )
|
|
|
-
|
|
|
-User language auto-detection
|
|
|
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-After wrapping your URL patterns with ``i18n_patterns``, your site will now
|
|
|
-respond on URL prefixes. But now it won't respond on the root path.
|
|
|
-
|
|
|
-To fix this, we need to detect the user's browser language and redirect them
|
|
|
-to the best language prefix. The recommended approach to do this is with
|
|
|
-Django's ``LocaleMiddleware``:
|
|
|
-
|
|
|
-.. code-block:: python
|
|
|
-
|
|
|
- # my_project/settings.py
|
|
|
-
|
|
|
- MIDDLEWARE = [
|
|
|
- # ...
|
|
|
- 'django.middleware.locale.LocaleMiddleware',
|
|
|
- # ...
|
|
|
- ]
|
|
|
-
|
|
|
-Custom routing/language detection
|
|
|
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-You don't strictly have to use ``i18n_patterns`` or ``LocaleMiddleware`` for
|
|
|
-this and you can write your own logic if you need to.
|
|
|
-
|
|
|
-All Wagtail needs is the language to be activated (using Django's
|
|
|
-``django.utils.translation.activate`` function) before the
|
|
|
-``wagtail.views.serve`` view is called.
|
|
|
-
|
|
|
-Recipes for internationalised sites
|
|
|
------------------------------------
|
|
|
-
|
|
|
-Language/region selector
|
|
|
-^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-Perhaps the most important bit of internationalisation-related UI you can add
|
|
|
-to your site is a selector to allow users to switch between different
|
|
|
-languages.
|
|
|
-
|
|
|
-If you're not convinced that you need this, have a look at https://www.w3.org/International/questions/qa-site-conneg#yyyshortcomings for some rationale.
|
|
|
-
|
|
|
-Basic example
|
|
|
-~~~~~~~~~~~~~
|
|
|
-
|
|
|
-Here is a basic example of how to add links between translations of a page.
|
|
|
-
|
|
|
-This example, however, will only include languages defined in
|
|
|
-``WAGTAIL_CONTENT_LANGUAGES`` and not any extra languages that might be defined
|
|
|
-in ``LANGUAGES``. For more information on what both of these settings mean, see
|
|
|
-`Configuring available languages`_.
|
|
|
-
|
|
|
-If both settings are set to the same value, this example should work well for you,
|
|
|
-otherwise skip to the next section that has a more complicated example which takes
|
|
|
-this into account.
|
|
|
-
|
|
|
-.. code-block:: html+Django
|
|
|
-
|
|
|
- {# make sure these are at the top of the file #}
|
|
|
- {% load i18n wagtailcore_tags %}
|
|
|
-
|
|
|
- {% if page %}
|
|
|
- {% for translation in page.get_translations.live %}
|
|
|
- {% get_language_info for translation.locale.language_code as lang %}
|
|
|
- <a href="{% pageurl translation %}" rel="alternate" hreflang="{{ language_code }}">
|
|
|
- {{ lang.name_local }}
|
|
|
- </a>
|
|
|
- {% endfor %}
|
|
|
- {% endif %}
|
|
|
-
|
|
|
-Let's break this down:
|
|
|
-
|
|
|
-.. code-block:: html+Django
|
|
|
-
|
|
|
- {% if page %}
|
|
|
- ...
|
|
|
- {% endif %}
|
|
|
-
|
|
|
-If this is part of a shared base template it may be used in situations where no page object is available, such as 404 error responses, so check that we have a page before proceeding.
|
|
|
-
|
|
|
-.. code-block:: html+Django
|
|
|
-
|
|
|
- {% for translation in page.get_translations.live %}
|
|
|
- ...
|
|
|
- {% endfor %}
|
|
|
-
|
|
|
-This ``for`` block iterates through all published translations of the current page.
|
|
|
-
|
|
|
-.. code-block:: html+Django
|
|
|
-
|
|
|
- {% get_language_info for translation.locale.language_code as lang %}
|
|
|
-
|
|
|
-This is a Django built-in tag that gets info about the language of the translation.
|
|
|
-For more information, see `get_language_info() in the Django docs <https://docs.djangoproject.com/en/3.1/topics/i18n/translation/#django.utils.translation.get_language_info>`_.
|
|
|
-
|
|
|
-.. code-block:: html+Django
|
|
|
-
|
|
|
- <a href="{% pageurl translation %}" rel="alternate" hreflang="{{ language_code }}">
|
|
|
- {{ lang.name_local }}
|
|
|
- </a>
|
|
|
-
|
|
|
-This adds a link to the translation. We use ``{{ lang.name_local }}`` to display
|
|
|
-the name of the locale in its own language. We also add ``rel`` and ``hreflang``
|
|
|
-attributes to the ``<a>`` tag for SEO.
|
|
|
-
|
|
|
-Handling locales that share content
|
|
|
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
-
|
|
|
-Rather than iterating over pages, this example iterates over all of the configured
|
|
|
-languages and finds the page for each one. This works better than the `Basic example`_
|
|
|
-above on sites that have extra Django ``LANGUAGES`` that share the same Wagtail content.
|
|
|
-
|
|
|
-For this example to work, you firstly need to add Django's
|
|
|
-`django.template.context_processors.i18n <https://docs.djangoproject.com/en/3.1/ref/templates/api/#django-template-context-processors-i18n>`_
|
|
|
-context processor to your ``TEMPLATES`` setting:
|
|
|
-
|
|
|
-.. code-block:: python
|
|
|
-
|
|
|
- # myproject/settings.py
|
|
|
-
|
|
|
- TEMPLATES = [
|
|
|
- {
|
|
|
- # ...
|
|
|
- 'OPTIONS': {
|
|
|
- 'context_processors': [
|
|
|
- # ...
|
|
|
- 'django.template.context_processors.i18n',
|
|
|
- ],
|
|
|
- },
|
|
|
- },
|
|
|
- ]
|
|
|
-
|
|
|
-Now for the example itself:
|
|
|
-
|
|
|
-.. code-block:: html+Django
|
|
|
-
|
|
|
- {% for language_code, language_name in LANGUAGES %}
|
|
|
- {% get_language_info for language_code as lang %}
|
|
|
-
|
|
|
- {% language language_code %}
|
|
|
- <a href="{% pageurl page.localized %}" rel="alternate" hreflang="{{ language_code }}">
|
|
|
- {{ lang.name_local }}
|
|
|
- </a>
|
|
|
- {% endlanguage %}
|
|
|
- {% endfor %}
|
|
|
-
|
|
|
-Let's break this down too:
|
|
|
-
|
|
|
-.. code-block:: html+Django
|
|
|
-
|
|
|
- {% for language_code, language_name in LANGUAGES %}
|
|
|
- ...
|
|
|
- {% endfor %}
|
|
|
-
|
|
|
-This ``for`` block iterates through all of the configured languages on the site.
|
|
|
-The ``LANGUAGES`` variable comes from the ``django.template.context_processors.i18n``
|
|
|
-context processor.
|
|
|
-
|
|
|
-.. code-block:: html+Django
|
|
|
-
|
|
|
- {% get_language_info for language_code as lang %}
|
|
|
-
|
|
|
-Does exactly the same as the previous example.
|
|
|
-
|
|
|
-.. code-block:: html+Django
|
|
|
-
|
|
|
- {% language language_code %}
|
|
|
- ...
|
|
|
- {% endlanguage %}
|
|
|
-
|
|
|
-This ``language`` tag comes from Django's ``i18n`` tag library. It changes the
|
|
|
-active language for just the code contained within it.
|
|
|
-
|
|
|
-.. code-block:: html+Django
|
|
|
-
|
|
|
- <a href="{% pageurl page.localized %}" rel="alternate" hreflang="{{ language_code }}">
|
|
|
- {{ lang.name_local }}
|
|
|
- </a>
|
|
|
-
|
|
|
-The only difference with the ``<a>`` tag here from the ``<a>`` tag in the previous example
|
|
|
-is how we're getting the page's URL: ``{% pageurl page.localized %}``.
|
|
|
-
|
|
|
-All page instances in Wagtail have a ``.localized`` attribute which fetches the translation
|
|
|
-of the page in the current active language. This is why we activated the language previously.
|
|
|
-
|
|
|
-Another difference here is that if the same translated page is shared in two locales, Wagtail
|
|
|
-will generate the correct URL for the page based on the current active locale. This is the
|
|
|
-key difference between this example and the previous one as the previous one can only get the
|
|
|
-URL of the page in its default locale.
|
|
|
-
|
|
|
-API filters for headless sites
|
|
|
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-For headless sites, the Wagtail API supports two extra filters for internationalised sites:
|
|
|
-
|
|
|
- - ``?locale=`` Filters pages by the given locale
|
|
|
- - ``?translation_of=`` Filters pages to only include translations of the given page ID
|
|
|
-
|
|
|
-For more information, see :ref:`apiv2_i18n_filters`.
|
|
|
-
|
|
|
-Translatable snippets
|
|
|
-^^^^^^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-You can make a snippet translatable by making it inherit from ``wagtail.models.TranslatableMixin``.
|
|
|
-For example:
|
|
|
-
|
|
|
-.. code-block:: python
|
|
|
-
|
|
|
- # myapp/models.py
|
|
|
-
|
|
|
- from django.db import models
|
|
|
-
|
|
|
- from wagtail.models import TranslatableMixin
|
|
|
- from wagtail.snippets.models import register_snippet
|
|
|
-
|
|
|
-
|
|
|
- @register_snippet
|
|
|
- class Advert(TranslatableMixin, models.Model):
|
|
|
- name = models.CharField(max_length=255)
|
|
|
-
|
|
|
-The ``TranslatableMixin`` model adds the ``locale`` and ``translation_key`` fields to the model.
|
|
|
-
|
|
|
-Making snippets with existing data translatable
|
|
|
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
-
|
|
|
-For snippets with existing data, it's not possible to just add ``TranslatableMixin``,
|
|
|
-make a migration, and run it. This is because the ``locale`` and ``translation_key``
|
|
|
-fields are both required and ``translation_key`` needs a unique value for each
|
|
|
-instance.
|
|
|
-
|
|
|
-To migrate the existing data properly, we firstly need to use ``BootstrapTranslatableMixin``,
|
|
|
-which excludes these constraints, then add a data migration to set the two fields, then
|
|
|
-switch to ``TranslatableMixin``.
|
|
|
-
|
|
|
-This is only needed if there are records in the database. So if the model is empty, you can
|
|
|
-go straight to adding ``TranslatableMixin`` and skip this.
|
|
|
-
|
|
|
-Step 1: Add ``BootstrapTranslatableMixin`` to the model
|
|
|
-*******************************************************
|
|
|
-
|
|
|
-This will add the two fields without any constraints:
|
|
|
-
|
|
|
-.. code-block:: python
|
|
|
-
|
|
|
- # myapp/models.py
|
|
|
-
|
|
|
- from django.db import models
|
|
|
-
|
|
|
- from wagtail.models import BootstrapTranslatableMixin
|
|
|
- from wagtail.snippets.models import register_snippet
|
|
|
-
|
|
|
-
|
|
|
- @register_snippet
|
|
|
- class Advert(BootstrapTranslatableMixin, models.Model):
|
|
|
- name = models.CharField(max_length=255)
|
|
|
-
|
|
|
- # if the model has a Meta class, ensure it inherits from
|
|
|
- # BootstrapTranslatableMixin.Meta too
|
|
|
- class Meta(BootstrapTranslatableMixin.Meta):
|
|
|
- verbose_name = 'adverts'
|
|
|
-
|
|
|
-Run ``python manage.py makemigrations myapp`` to generate the schema migration.
|
|
|
-
|
|
|
-Step 2: Create a data migration
|
|
|
-*******************************
|
|
|
-
|
|
|
-Create a data migration with the following command:
|
|
|
-
|
|
|
-.. code-block:: bash
|
|
|
-
|
|
|
- python manage.py makemigrations myapp --empty
|
|
|
-
|
|
|
-This will generate a new empty migration in the app's ``migrations`` folder. Edit
|
|
|
-that migration and add a ``BootstrapTranslatableModel`` for each model to bootstrap
|
|
|
-in that app:
|
|
|
-
|
|
|
-.. code-block:: python
|
|
|
-
|
|
|
- from django.db import migrations
|
|
|
- from wagtail.models import BootstrapTranslatableModel
|
|
|
-
|
|
|
- class Migration(migrations.Migration):
|
|
|
- dependencies = [
|
|
|
- ('myapp', '0002_bootstraptranslations'),
|
|
|
- ]
|
|
|
-
|
|
|
- # Add one operation for each model to bootstrap here
|
|
|
- # Note: Only include models that are in the same app!
|
|
|
- operations = [
|
|
|
- BootstrapTranslatableModel('myapp.Advert'),
|
|
|
- ]
|
|
|
-
|
|
|
-Repeat this for any other apps that contain a model to be bootstrapped.
|
|
|
-
|
|
|
-Step 3: Change ``BootstrapTranslatableMixin`` to ``TranslatableMixin``
|
|
|
-**********************************************************************
|
|
|
-
|
|
|
-Now that we have a migration that fills in the required fields, we can swap out
|
|
|
-``BootstrapTranslatableMixin`` for ``TranslatableMixin`` that has all the
|
|
|
-constraints:
|
|
|
-
|
|
|
-.. code-block:: python
|
|
|
-
|
|
|
- # myapp/models.py
|
|
|
-
|
|
|
- from wagtail.models import TranslatableMixin # Change this line
|
|
|
-
|
|
|
- @register_snippet
|
|
|
- class Advert(TranslatableMixin, models.Model): # Change this line
|
|
|
- name = models.CharField(max_length=255)
|
|
|
-
|
|
|
- class Meta(TranslatableMixin.Meta): # Change this line, if present
|
|
|
- verbose_name = 'adverts'
|
|
|
-
|
|
|
-Step 4: Run ``makemigrations`` to generate schema migrations, then migrate!
|
|
|
-***************************************************************************
|
|
|
-
|
|
|
-Run ``makemigrations`` to generate the schema migration that adds the
|
|
|
-constraints into the database, then run ``migrate`` to run all of the
|
|
|
-migrations:
|
|
|
-
|
|
|
-.. code-block:: bash
|
|
|
-
|
|
|
- python manage.py makemigrations myapp
|
|
|
- python manage.py migrate
|
|
|
-
|
|
|
-When prompted to select a fix for the nullable field 'locale' being changed to
|
|
|
-non-nullable, select the option "Ignore for now" (as this has been handled by the
|
|
|
-data migration).
|
|
|
-
|
|
|
-
|
|
|
-Translation workflow
|
|
|
---------------------
|
|
|
-
|
|
|
-As mentioned at the beginning, Wagtail does supply ``wagtail.contrib.simple_translation``.
|
|
|
-
|
|
|
-The simple_translation module provides a user interface that allows users to copy pages and translatable snippets into another language.
|
|
|
-
|
|
|
-- Copies are created in the source language (not translated)
|
|
|
-- Copies of pages are in draft status
|
|
|
-
|
|
|
-Content editors need to translate the content and publish the pages.
|
|
|
-
|
|
|
-To enable add ``"wagtail.contrib.simple_translation"`` to ``INSTALLED_APPS``
|
|
|
-and run ``python manage.py migrate`` to create the ``submit_translation`` permissions.
|
|
|
-In the Wagtail admin, go to settings and give some users or groups the "Can submit translations" permission.
|
|
|
-
|
|
|
-.. note::
|
|
|
- Simple Translation is optional. It can be switched out by third-party packages. Like the more advanced `wagtail-localize <https://github.com/wagtail/wagtail-localize>`_.
|
|
|
-
|
|
|
-
|
|
|
-Wagtail Localize
|
|
|
-^^^^^^^^^^^^^^^^
|
|
|
-
|
|
|
-As part of the initial work on implementing internationalisation for Wagtail core,
|
|
|
-we also created a translation package called ``wagtail-localize``. This supports
|
|
|
-translating pages within Wagtail, using PO files, machine translation, and external
|
|
|
-integration with translation services.
|
|
|
-
|
|
|
-Github: https://github.com/wagtail/wagtail-localize
|
|
|
-
|
|
|
-Alternative internationalisation plugins
|
|
|
-========================================
|
|
|
-
|
|
|
-Before official multi-language support was added into Wagtail, site implementors
|
|
|
-had to use external plugins. These have not been replaced by Wagtail's own
|
|
|
-implementation as they use slightly different approaches, one of them might
|
|
|
-fit your use case better:
|
|
|
-
|
|
|
-- `Wagtailtrans <https://github.com/wagtail/wagtailtrans>`_
|
|
|
-- `wagtail-modeltranslation <https://github.com/infoportugal/wagtail-modeltranslation>`_
|
|
|
-
|
|
|
-For a comparison of these options, see AccordBox's blog post
|
|
|
-`How to support multi-language in Wagtail CMS <https://www.accordbox.com/blog/how-support-multi-language-wagtail-cms/>`_.
|
|
|
-
|
|
|
-Wagtail admin translations
|
|
|
-==========================
|
|
|
-
|
|
|
-The Wagtail admin backend has been translated into many different languages. You can find a list of currently available translations on Wagtail's `Transifex page <https://www.transifex.com/torchbox/wagtail/>`_. (Note: if you're using an old version of Wagtail, this page may not accurately reflect what languages you have available).
|
|
|
-
|
|
|
-If your language isn't listed on that page, you can easily contribute new languages or correct mistakes. Sign up and submit changes to `Transifex <https://www.transifex.com/torchbox/wagtail/>`_. Translation updates are typically merged into an official release within one month of being submitted.
|
|
|
-
|
|
|
-Change Wagtail admin language on a per-user basis
|
|
|
-=================================================
|
|
|
-
|
|
|
-Logged-in users can set their preferred language from ``/admin/account/``.
|
|
|
-By default, Wagtail provides a list of languages that have a >= 90% translation coverage.
|
|
|
-It is possible to override this list via the :ref:`WAGTAILADMIN_PERMITTED_LANGUAGES <WAGTAILADMIN_PERMITTED_LANGUAGES>` setting.
|
|
|
-
|
|
|
-In case there is zero or one language permitted, the form will be hidden.
|
|
|
-
|
|
|
-If there is no language selected by the user, the ``LANGUAGE_CODE`` will be used.
|
|
|
-
|
|
|
-
|
|
|
-Changing the primary language of your Wagtail installation
|
|
|
-==========================================================
|
|
|
-
|
|
|
-The default language of Wagtail is ``en-us`` (American English). You can change this by tweaking a couple of Django settings:
|
|
|
-
|
|
|
-- Make sure `USE_I18N <https://docs.djangoproject.com/en/stable/ref/settings/#use-i18n>`_ is set to ``True``
|
|
|
-- Set `LANGUAGE_CODE <https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-LANGUAGE_CODE>`_ to your websites' primary language
|
|
|
-
|
|
|
-If there is a translation available for your language, the Wagtail admin backend should now be in the language you've chosen.
|