Coverage for app/venv/lib/python3.14/site-packages/weblate/addons/flags.py: 64%
62 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, ClassVar
9from django.utils.translation import gettext_lazy
11from weblate.addons.base import BaseAddon
12from weblate.addons.events import AddonEvent
13from weblate.addons.forms import BulkEditAddonForm
14from weblate.trans.bulk import bulk_perform
15from weblate.trans.models import Unit
16from weblate.utils.state import STATE_FUZZY, STATE_TRANSLATED
18if TYPE_CHECKING: 18 ↛ 19line 18 didn't jump to line 19 because the condition on line 18 was never true
19 from weblate.addons.base import CompatDict
20 from weblate.auth.models import User
21 from weblate.trans.models import Component
24class FlagBase(BaseAddon):
25 events: ClassVar[set[AddonEvent]] = {
26 AddonEvent.EVENT_UNIT_PRE_CREATE,
27 }
28 icon = "flag.svg"
30 @classmethod
31 def can_install(cls, component: Component, user: User | None) -> bool:
32 # Following formats support fuzzy flag, so avoid messing up with them
33 if component.file_format in {"ts", "po", "po-mono"}:
34 return False
35 return super().can_install(component, user)
38class SourceEditAddon(FlagBase):
39 name = "weblate.flags.source_edit"
40 verbose = gettext_lazy('Flag new source strings as "Needs editing"')
41 description = gettext_lazy(
42 "Whenever a new source string is imported from the VCS, it is "
43 "flagged as needing editing in Weblate. This way you can easily "
44 "filter and edit source strings written by the developers."
45 )
46 compat: ClassVar[CompatDict] = {
47 "edit_template": {True},
48 }
50 def unit_pre_create(self, unit: Unit, activity_log_id: int | None = None) -> None:
51 if (
52 unit.translation.is_template
53 and unit.state >= STATE_TRANSLATED
54 and not unit.readonly
55 ):
56 unit.state = STATE_FUZZY
59class TargetEditAddon(FlagBase):
60 name = "weblate.flags.target_edit"
61 verbose = gettext_lazy('Flag new translations as "Needs editing"')
62 description = gettext_lazy(
63 "Whenever a new translatable string is imported from the VCS, it is "
64 "flagged as needing editing in Weblate. This way you can easily "
65 "filter and edit translations created by the developers."
66 )
68 def unit_pre_create(self, unit: Unit, activity_log_id: int | None = None) -> None:
69 if (
70 not unit.translation.is_template
71 and unit.state >= STATE_TRANSLATED
72 and not unit.readonly
73 ):
74 unit.state = STATE_FUZZY
77class SameEditAddon(FlagBase):
78 name = "weblate.flags.same_edit"
79 verbose = gettext_lazy('Flag unchanged translations as "Needs editing"')
80 description = gettext_lazy(
81 "Whenever a new translatable string is imported from the VCS and it matches a "
82 "source string, it is flagged as needing editing in Weblate. Especially "
83 "useful for file formats that include source strings for untranslated strings."
84 )
86 def unit_pre_create(self, unit: Unit, activity_log_id: int | None = None) -> None:
87 if (
88 not unit.translation.is_template
89 and unit.source == unit.target
90 and "ignore-same" not in unit.all_flags
91 and unit.state >= STATE_TRANSLATED
92 and not unit.readonly
93 ):
94 unit.state = STATE_FUZZY
97class BulkEditAddon(BaseAddon):
98 events: ClassVar[set[AddonEvent]] = {
99 AddonEvent.EVENT_COMPONENT_UPDATE,
100 }
101 name = "weblate.flags.bulk"
102 verbose = gettext_lazy("Bulk edit")
103 description = gettext_lazy("Bulk edit flags, labels, or states of strings.")
104 settings_form = BulkEditAddonForm
105 multiple = True
107 def component_update(
108 self, component: Component, activity_log_id: int | None = None
109 ) -> None:
110 label_set = component.project.label_set
111 bulk_perform(
112 None,
113 Unit.objects.filter(translation__component=component),
114 components=[component],
115 query=self.instance.configuration["q"],
116 target_state=self.instance.configuration["state"],
117 add_flags=self.instance.configuration["add_flags"],
118 remove_flags=self.instance.configuration["remove_flags"],
119 add_labels=label_set.filter(
120 name__in=self.instance.configuration["add_labels"]
121 ),
122 remove_labels=label_set.filter(
123 name__in=self.instance.configuration["remove_labels"]
124 ),
125 project=component.project,
126 )
129class TargetRepoUpdateAddon(BaseAddon):
130 events: ClassVar[set[AddonEvent]] = {AddonEvent.EVENT_UNIT_POST_SYNC}
131 icon = "flag.svg"
132 name = "weblate.flags.target_repo_update"
133 verbose = gettext_lazy(
134 'Flag updated translations from repository as "Needs editing"'
135 )
136 description = gettext_lazy(
137 "Whenever a string translation is changed from the VCS, "
138 "it is flagged as needing editing in Weblate. Especially useful if "
139 "translation files are often updated manually or by an external service."
140 )
142 def unit_post_sync(self, unit: Unit, changed_attr: str, **kwargs) -> None:
143 if changed_attr == "target":
144 unit.state = STATE_FUZZY