Coverage for app/venv/lib/python3.14/site-packages/weblate/glossary/forms.py: 33%
57 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
1# Copyright © Michal Čihař <michal@weblate.org>
2#
3# SPDX-License-Identifier: GPL-3.0-or-later
5from __future__ import annotations
7from typing import TYPE_CHECKING, cast
9from django import forms
10from django.core.exceptions import ValidationError
11from django.utils.translation import gettext
13from weblate.trans.forms import NewBilingualGlossaryUnitForm
14from weblate.trans.models import Translation, Unit
16if TYPE_CHECKING: 16 ↛ 17line 16 didn't jump to line 17 because the condition on line 16 was never true
17 from weblate.auth.models import User
18 from weblate.trans.models.translation import NewUnitParams
21class CommaSeparatedIntegerField(forms.Field):
22 def to_python(self, value) -> list[int]:
23 if not value:
24 return []
26 try:
27 return [int(item.strip()) for item in value.split(",") if item.strip()]
28 except (ValueError, TypeError) as error:
29 raise ValidationError(gettext("Invalid integer list!")) from error
32class GlossaryModelChoiceField(forms.ModelChoiceField):
33 def label_from_instance(self, obj) -> str:
34 return obj.component.name
37class TermForm(NewBilingualGlossaryUnitForm, forms.ModelForm):
38 """Form for adding term to a glossary."""
40 terms = CommaSeparatedIntegerField(widget=forms.HiddenInput, required=False)
42 class Meta:
43 model = Unit
44 fields = [ # noqa: RUF012
45 "context",
46 "source",
47 "target",
48 "translation",
49 "explanation",
50 ]
51 widgets = { # noqa: RUF012
52 "context": forms.TextInput,
53 "source": forms.TextInput,
54 "target": forms.TextInput,
55 "explanation": forms.TextInput,
56 }
57 field_classes = { # noqa: RUF012
58 "translation": GlossaryModelChoiceField,
59 }
61 def __init__(self, unit: Unit, user: User, data: dict | None = None) -> None:
62 self.unit = unit
63 translation = unit.translation
64 self.glossaries = Translation.objects.filter(
65 language=translation.language,
66 component__in=translation.component.project.glossaries,
67 component__manage_units=True,
68 ).prefetch()
69 exclude = [
70 glossary.pk
71 for glossary in self.glossaries
72 if not user.has_perm("unit.add", glossary)
73 ]
74 if exclude:
75 self.glossaries = self.glossaries.exclude(pk__in=exclude)
77 super().__init__(
78 translation=translation,
79 user=user,
80 data=data,
81 auto_id="id_add_term_%s",
82 )
84 def patch_fields(self) -> None:
85 super().patch_fields()
86 self.fields["translation"].queryset = self.glossaries
87 self.fields["translation"].label = gettext("Glossary")
88 if len(self.glossaries) == 1:
89 self.fields["translation"].initial = self.glossaries[0]
91 if self.unit.is_source:
92 self.fields["terminology"].initial = True
94 if self.unit.translation.is_source:
95 self.fields["target"].required = False
96 self.fields["target"].widget = forms.HiddenInput()
98 def clean(self) -> None:
99 self.translation = cast("Translation", self.cleaned_data.get("translation"))
100 # Validate fields only if translation is valid
101 if self.translation:
102 super().clean()
104 def as_kwargs(self) -> NewUnitParams:
105 result = super().as_kwargs()
106 if self.cleaned_data["translation"].is_source:
107 result["target"] = result["source"]
108 result["skip_existing"] = bool(self.cleaned_data.get("terminology"))
109 return result