Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 35 additions & 20 deletions wagtail_localize/views/update_translations.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,32 @@
from wagtail_localize.views.submit_translations import TranslationComponentManager


def update_translations(
request,
instance,
translations,
use_machine_translation=False,
publish_translations=False,
):
instance.update_from_db()

if use_machine_translation:
machine_translator = get_machine_translator()
for translation in translations.select_related("target_locale"):
apply_machine_translation(translation.id, request.user, machine_translator)

if publish_translations:
for translation in translations.select_related("target_locale"):
with contextlib.suppress(ValidationError):
translation.save_target(user=request.user, publish=True)
else:
for translation in translations.select_related("source", "target_locale"):
with contextlib.suppress(ValidationError):
translation.source.update_target_view_restrictions(
translation.target_locale
)


class UpdateTranslationsForm(forms.Form):
publish_translations = forms.BooleanField(
label=gettext_lazy("Publish immediately"),
Expand Down Expand Up @@ -153,28 +179,17 @@ def post(self, request, **kwargs):

@transaction.atomic
def form_valid(self, form):
self.object.update_from_db()

enabled_translations = self.object.translations.filter(enabled=True)
if form.cleaned_data.get("use_machine_translation"):
machine_translator = get_machine_translator()
for translation in enabled_translations.select_related("target_locale"):
apply_machine_translation(
translation.id, self.request.user, machine_translator
)

if form.cleaned_data["publish_translations"]:
for translation in enabled_translations.select_related("target_locale"):
with contextlib.suppress(ValidationError):
translation.save_target(user=self.request.user, publish=True)
else:
for translation in enabled_translations.select_related(
"source", "target_locale"
):
with contextlib.suppress(ValidationError):
translation.source.update_target_view_restrictions(
translation.target_locale
)
update_translations(
self.request,
self.object,
enabled_translations,
use_machine_translation=form.cleaned_data.get(
"use_machine_translation", False
),
publish_translations=form.cleaned_data["publish_translations"],
)

self.components.save(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With publish+auto-machine-translate we cannot really handle those components, I think. With bulk actions we may add those components to the confirmation view. That's why I have not extracted them into update_translations().

I also don't fully understand them. Are those components meant to be created once per translation request or once per translation source? I know, it's up to the dev, but it would be nice to get some infos on how this has been used so far.

self.object,
Expand Down
90 changes: 90 additions & 0 deletions wagtail_localize/wagtail_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

from urllib.parse import urlencode

from django.conf import settings
from django.contrib.admin.utils import quote
from django.contrib.auth.models import Permission
from django.db import transaction
from django.db.models import Q
from django.shortcuts import redirect
from django.urls import include, path, reverse
from django.utils import timezone
from django.utils.translation import gettext as _
from django.utils.translation import gettext_lazy
from django.views.i18n import JavaScriptCatalog
Expand All @@ -20,6 +23,7 @@

# Import synctree so it can register its signal handler
from . import synctree # noqa: F401
from .machine_translators import get_machine_translator
from .models import Translation, TranslationSource
from .views import (
convert,
Expand Down Expand Up @@ -258,6 +262,12 @@ def before_edit_page(request, page):
return redirect(
reverse("wagtail_localize:convert_to_alias", args=[page.id])
)
elif "localize-publish-with-machine-translation" in request.POST:
request.POST = request.POST.copy()
request.POST["action-publish"] = "action-publish"
# This field will be checked by the "after_publish_page" hook. Since the page instance gets reloaded
# before "after_publish_page" is called, we have to use the request object to keep the flag.
request._localize_machine_translation_on_publish = page.id

# Overrides the edit page view if the page is the target of a translation
try:
Expand All @@ -272,6 +282,51 @@ def before_edit_page(request, page):
pass


@hooks.register("after_publish_page")
def after_publish_page(request, page):
if getattr(request, "_localize_machine_translation_on_publish", None) == page.id:
# Note: Syncing the go-live-date to the translations is not supported yet. To avoid publishing the
# translations too early, we skip it.
# TODO: Remove/Adapt this code and PublishWithMachineTranslationPageActionMenuItem, when go_live_at is synced with translations.
go_live_at = page.go_live_at
if go_live_at and go_live_at > timezone.now():
return

if get_machine_translator() is None:
return

# This is executed after publication, so we don't have to check can_publish().
if not request.user.has_perm("wagtail_localize.submit_translation"):
return

source = TranslationSource.objects.get_for_instance_or_none(page)
if source is None or not source.translations.filter(enabled=True).exists():
return

with transaction.atomic():
update_translations.update_translations(
request,
source,
source.translations.filter(enabled=True),
use_machine_translation=True,
publish_translations=True,
)
elif getattr(settings, "WAGTAILLOCALIZE_UPDATE_TRANSLATIONS_ON_PUBLISH", False):
if not request.user.has_perm("wagtail_localize.submit_translation"):
return

source = TranslationSource.objects.get_for_instance_or_none(page)
if source is None or not source.translations.filter(enabled=True).exists():
return

with transaction.atomic():
update_translations.update_translations(
request,
source,
source.translations.filter(enabled=True),
)


class RestartTranslationPageActionMenuItem(PageActionMenuItem):
label = gettext_lazy("Start Synced translation")
name = "localize-restart-translation"
Expand Down Expand Up @@ -328,6 +383,41 @@ def register_convert_back_to_alias_page_action_menu_item():
return ConvertToAliasPageActionMenuItem(order=0)


class PublishWithMachineTranslationPageActionMenuItem(PageActionMenuItem):
label = gettext_lazy("Publish & machine translate")
name = "localize-publish-with-machine-translation"
icon_name = "upload"
classname = "action-secondary"

def is_shown(self, context):
# We only support the edit view for now.
if context["view"] != "edit":
return False

# See note in "after_publish_page" hook above.
go_live_at = context["page"].go_live_at
if go_live_at and go_live_at > timezone.now():
return False

if get_machine_translator() is None:
return False

page_perms = self.get_user_page_permissions_tester(context)
if not page_perms.can_publish() or not context["request"].user.has_perm(
"wagtail_localize.submit_translation"
):
return False

# As with the "Sync translated pages" button we only show this menu item, if enabled translations exist.
source = TranslationSource.objects.get_for_instance_or_none(context["page"])
return source is not None and source.translations.filter(enabled=True).exists()


@hooks.register("register_page_action_menu_item")
def register_publish_with_machine_translation_page_action_menu_item():
return PublishWithMachineTranslationPageActionMenuItem()


@hooks.register("before_edit_snippet")
def before_edit_snippet(request, instance):
if isinstance(instance, TranslatableMixin):
Expand Down