Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature request: Machine translate and publish #786

Open
onno-timmerman opened this issue Mar 5, 2024 · 5 comments
Open

feature request: Machine translate and publish #786

onno-timmerman opened this issue Mar 5, 2024 · 5 comments

Comments

@onno-timmerman
Copy link
Contributor

When you sync a page there is this nice option "immediate publish"
Could there also be an option "Machine translate and plublish" so the translation is already done by Deepl etc..

image

@zerolab
Copy link
Collaborator

zerolab commented Mar 5, 2024

Ooh, I like this idea. We'd need:

  1. to detect we have a machine translator configured
  2. change the checkbox to a radio button or select so only one option is allowed. Alternatively, add some JS to untick the other option when one of them is ticked
  3. trigger the machine translation workflow after sync, then do the publishing

@zerolab zerolab changed the title feature request feature request: Machine translate and publish Mar 10, 2024
@waldo90
Copy link

waldo90 commented Jun 7, 2024

I'm currently developing an automatic machine translation feature on a client's website - I feel it's pretty close to what's being discussed here. Currently the implementation is external to wagtail-localize and lacks the UI selection feature - it hooks the after_create_page event and machine translates to all configured locales.

Something like:

wagtail_hooks.py

...
@hooks.register('after_create_page')
def after_create_page(request, page):

    locales_translated = machine.create_machine_translations(page, request.user)
    if request.POST.get('action-publish') == 'action-publish':
        machine.publish_translations(page, request.user)
        machine.stop_translations(page, request.user)

    langs = [l.language_name for l in locales_translated]
    langs_string = " and ".join([", ".join(langs[:-1]),langs[-1]])
    message = f"{page.locale.language_name} page has also been machine translated into { langs_string }"

    messages.success(
        request,
        message,
    )

machine.py

def create_machine_translations(page, user):
    """
    Progress untranslated locale pages to fully translated pages
    under Translation workflow
    """
    locales = [locale for locale in Locale.objects.all() if locale != page.locale]

    translate_object( page, locales, user=user)

    translations = Translation.objects.filter(source__object_id=page.translation_key)
    translator = get_machine_translator()

    for translation in translations:
        # 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,
                                "has_error": False,
                                "field_error": "",
                            },
                        )
    return locales

def publish_translations(page, user):
    """Publish all the translations associated with a page"""
    translations = Translation.objects.filter(source__object_id=page.translation_key)
    for translation in translations:
        translation.save_target(user=user, publish=True)

def stop_translations(page, user):
    translations = Translation.objects.filter(source__object_id=page.translation_key)
    for translation in translations:
        translation.enabled = False
        translation.save(update_fields=['enabled'])

Perhaps the above will be useful but I'd also be happy to work on this: add the machine-translator detection and UI step and submit a PR.

@zerolab
Copy link
Collaborator

zerolab commented Jun 13, 2024

@waldo90 a PR would be welcome

@martibosch
Copy link

martibosch commented Aug 13, 2024

is there any timeline for merging this PR? This would be extremely useful for us :) (thank you @waldo90)

@zerolab
Copy link
Collaborator

zerolab commented Aug 16, 2024

Hi all, I am hoping to do some wagtail-localize maintenance next week, so I hope to get to this as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants