[RFC 54] Internationalisation reference docs (#6377)

* Reference docs for internationalisation

* Update docs/reference/pages/model_reference.rst

Co-authored-by: Dan Braghis <dan@zerolab.org>

* Update docs/reference/pages/model_reference.rst

Co-authored-by: Dan Braghis <dan@zerolab.org>

* Update docs/reference/pages/model_reference.rst

Co-authored-by: Dan Braghis <dan@zerolab.org>

* Apply suggestions from code review

Co-authored-by: Dan Braghis <dan@zerolab.org>

* Add missing comma

* Apply suggestions from code review

Co-authored-by: Matt Westcott <matthew@torchbox.com>

Co-authored-by: Dan Braghis <dan@zerolab.org>
Co-authored-by: Matt Westcott <matthew@torchbox.com>
pull/6471/head
Karl Hobley 2020-10-19 18:40:58 +01:00 zatwierdzone przez GitHub
rodzic 9fab50e87a
commit 0efe4a75a5
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
3 zmienionych plików z 267 dodań i 9 usunięć

Wyświetl plik

@ -129,6 +129,22 @@ Database fields
If set, this page is an alias of the page referenced in this field.
.. attribute:: locale
(foreign key to Locale)
This foreign key links to the ``Locale`` object that represents the page language.
.. attribute:: translation_key
(uuid)
A UUID that is shared between translations of a page. These are randomly generated
when a new page is created and copied when a translation of a page is made.
A translation_key value can only be used on one page in each locale.
Methods and properties
~~~~~~~~~~~~~~~~~~~~~~
@ -184,6 +200,20 @@ In addition to the model fields provided, ``Page`` has many properties and metho
.. automethod:: get_siblings
.. automethod:: get_translations
.. automethod:: get_translation
.. automethod:: get_translation_or_none
.. automethod:: has_translation
.. automethod:: copy_for_translation
.. autoattribute:: localized
.. autoattribute:: localized_draft
.. attribute:: search_fields
A list of fields to be indexed by the search engine. See Search docs :ref:`wagtailsearch_indexing_fields`
@ -356,6 +386,87 @@ Methods and properties
.. automethod:: get_site_root_paths
Locale
======
The ``Locale`` model defines the set of languages and/or locales that can be used on a site.
Each ``Locale`` record corresponds to a "language code" defined in the :ref:`wagtail_content_languages_setting` setting.
Wagtail will initially set up one ``Locale`` to act as the default language for all existing content.
This first locale will automatically pick the value from ``WAGTAIL_CONTENT_LANGUAGES`` that most closely matches the site primary language code defined in ``LANGUAGE_CODE``.
If the primary language code is changed later, Wagtail will **not** automatically create a new ``Locale`` record or update an existing one.
Before internationalisation is enabled, all pages use this primary ``Locale`` record.
This is to satisfy the database constraints, and makes it easier to switch internationalisation on at a later date.
Changing ``WAGTAIL_CONTENT_LANGUAGES``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Languages can be added or removed from ``WAGTAIL_CONTENT_LANGUAGES`` over time.
Before removing an option from ``WAGTAIL_CONTENT_LANGUAGES``, it's important that the ``Locale``
record is updated to a use a different content language or is deleted.
Any ``Locale`` instances that have invalid content languages are automatically filtered out from all
database queries making them unable to be edited or viewed.
Methods and properties
~~~~~~~~~~~~~~~~~~~~~~
.. class:: Locale
:noindex:
.. autoattribute:: language_code
.. automethod:: get_default
.. automethod:: get_active
.. automethod:: get_display_name
Translatable Mixin
==================
``TranslatableMixin`` is an abstract model that can be added to any non-page Django model to make it translatable.
Pages already include this mixin, so there is no need to add it.
Methods and properties
~~~~~~~~~~~~~~~~~~~~~~
The ``locale`` and ``translation_key`` fields have a unique key constraint to prevent the object being translated into a language more than once.
.. class:: TranslatableMixin
:noindex:
.. attribute:: locale
(Foreign Key to :class:`~wagtail.core.models.Locale`)
For pages, this defaults to the locale of the parent page.
.. attribute:: translation_key
(uuid)
A UUID that is randomly generated whenever a new model instance is created.
This is shared with all translations of that instance so can be used for querying translations.
.. automethod:: get_translations
.. automethod:: get_translation
.. automethod:: get_translation_or_none
.. automethod:: has_translation
.. automethod:: copy_for_translation
.. automethod:: get_translation_model
.. autoattribute:: localized
.. _page-revision-model-ref:
``PageRevision``

Wyświetl plik

@ -64,6 +64,91 @@ Override the templates used by the search front-end views.
Set the number of days (default 7) that search query logs are kept for; these are used to identify popular search terms for :ref:`promoted search results <editors-picks>`. Queries older than this will be removed by the :ref:`search_garbage_collect` command.
Internationalisation
====================
.. versionadded:: 2.11
Wagtail supports internationalisation of content by maintaining separate trees
of pages for each language.
For a guide on how to enable internationalisation on your site, see the :ref:`configuration guide <enabling_internationalisation>`.
``WAGTAIL_I18N_ENABLED``
------------------------
(boolean, default ``False``)
When set to ``True``, Wagtail's internationalisation features will be enabled:
.. code-block:: python
WAGTAIL_I18N_ENABLED = True
.. _wagtail_content_languages_setting:
``WAGTAIL_CONTENT_LANGUAGES``
-----------------------------
(list, default ``[]``)
A list of languages and/or locales that Wagtail content can be authored in.
For example:
.. code-block:: python
WAGTAIL_CONTENT_LANGUAGES = [
('en', _("English")),
('fr', _("French")),
]
Each item in the list is a 2-tuple containing a language code and a display name.
The language code can either be a language code on its own (such as ``en``, ``fr``),
or it can include a region code (such as ``en-gb``, ``fr-fr``).
You can mix the two formats if you only need to localize in some regions but not others.
This setting follows the same structure of Django's ``LANGUAGES`` setting,
so they can both be set to the same value:
.. code-block:: python
LANGUAGES = WAGTAIL_CONTENT_LANGUAGES = [
('en-gb', _("English (United Kingdom)")),
('en-us', _("English (United States)")),
('es-es', _("Spanish (Spain)")),
('es-mx', _("Spanish (Mexico)")),
]
However having them separate allows you to configure many different regions on your site
yet have them share Wagtail content (but defer on things like date formatting, currency, etc):
.. code-block:: python
LANGUAGES = [
('en', _("English (United Kingdom)")),
('en-us', _("English (United States)")),
('es', _("Spanish (Spain)")),
('es-mx', _("Spanish (Mexico)")),
]
WAGTAIL_CONTENT_LANGUAGES = [
('en', _("English")),
('es', _("Spanish")),
]
This would mean that your site will respond on the
``https://www.mysite.com/es/`` and ``https://www.mysite.com/es-MX/`` URLs, but both
of them will serve content from the same "Spanish" tree in Wagtail.
.. note:: ``WAGTAIL_CONTENT_LANGUAGES`` must be a subset of ``LANGUAGES``
Note that all languages that exist in ``WAGTAIL_CONTENT_LANGUAGES``
must also exist in your ``LANGUAGES`` setting. This is so that Wagtail can
generate a live URL to these pages from an untranslated context (e.g. the admin
interface).
Embeds
======

Wyświetl plik

@ -336,6 +336,10 @@ class LocaleManager(models.Manager):
class Locale(models.Model):
#: The language code that represents this locale
#:
#: The language code can either be a language code on its own (such as ``en``, ``fr``),
#: or it can include a region code (such as ``en-gb``, ``fr-fr``).
language_code = models.CharField(max_length=100, unique=True)
# Objects excludes any Locales that have been removed from LANGUAGES, This effectively disables them
@ -406,6 +410,11 @@ class TranslatableMixin(models.Model):
@property
def localized(self):
"""
Finds the translation in the current active language.
If there is no translation in the active language, self is returned.
"""
locale = Locale.get_active()
if locale.id == self.locale_id:
@ -414,6 +423,9 @@ class TranslatableMixin(models.Model):
return self.get_translation_or_none(locale) or self
def get_translations(self, inclusive=False):
"""
Returns a queryset containing the translations of this instance.
"""
translations = self.__class__.objects.filter(
translation_key=self.translation_key
)
@ -424,20 +436,35 @@ class TranslatableMixin(models.Model):
return translations
def get_translation(self, locale):
"""
Finds the translation in the specified locale.
If there is no translation in that locale, this raises a ``model.DoesNotExist`` exception.
"""
return self.get_translations(inclusive=True).get(locale_id=pk(locale))
def get_translation_or_none(self, locale):
"""
Finds the translation in the specified locale.
If there is no translation in that locale, this returns None.
"""
try:
return self.get_translation(locale)
except self.__class__.DoesNotExist:
return None
def has_translation(self, locale):
"""
Returns True if a translation exists in the specified locale.
"""
return self.get_translations(inclusive=True).filter(locale_id=pk(locale)).exists()
def copy_for_translation(self, locale):
"""
Copies this instance for the specified locale.
Creates a copy of this instance with the specified locale.
Note that the copy is initially unsaved.
"""
translated = self.__class__.objects.get(id=self.id)
translated.id = None
@ -472,15 +499,17 @@ class TranslatableMixin(models.Model):
return Locale.get_default()
@classmethod
def get_translation_model(self):
def get_translation_model(cls):
"""
Gets the model which manages the translations for this model.
(The model that has the "translation_key" and "locale" fields)
Most of the time this would be the current model, but some sites
may have intermediate concrete models between wagtailcore.Page and
the specfic page model.
Returns this model's "Translation model".
The "Translation model" is the model that has the ``locale`` and
``translation_key`` fields.
Typically this would be the current model, but it may be a
super-class if multi-table inheritance is in use (as is the case
for ``wagtailcore.Page``).
"""
return self._meta.get_field("locale").model
return cls._meta.get_field("locale").model
def bootstrap_translatable_model(model, locale):
@ -1161,6 +1190,14 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
@property
def localized_draft(self):
"""
Finds the translation in the current active language.
If there is no translation in the active language, self is returned.
Note: This will return translations that are in draft. If you want to exclude
these, use the ``.localized`` attribute.
"""
locale = Locale.get_active()
if locale.id == self.locale_id:
@ -1170,6 +1207,14 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
@property
def localized(self):
"""
Finds the translation in the current active language.
If there is no translation in the active language, self is returned.
Note: This will not return the translation if it is in draft.
If you want to include drafts, use the ``.localized_draft`` attribute instead.
"""
localized = self.localized_draft
if not localized.live:
return self
@ -2205,7 +2250,24 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
@transaction.atomic
def copy_for_translation(self, locale, copy_parents=False, alias=False, exclude_fields=None):
"""
Copies this page for the specified locale.
Creates a copy of this page in the specified locale.
The new page will be created in draft as a child of this page's translated
parent.
For example, if you are translating a blog post from English into French,
this method will look for the French version of the blog index and create
the French translation of the blog post under that.
If this page's parent is not translated into the locale, then a ``ParentNotTranslatedError``
is raised. You can circumvent this error by passing ``copy_parents=True`` which
copies any parents that are not translated yet.
The ``exclude_fields`` parameter can be used to set any fields to a blank value
in the copy.
Note that this method calls the ``.copy()`` method internally so any fields that
are excluded in ``.exclude_fields_in_copy`` will be excluded from the translation.
"""
# Find the translated version of the parent page to create the new page under
parent = self.get_parent().specific