wagtaildeeplwagtail-localize

wagtail localize translate page programmatically with deepl


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


Solution

  • 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.