Add wagtail-localize-smartling to the project, for Smartling L10N support (#14794)

* Add wagtail-localize-smartling to the project, for Smartling L10N support

* Add docs for wagtail-localize-smartling

* Minor reformatting

* Fix duplicated env var reference 🤦

* Add a management command that wraps the sync_smartling command so we can monitor it with a DMS
This commit is contained in:
Steve Jalim 2024-07-22 23:09:49 +01:00 коммит произвёл GitHub
Родитель 5fd5d4f524
Коммит 1829904358
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
6 изменённых файлов: 148 добавлений и 1 удалений

Просмотреть файл

@ -0,0 +1,34 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
import sys
from django.core.management import call_command
from django.core.management.base import BaseCommand
import requests
from bedrock.base.config_manager import config
class Command(BaseCommand):
help = """Wraps the sync_smartling management command from
wagtail-localize-smartling so that we can monitor its
operation via a Dead Man's Snitch"""
def handle(self, *args, **kwargs):
SMARTLING_SYNC_SNITCH_URL = config("SMARTLING_SYNC_SNITCH_URL", default="")
try:
call_command("sync_smartling")
sys.stdout.write(
"\nsync_smartling executed successfully\n",
)
if SMARTLING_SYNC_SNITCH_URL:
requests.get(SMARTLING_SYNC_SNITCH_URL)
sys.stdout.write("Snitch pinged\n")
except Exception as ex:
sys.stderr.write(f"\nsync_smartling did not execute successfully: {ex}\n")

Просмотреть файл

@ -749,6 +749,7 @@ INSTALLED_APPS = [
"wagtail.users",
"wagtail.snippets",
"wagtail.images",
"wagtail_localize_smartling", # Has to come before wagtail_localize
"wagtail_localize",
"wagtail_localize.locales", # This replaces "wagtail.locales"
"wagtail.search",
@ -2122,6 +2123,29 @@ else:
# Wagtailed, but we need something valid so Pocket mode will boot up
WAGTAIL_CONTENT_LANGUAGES = [("en", "English")]
# Settings for https://github.com/mozilla/wagtail-localize-smartling
WAGTAIL_LOCALIZE_SMARTLING = {
# Required settings (get these from "Account settings" > "API" in the Smartling dashboard)
"PROJECT_ID": config("WAGTAIL_LOCALIZE_SMARTLING_PROJECT_ID", default="setme"),
"USER_IDENTIFIER": config("WAGTAIL_LOCALIZE_SMARTLING_USER_IDENTIFIER", default="setme"),
"USER_SECRET": config("WAGTAIL_LOCALIZE_SMARTLING_USER_SECRET", default="setme"),
# Optional settings and their default values
"REQUIRED": config(
"WAGTAIL_LOCALIZE_SMARTLING_ALWAYS_SEND",
default="False",
parser=bool,
), # Set this to True to always send translations to Smartling
"ENVIRONMENT": config(
"WAGTAIL_LOCALIZE_SMARTLING_ENVIRONMENT",
default="production",
), # Set this to "staging" to use Smartling's staging API
"API_TIMEOUT_SECONDS": config(
"WAGTAIL_LOCALIZE_SMARTLING_API_TIMEOUT_SECONDS",
default="5",
parser=float,
), # Timeout in seconds for requests to the Smartling API
}
# Custom settings, not a core Wagtail ones, to scope out RichText options
WAGTAIL_RICHEXT_FEATURES_FULL = [
# https://docs.wagtail.org/en/stable/advanced_topics/customisation/page_editing_interface.html#limiting-features-in-a-rich-text-field

Просмотреть файл

@ -415,6 +415,68 @@ This approach will not be a problem if we stick to image filter-specs from the
'approved' list. Note that extending the list of filter-specs is possible, if
we need to.
L10N and Translation Management
-------------------------------
.. important::
Localization via Wagtail is something we are ramping up on, so please
do not assume the following notes are final, or that the workflows are
currently all rock-solid. We're learning as we go.
Page-tree concept
=================
Our Wagtail setup uses the official `wagtail-localize`_ package to manage
localization of pages.
This package supports page-level localization rather than field-level localization, which means that each locale has its own distinct tree of pages, rather than each page having a stack of duplicate fields, one per destination language.
These language-specific trees can be "synchronised" with the default ``en-US`` page tree, so would have the same page structure, field by field) — or they can not be synchronised, so can have their own extra pages, or some specific pages in the tree can be made not "synchronised", while others are.
Basically, there is plenty of flexibility. The flipside of that flexibility is we may also create an edge-case situation that ``wagtail-localize`` won't work with, but we'll have to see and deal with it.
.. note::
It's worth investing 15 mins in watching the `Wagtail Localize original demo`_ to get a good feel of how it can work.
Localization process
====================
Manual updates
~~~~~~~~~~~~~~
At its most basic, there's nothing stopping us using copy-and-paste to enter translations into lang-specific pages, which might work well if we have a page in just one non-en-US lang and an in-house colleague doing the translation.
Automated via Smartling
~~~~~~~~~~~~~~~~~~~~~~~
However, we also have automation available to send source strings to translation vendor Smartling. This uses the ``wagtail-localize-smartling`` package.
Here's the workflow:
1. CMS page "MyPage" is created in the default lang (``en-US``)
2. The "Translate this page" option is triggered for MyPage, and relevant langs are selected from the configured langs that Smartling supports. (We don't have to translate into all of them)
3. A translation Job is created in Smartling, awaiting authorization by our L10N team
4. A L10N team colleague authorizes the Job and selects the relevant translation workflow(s) for the relevant lang(s)
5. Once the jobs are completed, the localised strings flow back to Wagtail and populate a draft version of each language-specific page
6. A human reviews these draft pages and publishes them
**Notes:**
* Smartling/``wagtail-localize-smartling`` will only translate pages from the base lang (``en-US``) to another lang - it won't treat, say, a Page in ``fr`` as a source-language document.
* If a string is received from Smartling into the CMS and then manually edited on the CMS side, the change will `not` be overwritten by subsequent Smartling syncs and the manual edit needs to be added on the Smartling side for consistency and stability.
* If a page is translated from ``en-US`` once, then has new ``en-US`` content added that is sent for translation, that will trigger a new Smartling Job. When that job is complete, it `will` overwrite any manual edits made to a translation within the CMS. This is why it's important to make sure Smartling contains any manual tweaks done to translations in the CMS.
Automated via Pontoon
~~~~~~~~~~~~~~~~~~~~~
It should also be possible to use `Pontoon`_ with `wagtail-localize`. (There are notes on the `Pontoon integration`_ here, but we have not yet tried to enable this alongside `wagtail-localize-smartling`).
Additionally using Pontoon would let us benefit from community translations across a broad range of languages. However, we have yet to try to set this up and would need to agree which parts of the site do and do not use Pontoon.
Infrastructure notes
====================
@ -451,3 +513,8 @@ admin user in your local build.
.. _Custom Block types: https://docs.wagtail.org/en/stable/advanced_topics/customisation/streamfield_blocks.html#custom-streamfield-blocks
.. _Django migrations docs: https://docs.djangoproject.com/en/4.2/topics/migrations/
.. _Squashing migrations: https://docs.djangoproject.com/en/4.2/topics/migrations/
.. _wagtail-localize: https://wagtail-localize.org/
.. _wagtail-localize-smartling: https://github.com/mozilla/wagtail-localize-smartling
.. _Pontoon: https://pontoon.mozilla.org/
.. _Pontoon integration: https://wagtail-localize.org/stable/how-to/integrations/pontoon/
.. _Wagtail Localize original demo: https://www.youtube.com/watch?v=mEzQcOMUzoc

Просмотреть файл

@ -478,6 +478,7 @@ django==4.2.14 \
# mozilla-django-oidc
# wagtail
# wagtail-localize
# wagtail-localize-smartling
django-allow-cidr==0.7.1 \
--hash=sha256:11126c5bb9df3a61ff9d97304856ba7e5b26d46c6d456709a6d9e28483bff47f \
--hash=sha256:382c5d7a9807279e3e96e4f4892b59163a2b30128c596902bf5f80e133e1ccbb
@ -567,6 +568,7 @@ djangorestframework==3.15.2 \
# via
# -r requirements/prod.txt
# wagtail
# wagtail-localize-smartling
docutils==0.21.2 \
--hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \
--hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2
@ -1885,6 +1887,7 @@ requests==2.32.3 \
# pytest-selenium
# responses
# wagtail
# wagtail-localize-smartling
responses==0.25.0 \
--hash=sha256:01ae6a02b4f34e39bffceb0fc6786b67a25eae919c6368d05eabc8d9576c2a66 \
--hash=sha256:2f0b9c2b6437db4b528619a77e5d565e4ec2a9532162ac1a131a83529db7be1a
@ -2209,6 +2212,7 @@ wagtail==6.1.3 \
# -r requirements/prod.txt
# wagtail-factories
# wagtail-localize
# wagtail-localize-smartling
wagtail-factories==4.2.1 \
--hash=sha256:7a180fc1b074af7a78648c634740ee89d4dbb45899917744b66431d38155b6ae \
--hash=sha256:bfe158092982a2b30a3e603c482242905df0b163fc69573fa6f159df482175c5
@ -2216,6 +2220,12 @@ wagtail-factories==4.2.1 \
wagtail-localize==1.9 \
--hash=sha256:a680fc33c17145e6726f03a57b2ec465405847ae7cb77943ecc0e56463ad68c7 \
--hash=sha256:f4fa9c36d8dbab5c27d1b675ed6fd7b9e8f012cf4bb308464168de7ebbad8324
# via
# -r requirements/prod.txt
# wagtail-localize-smartling
wagtail-localize-smartling==0.2.3 \
--hash=sha256:0701444976c6b5392616d5dcdbf202fdce730b591e9d6794efee99c613107dc5 \
--hash=sha256:6bef31958c24229a663b81b889879c845bed021dde0eba44a9527eb45e6cf3ed
# via -r requirements/prod.txt
wcwidth==0.2.13 \
--hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 \

Просмотреть файл

@ -57,3 +57,4 @@ timeago==1.0.16
whitenoise==6.7.0
Wagtail==6.1.3
wagtail-localize==1.9
wagtail-localize-smartling==0.2.3

Просмотреть файл

@ -325,6 +325,7 @@ django==4.2.14 \
# mozilla-django-oidc
# wagtail
# wagtail-localize
# wagtail-localize-smartling
django-allow-cidr==0.7.1 \
--hash=sha256:11126c5bb9df3a61ff9d97304856ba7e5b26d46c6d456709a6d9e28483bff47f \
--hash=sha256:382c5d7a9807279e3e96e4f4892b59163a2b30128c596902bf5f80e133e1ccbb
@ -401,7 +402,9 @@ django-watchman==1.3.0 \
djangorestframework==3.15.2 \
--hash=sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20 \
--hash=sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad
# via wagtail
# via
# wagtail
# wagtail-localize-smartling
docutils==0.21.2 \
--hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \
--hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2
@ -1365,6 +1368,7 @@ requests==2.32.3 \
# mozilla-django-oidc
# pygithub
# wagtail
# wagtail-localize-smartling
rich-text-renderer==0.2.8 \
--hash=sha256:74e28bde639f737e2bc50f3dfb147bdbad4b2d7ab3f8f76a9db2d444edb8d13b \
--hash=sha256:e4680109372b55611250ebe0745f59cbf3f8932afa6f5cb5d1f3cc282a4bf95c
@ -1591,9 +1595,16 @@ wagtail==6.1.3 \
# via
# -r requirements/prod.in
# wagtail-localize
# wagtail-localize-smartling
wagtail-localize==1.9 \
--hash=sha256:a680fc33c17145e6726f03a57b2ec465405847ae7cb77943ecc0e56463ad68c7 \
--hash=sha256:f4fa9c36d8dbab5c27d1b675ed6fd7b9e8f012cf4bb308464168de7ebbad8324
# via
# -r requirements/prod.in
# wagtail-localize-smartling
wagtail-localize-smartling==0.2.3 \
--hash=sha256:0701444976c6b5392616d5dcdbf202fdce730b591e9d6794efee99c613107dc5 \
--hash=sha256:6bef31958c24229a663b81b889879c845bed021dde0eba44a9527eb45e6cf3ed
# via -r requirements/prod.in
webencodings==0.5.1 \
--hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \