Coverage for app/venv/lib/python3.14/site-packages/weblate/trans/views/source.py: 22%
89 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 login_required
9from django.core.exceptions import PermissionDenied
10from django.db import transaction
11from django.http import Http404
12from django.http.response import HttpResponseServerError
13from django.shortcuts import get_object_or_404
14from django.utils.translation import gettext
15from django.views.decorators.http import require_POST
17from weblate.checks.flags import Flags
18from weblate.trans.forms import ContextForm, MatrixLanguageForm
19from weblate.trans.models import Component, Unit
20from weblate.trans.util import redirect_next, render
21from weblate.utils import messages
22from weblate.utils.views import parse_path, show_form_errors
24if TYPE_CHECKING: 24 ↛ 25line 24 didn't jump to line 25 because the condition on line 24 was never true
25 from weblate.auth.models import AuthenticatedHttpRequest
28@require_POST
29@login_required
30@transaction.atomic
31def edit_context(request: AuthenticatedHttpRequest, pk):
32 unit = get_object_or_404(Unit, pk=pk)
33 if not unit.is_source and not unit.translation.component.is_glossary:
34 msg = "Non source unit!"
35 raise Http404(msg)
37 do_add = "addflag" in request.POST
38 if do_add or "removeflag" in request.POST:
39 if not request.user.has_perm("meta:unit.flag", unit.translation):
40 raise PermissionDenied
41 flag = request.POST.get("addflag", request.POST.get("removeflag"))
42 flags = unit.get_unit_flags()
43 if (
44 flag in {"terminology", "forbidden", "read-only"}
45 and not unit.is_source
46 and flag not in flags
47 ):
48 unit = unit.source_unit
49 flags = Flags(unit.extra_flags)
50 if do_add:
51 flags.merge(flag)
52 else:
53 flags.remove(flag)
54 new_flags = flags.format()
55 if new_flags != unit.extra_flags:
56 unit.update_extra_flags(new_flags, request.user)
57 else:
58 if not request.user.has_perm("source.edit", unit.translation):
59 raise PermissionDenied
61 form = ContextForm(request.POST, instance=unit, user=request.user)
63 if form.is_valid():
64 form.save()
65 else:
66 messages.error(request, gettext("Could not change additional string info!"))
67 show_form_errors(request, form)
69 return redirect_next(request.POST.get("next"), unit.get_absolute_url())
72@login_required
73def matrix(request: AuthenticatedHttpRequest, path):
74 """Matrix view of all strings."""
75 obj = parse_path(request, path, (Component,))
77 show = False
78 translations = None
79 language_codes_url = None
81 if "lang" in request.GET:
82 form = MatrixLanguageForm(obj, request.GET)
83 show = form.is_valid()
84 else:
85 form = MatrixLanguageForm(obj)
87 if show:
88 translations = (
89 obj.translation_set.filter(language__code__in=form.cleaned_data["lang"])
90 .select_related("language")
91 .order()
92 )
93 language_codes_url = "&".join(
94 f"lang={translation.language.code}" for translation in translations
95 )
97 return render(
98 request,
99 "matrix.html",
100 {
101 "object": obj,
102 "project": obj.project,
103 "component": obj,
104 "translations": translations,
105 "language_codes_url": language_codes_url,
106 "languages_form": form,
107 },
108 )
111@login_required
112def matrix_load(request: AuthenticatedHttpRequest, path):
113 """Backend for matrix view of all strings."""
114 obj = parse_path(request, path, (Component,))
116 try:
117 offset = int(request.GET.get("offset", ""))
118 except ValueError:
119 return HttpResponseServerError("Missing offset")
120 form = MatrixLanguageForm(obj, request.GET)
121 if not form.is_valid():
122 return HttpResponseServerError("Missing lang")
123 language_codes = form.cleaned_data["lang"]
125 # Can not use filter to keep ordering
126 translations = [
127 get_object_or_404(obj.translation_set, language__code=lang)
128 for lang in language_codes
129 ]
131 data = []
133 source_units = obj.source_translation.unit_set.order()[offset : offset + 20]
134 source_ids = [unit.pk for unit in source_units]
136 translated_units = [
137 {
138 unit.source_unit_id: unit
139 for unit in translation.unit_set.order().filter(source_unit__in=source_ids)
140 }
141 for translation in translations
142 ]
144 for unit in source_units:
145 units = []
146 # Avoid need to fetch source unit again
147 unit.source_unit = unit
148 for translation in translated_units:
149 if unit.pk in translation:
150 # Avoid need to fetch source unit again
151 translation[unit.pk].source_unit = unit
152 units.append(translation[unit.pk])
153 else:
154 units.append(None)
156 data.append((unit, units))
158 return render(
159 request,
160 "matrix-table.html",
161 {
162 "object": obj,
163 "data": data,
164 "last": translations[0].unit_set.count() <= offset + 20,
165 },
166 )