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

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, ClassVar 

8 

9from django.utils.translation import gettext_lazy 

10 

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 

17 

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 

22 

23 

24class FlagBase(BaseAddon): 

25 events: ClassVar[set[AddonEvent]] = { 

26 AddonEvent.EVENT_UNIT_PRE_CREATE, 

27 } 

28 icon = "flag.svg" 

29 

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) 

36 

37 

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 } 

49 

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 

57 

58 

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 ) 

67 

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 

75 

76 

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 ) 

85 

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 

95 

96 

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 

106 

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 ) 

127 

128 

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 ) 

141 

142 def unit_post_sync(self, unit: Unit, changed_attr: str, **kwargs) -> None: 

143 if changed_attr == "target": 

144 unit.state = STATE_FUZZY