/
translations_management_form.py
161 lines (134 loc) · 5.84 KB
/
translations_management_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
156
157
158
159
160
161
from __future__ import annotations
import logging
from dataclasses import dataclass
from typing import TYPE_CHECKING
from django import forms
from django.utils.translation import gettext_lazy as _
from ...models import LanguageTreeNode, Region
from ..custom_model_form import CustomModelForm
if TYPE_CHECKING:
from typing import Any, Iterator
from ....core.utils.machine_translation_provider import (
MachineTranslationProviderType,
)
logger = logging.getLogger(__name__)
class CustomCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
"""
Custom CheckboxSelectMultiple child class which appends a machine
translation provider to option labels or disables them if no provider
is available
"""
#: The template to use when rendering this widget
template_name: str = "translations/languages_input.html"
@dataclass
class TranslationLanguageOptions:
"""
Helper class to easily provide the translation providers for a language for form fields.
"""
language_tree_node: LanguageTreeNode
@property
def choices(self) -> list[tuple[str, str]]:
"""
:attr:`~integreat_cms.cms.models.languages.language_tree_node.LanguageTreeNode.mt_providers` as list of tuples for :attr:`django.forms.ChoiceField.choices`
"""
return [
(provider.name, provider.name)
for provider in self.language_tree_node.mt_providers
]
@property
def providers(self) -> dict[str, MachineTranslationProviderType]:
"""
:attr:`~integreat_cms.cms.models.languages.language_tree_node.LanguageTreeNode.mt_providers` as a dict, indexed by :attr:`~integreat_cms.core.utils.machine_translation_provider.MachineTranslationProvider.name`
"""
return {
provider.name: provider for provider in self.language_tree_node.mt_providers
}
@property
def initial(self) -> str:
"""
:attr:`mt_provider.name <integreat_cms.core.utils.machine_translation_provider.MachineTranslationProvider.name>` for :attr:`django.forms.Field.initial`
"""
return self.language_tree_node.mt_provider.name
class TranslationsManagementForm(CustomModelForm):
"""
Form for modifying machine translation settings of a region
"""
#: The languages that cannot be selected at the moment
unavailable_languages: list[str] = []
class Meta:
"""
This class contains additional meta configuration of the form class,
see the :class:`django.forms.ModelForm` for more information.
"""
#: The model of this :class:`django.forms.ModelForm`
model = Region
#: The fields of the model which should be handled by this form
fields = [
"machine_translate_pages",
"machine_translate_events",
"machine_translate_pois",
]
def __init__(self, *args: Any, **kwargs: Any) -> None:
r"""
Initialize translations management form
:param \*args: The supplied arguments
:param \**kwargs: The supplied keyword arguments
"""
self.uncleaned_data: Any = kwargs.get("data")
super().__init__(*args, **kwargs)
self.languages_dict = kwargs.pop("languages_dict", {})
languages = self.instance.language_tree_nodes.filter(
active=True, parent__isnull=False
).select_related("language")
self.unavailable_languages = []
for language in languages:
if language.mt_provider:
self.languages_dict[language.slug] = TranslationLanguageOptions(
language_tree_node=language
)
else:
self.unavailable_languages.append(language.translated_name)
def get_language_fields(self) -> Iterator[forms.ChoiceField]:
"""
Generator for a :class:`django.forms.ChoiceField` for each language with the available translation providers
"""
for slug, language_options in self.languages_dict.items():
self.fields[slug] = forms.ChoiceField(
label=language_options.language_tree_node.translated_name,
choices=language_options.choices,
initial=language_options.initial,
)
yield self[slug]
def save(self, commit: bool = True) -> Region:
"""
This method extends the default ``save()``-method of the base :class:`~django.forms.ModelForm` to set attributes
which are not directly determined by input fields.
:param commit: Whether or not the changes should be written to the database
:return: The saved region object
"""
# Save CustomModelForm
region = super().save(commit=commit)
# Iterate over all machine translatable languages and toggle them based on the checkbox value
for lang, language_options in self.languages_dict.items():
if provider_name := self.uncleaned_data.get(lang, None):
if provider_name in language_options.providers:
language_options.language_tree_node.preferred_mt_provider = (
language_options.providers[provider_name]
)
language_options.language_tree_node.save()
logger.info(
"%s: Set provider %s for %s", region.slug, provider_name, lang
)
else:
logger.info(
"%s: Bogus provider %r for %s! (acceptable values: %s)",
region.slug,
provider_name,
lang,
", ".join(language_options.providers.keys()),
)
else:
logger.info(
"%s: Provider for language %s was not sent", region.slug, lang
)
return region