An extension for wagtail-localize that integrates with the Smartling translation platform
Project description
Wagtail Localize Smartling
An extension for Wagtail Localize that integrates with the Smartling translation platform.
Links
Supported versions
- Python 3.8+
- Django 4.2+
- Wagtail 6.1+
Installation
-
Install the package from PyPI:
python -m pip install wagtail-localize-smartling
-
Add
"wagtail_localize_smartling"toINSTALLED_APPSin your Django settings. Make sure it's before"wagtail_localize"and"wagtail_localize.locales":INSTALLED_APPS = [ ... "wagtail_localize_smartling", "wagtail_localize", "wagtail_localize.locales", ... ]
-
Configure the plugin in your Django settings:
WAGTAIL_LOCALIZE_SMARTLING = { # Required settings (get these from "Account settings" > "API" in the Smartling dashboard) "PROJECT_ID": "<project_id>", "USER_IDENTIFIER": "<user_identifier>", "USER_SECRET": "<user_secret>", # Optional settings and their default values "REQUIRED": False, # Set this to True to always send translations to Smartling "ENVIRONMENT": "production", # Set this to "staging" to use Smartling's staging API "API_TIMEOUT_SECONDS": 5.0, # Timeout in seconds for requests to the Smartling API }
If your project's locales do not match those in Smartling (e.g.
roin your project,ro-ROin Smartling), then you can provide a Wagtail locale ID to Smartling locale ID mapping via theLOCALE_TO_SMARTLING_LOCALEsetting:WAGTAIL_LOCALIZE_SMARTLING = { "LOCALE_TO_SMARTLING_LOCALE": { "ro": "ro-RO" } }
... or you can specify a callable or a dotted path to a callable in the
LOCALE_MAPPING_CALLBACKsetting:def map_project_locale_to_smartling(locale: str) -> str: if locale == "ro": return "ro-RO" return locale WAGTAIL_LOCALIZE_SMARTLING = { # ... "LOCALE_MAPPING_CALLBACK": "settings.map_project_locale_to_smartling" }
The callback receives a
WAGTAIL_CONTENT_LANGUAGESlocale code string and is expected to return a valid mapped locale ID (or the original locale ID).Note that by default, when syncing translations the project will attempt to reformat a mixed-case, Smartling-style language code (e.g.
zh-CN) into a Django-style all-lowercase code (e.g.zh-cn). Depending on how language codes are set up in your project, this behaviour may not be appropriate. You can disable it by settings theREFORMAT_LANGUAGE_CODESsetting toFalse(the default isTrue):WAGTAIL_LOCALIZE_SMARTLING = { # ... "REFORMAT_LANGUAGE_CODES": False }
If you need to customize the default Job description, you can specify a callable or a dotted path to a callable in the
JOB_DESCRIPTION_CALLBACKsetting:from typing import Iterable from wagtail_localize.models import Translation, TranslationSource def enhance_job_description( description: str, translation_source: TranslationSource, translations: Iterable[Translation] ) -> str: # note: to get the source instance, use translation_source.get_source_instance() return description + " my text."
The callback receives the default description string, the job
TranslationSourceinstance, and the list of targetTranslations. It expected to return string.
If you want to pass a Visual Context to Smartling after a Job is synced, you need to provide a way to get hold of the appropriate URL for the page to use context. You provide this via the
VISUAL_CONTEXT_CALLBACKsetting.If this callback is defined, it will be used to send the visual context to Smartling. This step happens just after the regular sync of a Job to Smartling and only if the callback is defined.
The callback must take the Job instance and return:
- a URL for the page that shows the content used to generate that Job
- the HTML of the page.
from wagtail.models import Page from wagtail_localize.models import Job from wagtail_localize_smartling.exceptions import IncapableVisualContextCallback def get_visual_context(job: Job) -> tuple[str, str]: # This assumes the page is live and visible. If the page is a # draft, you will need a some custom work to expose the draft # version of the page content_obj = job.translation_source.get_source_instance() # IMPORTANT: if your translatable objects include some where a visual # context is not available via a standalone, public URL (eg a Snippet, # rather than a Page), then your settings.VISUAL_CONTEXT_CALLBACK function # should raise IncapableVisualContextCallback with an explaination. # Below, we check if the object is a Page, but depending on how your objects # are previewable, you could use isinstance(content_obj, PreviewableMixin) if not isinstance(content_obj, Page): raise IncapableVisualContextCallback( "Object was not visually previewable" ) page_url = page.full_url html = # code to render that page instance return page_url, html
Note that if the syncing of the visual context fails, this will break the overall sync to Smartling, leaving an inconsistent state: there'll be a Job created in Smartling that's awaiting approval, but Wagtail will still think the job needs to be created. This, in turn, will mean we get duplicate job errors on the retry. Therefore, it is essential you have log handling set up to catch the
ERROR-level alert that will happen at this point. -
Run migrations:
./manage.py migrate
Setup
Smartling project setup
For the plugin to work with a Smartling project, the Django/Wagtail internationalization- and localization-related settings must be compatible with the project's language settings:
- Only Wagtail content authored in the same language as the Smartling project's source language can be translated.
- Ideally, the language tags in
WAGTAIL_CONTENT_LANGUAGESshould be the exact, case-insensitive matches for the Smartling projects target locales. For example, if your Smartling project targetsfr-FR, then you must have"fr-fr"in yourWAGTAIL_CONTENT_LANGUAGES, not just"fr". However, if that is not possible, use theLOCALE_TO_SMARTLING_LOCALEorLOCALE_MAPPING_CALLBACKsettings to map your Wagtail language codes to the Smartling language codes.
Synchronization
The plugin provides a sync_smartling management command that:
- Creates jobs in Smartling for new content that's awaiting translation
- Checks the status of pending translation jobs
- Downloads and applies translations for completed jobs
This command should be set to run periodically via cron or similiar:
./manage.py sync_smartling
We recommend running this regularly, around once every 10 minutes.
Callbacks
As well as the sync_smartling management command, the plugin sets the callbackUrl field on the Smartling jobs it creates to the URL of webhook handler view. This handler will proactively download and apply translations from completed jobs without waiting for the next sync_smartling run. This URL is based on the WAGTAILADMIN_BASE_URL setting, so it's important that's set and accessible from the internet.
[!WARNING] Callbacks should not be relied on as the only method for downloading translations. Always make sure the
sync_smartlingcommand is run regularly to ensure your translations are up-to-date.
Usage
Submitting new content for translation
Updating translations
How it works
Workflow
Submitting pages for Smartling translation
flowchart LR
submitPageForTranslation["Page submitted for translation in Wagtail"]
submitToSmartling{"
User choses to submit
translation job to Smartling?
"}
enterSmartlingJobConfig["User enters Smartling job config"]
pendingSmartlingJobCreated["A pending Smartling job is created in Wagtail"]
wagtailSyncedTranslationEditView["
User is redirected to Wagtail's
synced translation edit view
"]
submitPageForTranslation-->submitToSmartling
submitToSmartling-->|Yes|enterSmartlingJobConfig
enterSmartlingJobConfig-->pendingSmartlingJobCreated
pendingSmartlingJobCreated-->wagtailSyncedTranslationEditView
submitToSmartling-->|No|wagtailSyncedTranslationEditView
Smartling sync
django-admin sync_smartling, the below flowchart describes the logic run for each job
flowchart LR
jobSentToSmartling{"Has the job been
sent to Smartling yet?"}
sendJobToSmartling["Send job to Smartling"]
jobFinished{"Is the job finalised?"}
updateJobFromSmartling["Update job from Smartling"]
fin["End"]
jobSentToSmartling-->|Yes|jobFinished
jobSentToSmartling-->|No|sendJobToSmartling
sendJobToSmartling-->fin
jobFinished-->|Yes|fin
jobFinished-->|No|updateJobFromSmartling
Signals
This app provides a single wagtail_localize.signals.translation_imported
signal that is sent when translation are imported from Smartling.
Signal kwargs:
sender: Thewagtail_localize_smartling.models.Jobclassinstance: TheJobinstance for which translation are being importedtranslation: Thewagtail_localize.models.Translationinstance the translations are being imported to. Usetranslation.get_target_instance()to get the model instance that the translation is for (e.g. a page or snippet)
Cutting a new release
- Bump the version in https://github.com/mozilla/wagtail-localize-smartling/blob/main/src/wagtail_localize_smartling/__init__.py
- Update CHANGELOG.md
- Commit and land the changes in main (via a PR, or committing to main if you're sure this won't cause clashes)
- Tag the release as
vX.Y.Zonmain– or make a tag via the GH UI in Step 6. (Remember to push up the new tag if you made it locally, withgit push --tags) - Add a new Release via https://github.com/mozilla/wagtail-localize-smartling/releases
- Select (or create) the new tag, add the title and description
- Ensure the new Release is marked as latest (see checkboxes below the Release description)
- Publish the new Release within GitHub - automation will take of the rest and push it up to PyPI
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wagtail_localize_smartling-0.6.1.tar.gz.
File metadata
- Download URL: wagtail_localize_smartling-0.6.1.tar.gz
- Upload date:
- Size: 41.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
292c2d66ac72ea9924a553fad8f57035983437c97d53eb9eb3b8cca17852f54b
|
|
| MD5 |
3f5a3545cc68655056ce7bd8581969ea
|
|
| BLAKE2b-256 |
081f38c2f45ca3de7f6dacfc782c7dad8fd021a5b58d17e76bbcae99194eb1ad
|
Provenance
The following attestation bundles were made for wagtail_localize_smartling-0.6.1.tar.gz:
Publisher:
publish.yml on mozilla/wagtail-localize-smartling
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wagtail_localize_smartling-0.6.1.tar.gz -
Subject digest:
292c2d66ac72ea9924a553fad8f57035983437c97d53eb9eb3b8cca17852f54b - Sigstore transparency entry: 151679558
- Sigstore integration time:
-
Permalink:
mozilla/wagtail-localize-smartling@e43336627676394efca1e9d694a6373b285fe933 -
Branch / Tag:
refs/tags/v0.6.1 - Owner: https://github.com/mozilla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e43336627676394efca1e9d694a6373b285fe933 -
Trigger Event:
release
-
Statement type:
File details
Details for the file wagtail_localize_smartling-0.6.1-py3-none-any.whl.
File metadata
- Download URL: wagtail_localize_smartling-0.6.1-py3-none-any.whl
- Upload date:
- Size: 49.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9373e53328637aaed9cb7f368f892849fa88685f464f192c1e21c8e202da3457
|
|
| MD5 |
d775103c44827820907f873345a2394e
|
|
| BLAKE2b-256 |
df5e372ccbdc224c33ab69d9784ea37b62fd5214e89ddd62733e00b6bbb1f214
|
Provenance
The following attestation bundles were made for wagtail_localize_smartling-0.6.1-py3-none-any.whl:
Publisher:
publish.yml on mozilla/wagtail-localize-smartling
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wagtail_localize_smartling-0.6.1-py3-none-any.whl -
Subject digest:
9373e53328637aaed9cb7f368f892849fa88685f464f192c1e21c8e202da3457 - Sigstore transparency entry: 151679562
- Sigstore integration time:
-
Permalink:
mozilla/wagtail-localize-smartling@e43336627676394efca1e9d694a6373b285fe933 -
Branch / Tag:
refs/tags/v0.6.1 - Owner: https://github.com/mozilla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e43336627676394efca1e9d694a6373b285fe933 -
Trigger Event:
release
-
Statement type: