I'm trying to automate the translation of a Wagtail website with hundreds of pages. My goal is to create a Django command to translate all the pages with deepl. I can't find any documentation about it. Anyone as ever encountered the same issue ?
I'm using Wagtail 5.2 and wagtail-localize 1.7
At the end I managed to do what I wanted with this script :
management/commands/translate_all_pages.py
from django.core.management.base import BaseCommand
import json
from collections import defaultdict
from django.db import models, transaction
from django.shortcuts import get_object_or_404, redirect, render
from wagtail_localize.machine_translators import get_machine_translator
from wagtail_localize.models import (
StringTranslation,
Translation,
)
from wagtail_localize.segments import StringSegmentValue
from wagtail.models import Locale, Page
from wagtail_localize.operations import translate_object
def machine_translate(translation_id):
translation = get_object_or_404(Translation, id=translation_id)
translator = get_machine_translator()
# Get segments
segments = defaultdict(list)
for string_segment in translation.source.stringsegment_set.all().select_related(
"context", "string"
):
segment = StringSegmentValue(
string_segment.context.path, string_segment.string.as_value()
).with_order(string_segment.order)
if string_segment.attrs:
segment.attrs = json.loads(string_segment.attrs)
# Don't translate if there already is a translation
if StringTranslation.objects.filter(
translation_of_id=string_segment.string_id,
locale=translation.target_locale,
context_id=string_segment.context_id,
).exists():
continue
segments[segment.string].append(
(string_segment.string_id, string_segment.context_id)
)
if segments:
translations = translator.translate(
translation.source.locale, translation.target_locale, segments.keys()
)
with transaction.atomic():
for string, contexts in segments.items():
for string_id, context_id in contexts:
StringTranslation.objects.get_or_create(
translation_of_id=string_id,
locale=translation.target_locale,
context_id=context_id,
defaults={
"data": translations[string].data,
"translation_type": StringTranslation.TRANSLATION_TYPE_MACHINE,
"tool_name": translator.display_name,
# "last_translated_by": User.objects.get(username="admin"),
"has_error": False,
"field_error": "",
},
)
print("Successfully translated with {}.".format(translator.display_name))
else:
print("There isn't anything left to translate.")
class Command(BaseCommand):
help = "Translate all pages if not already translated."
# def add_arguments(self, parser):
# parser.add_argument("translation_id", nargs="+", type=int)
def publish_translated_page(self, translation):
# Récupérer la page traduite
translated_page = translation.get_target_instance()
# Vérifier si la page peut être publiée
if translated_page.has_unpublished_changes:
translated_page.save_revision().publish()
self.stdout.write(
self.style.SUCCESS(f'Page "{translated_page}" published in locale {translation.target_locale}'))
def create_translation_for_all_pages(self):
french_locale = Locale.objects.get(language_code="fr")
other_locales = Locale.objects.exclude(language_code="fr")
french_pages = Page.objects.filter(locale__language_code='fr')
counter = 1
french_pages_count = french_pages.count()
for page in french_pages:
try:
translate_object(page, other_locales)
print(f'translated {page} to other locales')
except Exception as e:
print(e)
continue
print(f'{counter}/{french_pages_count} pages translated')
counter += 1
def translate_page(self, translation):
# translation = get_object_or_404(Translation, id=kwargs["translation_id"][0])
translator = get_machine_translator()
# Get segments
segments = defaultdict(list)
for string_segment in translation.source.stringsegment_set.all().select_related(
"context", "string"
):
segment = StringSegmentValue(
string_segment.context.path, string_segment.string.as_value()
).with_order(string_segment.order)
if string_segment.attrs:
segment.attrs = json.loads(string_segment.attrs)
# Don't translate if there already is a translation
if StringTranslation.objects.filter(
translation_of_id=string_segment.string_id,
locale=translation.target_locale,
context_id=string_segment.context_id,
).exists():
continue
segments[segment.string].append(
(string_segment.string_id, string_segment.context_id)
)
if segments:
translations = translator.translate(
translation.source.locale, translation.target_locale, segments.keys()
)
with transaction.atomic():
for string, contexts in segments.items():
for string_id, context_id in contexts:
StringTranslation.objects.get_or_create(
translation_of_id=string_id,
locale=translation.target_locale,
context_id=context_id,
defaults={
"data": translations[string].data,
"translation_type": StringTranslation.TRANSLATION_TYPE_MACHINE,
"tool_name": translator.display_name,
# "last_translated_by": User.objects.get(username="admin"),
"has_error": False,
"field_error": "",
},
)
self.stdout.write(
self.style.SUCCESS(
f"{translation.get_target_instance().title} - {translation.get_target_instance().pk} - Successfully translated with {translator.display_name}.")
)
self.publish_translated_page(translation)
else:
self.stdout.write(
self.style.WARNING(
f"{translation.get_target_instance().title} - {translation.get_target_instance().pk}- There isn't anything left to translate.")
)
def handle(self, *args, **options):
# translation = get_object_or_404(Translation, id=kwargs["translation_id"][0])
self.create_translation_for_all_pages()
for translation in Translation.objects.all():
self.translate_page(translation)
self.create_translation_for_all_pages()
self.stdout.write(self.style.SUCCESS('Successfully translated all pages.'))
When I run python manage.py translate_all_pages all the pages of my site are translated and published.