Coverage for app/venv/lib/python3.14/site-packages/weblate/lang/views.py: 32%
106 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
4from __future__ import annotations
6from typing import TYPE_CHECKING
8from django.contrib.auth.decorators import permission_required
9from django.http import Http404
10from django.shortcuts import redirect, render
11from django.utils.decorators import method_decorator
12from django.utils.translation import gettext
13from django.views.generic import CreateView, UpdateView
15from weblate.lang.forms import LanguageForm, PluralForm
16from weblate.lang.models import Language, Plural
17from weblate.trans.forms import SearchForm, WorkflowSettingForm
18from weblate.trans.models import Change, WorkflowSetting
19from weblate.trans.models.project import prefetch_project_flags
20from weblate.trans.util import sort_objects
21from weblate.utils import messages
22from weblate.utils.stats import (
23 GlobalStats,
24 ProjectLanguage,
25 ProjectLanguageStats,
26 prefetch_stats,
27)
28from weblate.utils.views import get_paginator
30if TYPE_CHECKING: 30 ↛ 31line 30 didn't jump to line 31 because the condition on line 30 was never true
31 from weblate.auth.models import AuthenticatedHttpRequest
34def show_languages(request: AuthenticatedHttpRequest):
35 custom_workflows = set()
36 if request.user.has_perm("language.edit"):
37 languages = Language.objects.all()
38 custom_workflows = set(
39 WorkflowSetting.objects.filter(project=None).values_list(
40 "language_id", flat=True
41 )
42 )
43 else:
44 languages = Language.objects.have_translation()
46 return render(
47 request,
48 "languages.html",
49 {
50 "allow_index": True,
51 "languages": prefetch_stats(sort_objects(languages)),
52 "custom_workflows": custom_workflows,
53 "title": gettext("Languages"),
54 "global_stats": GlobalStats(),
55 "bootstrap_5": True,
56 },
57 )
60def show_language(request: AuthenticatedHttpRequest, lang):
61 try:
62 obj = Language.objects.get(code=lang)
63 except Language.DoesNotExist as error:
64 obj = Language.objects.fuzzy_get(lang)
65 if isinstance(obj, Language):
66 return redirect(obj)
67 msg = "No Language matches the given query."
68 raise Http404(msg) from error
70 user = request.user
72 if request.method == "POST" and user.has_perm("language.edit"):
73 if obj.translation_set.exists():
74 messages.error(
75 request, gettext("Remove all translations using this language first.")
76 )
77 else:
78 obj.delete()
79 messages.success(request, gettext("Language %s removed.") % obj)
80 return redirect("languages")
82 last_changes = Change.objects.last_changes(user, language=obj).recent()
83 projects = prefetch_project_flags(
84 get_paginator(
85 request,
86 user.allowed_projects.filter(
87 component__translation__language=obj
88 ).distinct(),
89 stats=True,
90 )
91 )
92 project_languages = [ProjectLanguage(project, obj) for project in projects]
94 ProjectLanguageStats.prefetch_many([project.stats for project in project_languages])
96 return render(
97 request,
98 "language.html",
99 {
100 "allow_index": True,
101 "object": obj,
102 "last_changes": last_changes,
103 "search_form": SearchForm(
104 request=request, language=obj, obj=obj, bootstrap_5=True
105 ),
106 "projects": projects,
107 "project_languages": project_languages,
108 "bootstrap_5": True,
109 },
110 )
113@method_decorator(permission_required("language.add"), name="dispatch")
114class CreateLanguageView(CreateView):
115 template_name = "lang/create.html"
117 def get_form(self, form_class=None):
118 kwargs = self.get_form_kwargs()
119 return (LanguageForm(**kwargs), PluralForm(**kwargs))
121 def post(self, request: AuthenticatedHttpRequest, *args, **kwargs):
122 self.object = None
123 forms = self.get_form()
124 if all(form.is_valid() for form in forms):
125 return self.form_valid(forms)
126 return self.form_invalid(forms)
128 def form_valid(self, form):
129 """If the form is valid, save the associated model."""
130 self.object = form[0].save()
131 plural = form[1].instance
132 plural.language = self.object
133 plural.save()
134 return redirect(self.object)
137@method_decorator(permission_required("language.edit"), name="dispatch")
138class EditLanguageView(UpdateView):
139 form_class = LanguageForm
140 model = Language
142 def get_context_data(self, **kwargs):
143 """Insert the form into the context dict."""
144 if "workflow_form" not in kwargs:
145 kwargs["workflow_form"] = self.get_workflow_form()
146 return super().get_context_data(**kwargs)
148 def get_workflow_form(self):
149 kwargs = self.get_form_kwargs()
150 kwargs.pop("instance", None)
151 kwargs.pop("initial", None)
152 if self.workflow_object:
153 kwargs["instance"] = self.workflow_object
154 return WorkflowSettingForm(**kwargs)
156 def get(self, request: AuthenticatedHttpRequest, *args, **kwargs):
157 self.object = self.get_object()
158 try:
159 self.workflow_object = self.object.workflowsetting_set.get(project=None)
160 except WorkflowSetting.DoesNotExist:
161 self.workflow_object = None
162 return super().get(request, *args, **kwargs)
164 def post(self, request: AuthenticatedHttpRequest, *args, **kwargs):
165 self.object = self.get_object()
166 try:
167 self.workflow_object = self.object.workflowsetting_set.get(project=None)
168 except WorkflowSetting.DoesNotExist:
169 self.workflow_object = None
170 form = self.get_form()
171 workflow_form = self.get_workflow_form()
172 if form.is_valid() and workflow_form.is_valid():
173 return self.form_valid(form, workflow_form)
174 return self.render_to_response(
175 self.get_context_data(form=form, workflow_form=workflow_form)
176 )
178 def form_valid(self, form, workflow_form):
179 """If the form is valid, save the associated model."""
180 workflow_form.instance.language = self.object
181 self.workflow_object = workflow_form.save()
182 return super().form_valid(form)
185@method_decorator(permission_required("language.edit"), name="dispatch")
186class EditPluralView(UpdateView):
187 form_class = PluralForm
188 model = Plural