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

1# Copyright © Michal Čihař <michal@weblate.org> 

2# 

3# SPDX-License-Identifier: GPL-3.0-or-later 

4 

5from __future__ import annotations 

6 

7from typing import TYPE_CHECKING, NoReturn 

8 

9from django.conf import settings 

10from django.contrib import admin 

11from django.utils.translation import gettext_lazy 

12 

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 

30 

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 

33 

34 

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 ) 

44 

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.") 

51 

52 def get_qs_units(self, queryset) -> NoReturn: 

53 raise NotImplementedError 

54 

55 def get_qs_translations(self, queryset) -> NoReturn: 

56 raise NotImplementedError 

57 

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() 

64 

65 for translation in self.get_qs_translations(queryset): 

66 translation.invalidate_cache() 

67 

68 self.message_user(request, f"Updated checks for {len(units):d} units.") 

69 

70 

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") 

90 

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 ) 

96 

97 @admin.display(description=gettext_lazy("Source strings")) 

98 def get_total(self, obj): 

99 return obj.stats.source_strings 

100 

101 @admin.display(description=gettext_lazy("Source words")) 

102 def get_source_words(self, obj): 

103 return obj.stats.source_words 

104 

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 

109 

110 @admin.display(description=gettext_lazy("VCS repositories")) 

111 def num_vcs(self, obj): 

112 return obj.component_set.with_repo().count() 

113 

114 def get_qs_units(self, queryset): 

115 return Unit.objects.filter(translation__component__project__in=queryset) 

116 

117 def get_qs_translations(self, queryset): 

118 return Translation.objects.filter(component__project__in=queryset) 

119 

120 

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") 

131 

132 def get_qs_units(self, queryset): 

133 return Unit.objects.filter(translation__component__in=queryset) 

134 

135 def get_qs_translations(self, queryset): 

136 return Translation.objects.filter(component__in=queryset) 

137 

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 

146 

147 

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") 

152 

153 

154class UnitAdmin(WeblateModelAdmin): 

155 list_display = ("source", "target", "position", "state") 

156 search_fields = ("source", "target") 

157 list_filter = ("translation__component", "translation__language", "state") 

158 

159 

160class SuggestionAdmin(WeblateModelAdmin): 

161 list_display = ("target", "unit", "user") 

162 search_fields = ("unit__source", "target") 

163 

164 

165class CommentAdmin(WeblateModelAdmin): 

166 list_display = ("comment", "unit", "user") 

167 search_fields = ("unit__source", "comment") 

168 

169 

170class ChangeAdmin(WeblateModelAdmin): 

171 list_display = ("unit", "user", "timestamp") 

172 date_hierarchy = "timestamp" 

173 list_filter = ("component", "project", "language") 

174 raw_id_fields = ("unit",) 

175 

176 

177@admin.register(Announcement) 

178class AnnouncementAdmin(WeblateModelAdmin): 

179 list_display = ("message", "project", "component", "language") 

180 search_fields = ("message",) 

181 list_filter = ("project", "language") 

182 

183 

184class AutoComponentListAdmin(admin.TabularInline): 

185 model = AutoComponentList 

186 extra = 0 

187 

188 

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",) 

197 

198 

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") 

204 

205 

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)