/
machine_translation_form.py
155 lines (128 loc) · 5.72 KB
/
machine_translation_form.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
from django import forms
from django.utils.translation import gettext_lazy as _
if TYPE_CHECKING:
from typing import Any
from treebeard.ns_tree import NS_NodeQuerySet
from ..models import EventTranslation, PageTranslation, POITranslation
from ...core.utils.machine_translation_provider import MachineTranslationProvider
from ...textlab_api.utils import check_hix_score
from ..models import LanguageTreeNode
from .custom_content_model_form import CustomContentModelForm
logger = logging.getLogger(__name__)
class MachineTranslationForm(CustomContentModelForm):
"""
Form for selecting target languages for machine translation of a content object.
It should be used as base class for translation forms which enable machine translations.
"""
mt_translations_to_create = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple(),
queryset=LanguageTreeNode.objects.none(),
required=False,
label=_("Create new translations:"),
)
mt_translations_to_update = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple(),
queryset=LanguageTreeNode.objects.none(),
required=False,
label=_("Update existing translations:"),
)
def __init__(self, **kwargs: Any) -> None:
r"""
Initialize MT translation form. If request and language kwargs are missing, MTs are disabled.
:param \**kwargs: The supplied keyword arguments
"""
# Pop kwargs to make sure the super class does not get this params
self.request = kwargs.pop("request", None)
self.language = kwargs.pop("language", None)
# Initialize CustomContentModelForm
super().__init__(**kwargs)
if not self.request or not self.language:
self.logger.debug(
"%s initialized without support for machine translations",
type(self).__name__,
)
return
if not MachineTranslationProvider.is_permitted(
self.request.region, self.request.user, self._meta.model
):
return
parent_node = self.request.region.language_node_by_slug.get(self.language.slug)
translation_targets = [
language_node
for language_node in self.request.region.language_tree
if language_node.parent_id == parent_node.id and language_node.mt_provider
]
to_create: list[int] = []
to_update: list[int] = []
for target in translation_targets:
target_type = (
to_update
if self.instance.id
and target.language in self.instance.foreign_object.languages
else to_create
)
target_type.append(target.id)
self.fields["mt_translations_to_create"].queryset = (
self.request.region.language_tree_nodes.filter(id__in=to_create)
)
self.fields["mt_translations_to_update"].queryset = (
self.request.region.language_tree_nodes.filter(id__in=to_update)
)
self.initial["mt_translations_to_update"] = to_update
def mt_form_is_enabled(self) -> NS_NodeQuerySet:
"""
Helper method to decide if this form should be shown, or if it should be hidden for
the current language due to a lack of MT-compatible child language nodes
:return: Whether this form is enabled
"""
return (
self.fields["mt_translations_to_update"].queryset
or self.fields["mt_translations_to_create"].queryset
)
def clean(self) -> dict[str, Any]:
"""
Validate form fields which depend on each other, see :meth:`django.forms.Form.clean`
:return: The cleaned form data
"""
cleaned_data = super().clean()
if not cleaned_data.get("automatic_translation"):
cleaned_data["mt_translations_to_create"] = LanguageTreeNode.objects.none()
cleaned_data["mt_translations_to_update"] = LanguageTreeNode.objects.none()
return cleaned_data
def save(
self, commit: bool = True, foreign_form_changed: bool = False
) -> EventTranslation | (PageTranslation | POITranslation):
"""
Create machine translations and save them to the database
:param commit: Whether or not the changes should be written to the database
:param foreign_form_changed: Whether or not the foreign form of this translation form was changed
:return: The saved content translation object
"""
self.instance = super().save(commit, foreign_form_changed)
language_nodes = self.cleaned_data["mt_translations_to_create"].union(
self.cleaned_data["mt_translations_to_update"]
)
if commit and language_nodes and check_hix_score(self.request, self.instance):
for language_node in language_nodes:
logger.debug(
"Machine translation via %r into %r for: %r",
language_node.mt_provider,
language_node.language,
self.instance,
)
api_client = language_node.mt_provider.api_client(
self.request, type(self)
)
# Invalidate cached property to take new version into account
self.instance.foreign_object.invalidate_cached_translations()
api_client.translate_object(
self.instance.foreign_object, language_node.slug
)
return self.instance
class Meta(CustomContentModelForm.Meta):
"""
Inherit the meta class from the custom content model form
"""