Coverage for app/venv/lib/python3.14/site-packages/weblate/trans/admin.py: 67%
123 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, NoReturn
9from django.conf import settings
10from django.contrib import admin
11from django.utils.translation import gettext_lazy
13from weblate.auth.models import User
14from weblate.trans.models import (
15 Announcement,
16 AutoComponentList,
17 Change,
18 Comment,
19 Component,
20 ComponentList,
21 ContributorAgreement,
22 Project,
23 Suggestion,
24 Translation,
25 Unit,
26)
27from weblate.trans.util import sort_choices
28from weblate.utils.html import format_html_join_comma
29from weblate.wladmin.models import WeblateModelAdmin
31if TYPE_CHECKING: 31 ↛ 32line 31 didn't jump to line 32 because the condition on line 31 was never true
32 from weblate.auth.models import AuthenticatedHttpRequest
35class RepoAdminMixin:
36 @admin.action(description=gettext_lazy("Commit pending changes"))
37 def force_commit(self, request: AuthenticatedHttpRequest, queryset) -> None:
38 """Commit pending changes for selected components."""
39 for obj in queryset:
40 obj.commit_pending("admin", request)
41 self.message_user(
42 request, f"Flushed changes in {queryset.count():d} git repos."
43 )
45 @admin.action(description=gettext_lazy("Update VCS repository"))
46 def update_from_git(self, request: AuthenticatedHttpRequest, queryset) -> None:
47 """Update selected components from git."""
48 for obj in queryset:
49 obj.do_update(request)
50 self.message_user(request, f"Updated {queryset.count():d} git repos.")
52 def get_qs_units(self, queryset) -> NoReturn:
53 raise NotImplementedError
55 def get_qs_translations(self, queryset) -> NoReturn:
56 raise NotImplementedError
58 @admin.action(description=gettext_lazy("Update quality checks"))
59 def update_checks(self, request: AuthenticatedHttpRequest, queryset) -> None:
60 """Recalculate checks for selected components."""
61 units = self.get_qs_units(queryset)
62 for unit in units:
63 unit.run_checks()
65 for translation in self.get_qs_translations(queryset):
66 translation.invalidate_cache()
68 self.message_user(request, f"Updated checks for {len(units):d} units.")
71@admin.register(Project)
72class ProjectAdmin(WeblateModelAdmin, RepoAdminMixin):
73 list_display = (
74 "name",
75 "slug",
76 "web",
77 "list_admins",
78 "access_control",
79 "enable_hooks",
80 "num_vcs",
81 "get_total",
82 "get_source_words",
83 "get_language_count",
84 )
85 prepopulated_fields = { # noqa: RUF012
86 "slug": ("name",),
87 }
88 search_fields = ("name", "slug", "web")
89 actions = ("update_from_git", "update_checks", "force_commit")
91 @admin.display(description=gettext_lazy("Administrators"))
92 def list_admins(self, obj):
93 return format_html_join_comma(
94 "{}", (User.objects.all_admins(obj).values_list("username"))
95 )
97 @admin.display(description=gettext_lazy("Source strings"))
98 def get_total(self, obj):
99 return obj.stats.source_strings
101 @admin.display(description=gettext_lazy("Source words"))
102 def get_source_words(self, obj):
103 return obj.stats.source_words
105 @admin.display(description=gettext_lazy("Languages"))
106 def get_language_count(self, obj):
107 """Return number of languages used in this project."""
108 return obj.stats.languages
110 @admin.display(description=gettext_lazy("VCS repositories"))
111 def num_vcs(self, obj):
112 return obj.component_set.with_repo().count()
114 def get_qs_units(self, queryset):
115 return Unit.objects.filter(translation__component__project__in=queryset)
117 def get_qs_translations(self, queryset):
118 return Translation.objects.filter(component__project__in=queryset)
121@admin.register(Component)
122class ComponentAdmin(WeblateModelAdmin, RepoAdminMixin):
123 list_display = ("name", "slug", "project", "repo", "branch", "vcs", "file_format")
124 prepopulated_fields = { # noqa: RUF012
125 "slug": ("name",),
126 }
127 search_fields = ("name", "slug", "repo", "branch", "project__name", "project__slug")
128 list_filter = ("project", "vcs", "file_format")
129 actions = ("update_from_git", "update_checks", "force_commit")
130 ordering = ("project__name", "name")
132 def get_qs_units(self, queryset):
133 return Unit.objects.filter(translation__component__in=queryset)
135 def get_qs_translations(self, queryset):
136 return Translation.objects.filter(component__in=queryset)
138 def formfield_for_foreignkey(
139 self, db_field, request: AuthenticatedHttpRequest, **kwargs
140 ):
141 """Sort languages by localized names."""
142 result = super().formfield_for_foreignkey(db_field, request, **kwargs)
143 if db_field.name == "source_language":
144 result.choices = sort_choices(result.choices)
145 return result
148class TranslationAdmin(WeblateModelAdmin):
149 list_display = ("component", "language", "revision", "filename")
150 search_fields = ("component__name", "language__code", "revision", "filename")
151 list_filter = ("component__project", "component", "language")
154class UnitAdmin(WeblateModelAdmin):
155 list_display = ("source", "target", "position", "state")
156 search_fields = ("source", "target")
157 list_filter = ("translation__component", "translation__language", "state")
160class SuggestionAdmin(WeblateModelAdmin):
161 list_display = ("target", "unit", "user")
162 search_fields = ("unit__source", "target")
165class CommentAdmin(WeblateModelAdmin):
166 list_display = ("comment", "unit", "user")
167 search_fields = ("unit__source", "comment")
170class ChangeAdmin(WeblateModelAdmin):
171 list_display = ("unit", "user", "timestamp")
172 date_hierarchy = "timestamp"
173 list_filter = ("component", "project", "language")
174 raw_id_fields = ("unit",)
177@admin.register(Announcement)
178class AnnouncementAdmin(WeblateModelAdmin):
179 list_display = ("message", "project", "component", "language")
180 search_fields = ("message",)
181 list_filter = ("project", "language")
184class AutoComponentListAdmin(admin.TabularInline):
185 model = AutoComponentList
186 extra = 0
189@admin.register(ComponentList)
190class ComponentListAdmin(WeblateModelAdmin):
191 list_display = ("name", "show_dashboard")
192 list_filter = ("show_dashboard",)
193 prepopulated_fields = {"slug": ("name",)} # noqa: RUF012
194 autocomplete_fields = ("components",)
195 inlines = (AutoComponentListAdmin,)
196 ordering = ("name",)
199@admin.register(ContributorAgreement)
200class ContributorAgreementAdmin(WeblateModelAdmin):
201 list_display = ("user", "component", "timestamp")
202 date_hierarchy = "timestamp"
203 ordering = ("user__username", "component__project__name", "component__name")
206# Show some controls only in debug mode
207if settings.DEBUG: 207 ↛ 208line 207 didn't jump to line 208 because the condition on line 207 was never true
208 admin.site.register(Translation, TranslationAdmin)
209 admin.site.register(Unit, UnitAdmin)
210 admin.site.register(Suggestion, SuggestionAdmin)
211 admin.site.register(Comment, CommentAdmin)
212 admin.site.register(Change, ChangeAdmin)