We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Checking "Needs editing" on a translated entry trigger "Has been translated" warning 
**Describe the bug**

After an entry has been already translated (even if it's already marked as "Need editing"), if the translation is modified and the user adds (or keeps) the "Need editing" checked, it will trigger the warning "Has been translated".

I think it shouldn't trigger that warning at least, the message is misleading and in any case the report already marks the entry that needs editing as red.

**To Reproduce the bug**

1. Go to an entry for a component (.po in my case)
2. Translate for the first time the entry and click Save.
3. Go to that entry again, click on "Needs editing" and then Save.
4. The warning will appear.

**Expected behavior**

This specific warning shouldn't show every time a translation is made and Needs editing is there. It's not a warning and the user is already marking as needing some action.

**Additional context**

See also #2935


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `weblate/checks/consistency.py`
Content:
```
1 # Copyright © Michal Čihař <michal@weblate.org>
2 #
3 # SPDX-License-Identifier: GPL-3.0-or-later
4 
5 from functools import reduce
6 
7 from django.db.models import Count, Prefetch, Q
8 from django.utils.translation import gettext_lazy as _
9 
10 from weblate.checks.base import TargetCheck
11 from weblate.utils.state import STATE_TRANSLATED
12 
13 
14 class PluralsCheck(TargetCheck):
15     """Check for incomplete plural forms."""
16 
17     check_id = "plurals"
18     name = _("Missing plurals")
19     description = _("Some plural forms are untranslated")
20 
21     def should_skip(self, unit):
22         if unit.translation.component.is_multivalue:
23             return True
24         return super().should_skip(unit)
25 
26     def check_target_unit(self, sources, targets, unit):
27         # Is this plural?
28         if len(sources) == 1:
29             return False
30         # Is at least something translated?
31         if targets == len(targets) * [""]:
32             return False
33         # Check for empty translation
34         return "" in targets
35 
36     def check_single(self, source, target, unit):
37         """We don't check target strings here."""
38         return False
39 
40 
41 class SamePluralsCheck(TargetCheck):
42     """Check for same plural forms."""
43 
44     check_id = "same-plurals"
45     name = _("Same plurals")
46     description = _("Some plural forms are translated in the same way")
47 
48     def check_target_unit(self, sources, targets, unit):
49         # Is this plural?
50         if len(sources) == 1 or len(targets) == 1:
51             return False
52         if not targets[0]:
53             return False
54         return len(set(targets)) == 1
55 
56     def check_single(self, source, target, unit):
57         """We don't check target strings here."""
58         return False
59 
60 
61 class ConsistencyCheck(TargetCheck):
62     """Check for inconsistent translations."""
63 
64     check_id = "inconsistent"
65     name = _("Inconsistent")
66     description = _(
67         "This string has more than one translation in this project "
68         "or is untranslated in some components."
69     )
70     ignore_untranslated = False
71     propagates = True
72     batch_project_wide = True
73     skip_suggestions = True
74 
75     def check_target_unit(self, sources, targets, unit):
76         component = unit.translation.component
77         if not component.allow_translation_propagation:
78             return False
79 
80         # Use last result if checks are batched
81         if component.batch_checks:
82             return self.handle_batch(unit, component)
83 
84         for other in unit.same_source_units:
85             if unit.target == other.target:
86                 continue
87             if unit.translated or other.translated:
88                 return True
89         return False
90 
91     def check_single(self, source, target, unit):
92         """We don't check target strings here."""
93         return False
94 
95     def check_component(self, component):
96         from weblate.trans.models import Unit
97 
98         units = Unit.objects.filter(
99             translation__component__project=component.project,
100             translation__component__allow_translation_propagation=True,
101         )
102 
103         # List strings with different targets
104         # Limit this to 100 strings, otherwise the resulting query is way too complex
105         matches = (
106             units.values("id_hash", "translation__language", "translation__plural")
107             .annotate(Count("target", distinct=True))
108             .filter(target__count__gt=1)
109             .order_by("id_hash")[:100]
110         )
111 
112         if not matches:
113             return []
114 
115         return (
116             units.filter(
117                 reduce(
118                     lambda x, y: x
119                     | (
120                         Q(id_hash=y["id_hash"])
121                         & Q(translation__language=y["translation__language"])
122                         & Q(translation__plural=y["translation__plural"])
123                     ),
124                     matches,
125                     Q(),
126                 )
127             )
128             .prefetch()
129             .prefetch_bulk()
130         )
131 
132 
133 class TranslatedCheck(TargetCheck):
134     """Check for inconsistent translations."""
135 
136     check_id = "translated"
137     name = _("Has been translated")
138     description = _("This string has been translated in the past")
139     ignore_untranslated = False
140     skip_suggestions = True
141 
142     def get_description(self, check_obj):
143         unit = check_obj.unit
144         target = self.check_target_unit(unit.source, unit.target, unit)
145         if not target:
146             return super().get_description(check_obj)
147         return _('Previous translation was "%s".') % target
148 
149     def check_target_unit(self, sources, targets, unit):
150         if unit.translated:
151             return False
152 
153         component = unit.translation.component
154 
155         if component.batch_checks:
156             return self.handle_batch(unit, component)
157 
158         from weblate.trans.models import Change
159 
160         changes = unit.change_set.filter(action__in=Change.ACTIONS_CONTENT).order()
161 
162         for action, target in changes.values_list("action", "target"):
163             if action == Change.ACTION_SOURCE_CHANGE:
164                 break
165             if target and target != unit.target:
166                 return target
167 
168         return False
169 
170     def check_single(self, source, target, unit):
171         """We don't check target strings here."""
172         return False
173 
174     def get_fixup(self, unit):
175         target = self.check_target_unit(unit.source, unit.target, unit)
176         if not target:
177             return None
178         return [(".*", target, "u")]
179 
180     def check_component(self, component):
181         from weblate.trans.models import Change, Unit
182 
183         units = (
184             Unit.objects.filter(
185                 translation__component=component,
186                 change__action__in=Change.ACTIONS_CONTENT,
187                 state__lt=STATE_TRANSLATED,
188             )
189             .prefetch_related(
190                 Prefetch(
191                     "change_set",
192                     queryset=Change.objects.filter(
193                         action__in=Change.ACTIONS_CONTENT,
194                     ).order(),
195                     to_attr="recent_consistency_changes",
196                 )
197             )
198             .prefetch()
199             .prefetch_bulk()
200         )
201 
202         for unit in units:
203             for change in unit.recent_consistency_changes:
204                 if change.action == Change.ACTION_SOURCE_CHANGE:
205                     break
206                 if change.target:
207                     yield unit
208
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/weblate/checks/consistency.py b/weblate/checks/consistency.py
--- a/weblate/checks/consistency.py
+++ b/weblate/checks/consistency.py
@@ -146,6 +146,23 @@
             return super().get_description(check_obj)
         return _('Previous translation was "%s".') % target
 
+    def should_skip_change(self, change, unit):
+        from weblate.trans.models import Change
+
+        # Skip automatic translation entries adding needs editing string
+        return (
+            change.action == Change.ACTION_AUTO
+            and change.details.get("state", STATE_TRANSLATED) < STATE_TRANSLATED
+        )
+
+    @staticmethod
+    def should_break_changes(change):
+        from weblate.trans.models import Change
+
+        # Stop changes processin on source string change or on
+        # intentional marking as needing edit
+        return change.action in (Change.ACTION_SOURCE_CHANGE, Change.ACTION_MARKED_EDIT)
+
     def check_target_unit(self, sources, targets, unit):
         if unit.translated:
             return False
@@ -159,11 +176,13 @@
 
         changes = unit.change_set.filter(action__in=Change.ACTIONS_CONTENT).order()
 
-        for action, target in changes.values_list("action", "target"):
-            if action == Change.ACTION_SOURCE_CHANGE:
+        for change in changes:
+            if self.should_break_changes(change):
                 break
-            if target and target != unit.target:
-                return target
+            if self.should_skip_change(change, unit):
+                continue
+            if change.target and change.target != unit.target:
+                return change.target
 
         return False
 
@@ -201,7 +220,9 @@
 
         for unit in units:
             for change in unit.recent_consistency_changes:
-                if change.action == Change.ACTION_SOURCE_CHANGE:
+                if self.should_break_changes(change):
                     break
+                if self.should_skip_change(change, unit):
+                    continue
                 if change.target:
                     yield unit

{"golden_diff": "diff --git a/weblate/checks/consistency.py b/weblate/checks/consistency.py\n--- a/weblate/checks/consistency.py\n+++ b/weblate/checks/consistency.py\n@@ -146,6 +146,23 @@\n             return super().get_description(check_obj)\n         return _('Previous translation was \"%s\".') % target\n \n+    def should_skip_change(self, change, unit):\n+        from weblate.trans.models import Change\n+\n+        # Skip automatic translation entries adding needs editing string\n+        return (\n+            change.action == Change.ACTION_AUTO\n+            and change.details.get(\"state\", STATE_TRANSLATED) < STATE_TRANSLATED\n+        )\n+\n+    @staticmethod\n+    def should_break_changes(change):\n+        from weblate.trans.models import Change\n+\n+        # Stop changes processin on source string change or on\n+        # intentional marking as needing edit\n+        return change.action in (Change.ACTION_SOURCE_CHANGE, Change.ACTION_MARKED_EDIT)\n+\n     def check_target_unit(self, sources, targets, unit):\n         if unit.translated:\n             return False\n@@ -159,11 +176,13 @@\n \n         changes = unit.change_set.filter(action__in=Change.ACTIONS_CONTENT).order()\n \n-        for action, target in changes.values_list(\"action\", \"target\"):\n-            if action == Change.ACTION_SOURCE_CHANGE:\n+        for change in changes:\n+            if self.should_break_changes(change):\n                 break\n-            if target and target != unit.target:\n-                return target\n+            if self.should_skip_change(change, unit):\n+                continue\n+            if change.target and change.target != unit.target:\n+                return change.target\n \n         return False\n \n@@ -201,7 +220,9 @@\n \n         for unit in units:\n             for change in unit.recent_consistency_changes:\n-                if change.action == Change.ACTION_SOURCE_CHANGE:\n+                if self.should_break_changes(change):\n                     break\n+                if self.should_skip_change(change, unit):\n+                    continue\n                 if change.target:\n                     yield unit\n", "issue": "Checking \"Needs editing\" on a translated entry trigger \"Has been translated\" warning \n**Describe the bug**\r\n\r\nAfter an entry has been already translated (even if it's already marked as \"Need editing\"), if the translation is modified and the user adds (or keeps) the \"Need editing\" checked, it will trigger the warning \"Has been translated\".\r\n\r\nI think it shouldn't trigger that warning at least, the message is misleading and in any case the report already marks the entry that needs editing as red.\r\n\r\n**To Reproduce the bug**\r\n\r\n1. Go to an entry for a component (.po in my case)\r\n2. Translate for the first time the entry and click Save.\r\n3. Go to that entry again, click on \"Needs editing\" and then Save.\r\n4. The warning will appear.\r\n\r\n**Expected behavior**\r\n\r\nThis specific warning shouldn't show every time a translation is made and Needs editing is there. It's not a warning and the user is already marking as needing some action.\r\n\r\n**Additional context**\r\n\r\nSee also #2935\r\n\n", "before_files": [{"content": "# Copyright \u00a9 Michal \u010ciha\u0159 <michal@weblate.org>\n#\n# SPDX-License-Identifier: GPL-3.0-or-later\n\nfrom functools import reduce\n\nfrom django.db.models import Count, Prefetch, Q\nfrom django.utils.translation import gettext_lazy as _\n\nfrom weblate.checks.base import TargetCheck\nfrom weblate.utils.state import STATE_TRANSLATED\n\n\nclass PluralsCheck(TargetCheck):\n    \"\"\"Check for incomplete plural forms.\"\"\"\n\n    check_id = \"plurals\"\n    name = _(\"Missing plurals\")\n    description = _(\"Some plural forms are untranslated\")\n\n    def should_skip(self, unit):\n        if unit.translation.component.is_multivalue:\n            return True\n        return super().should_skip(unit)\n\n    def check_target_unit(self, sources, targets, unit):\n        # Is this plural?\n        if len(sources) == 1:\n            return False\n        # Is at least something translated?\n        if targets == len(targets) * [\"\"]:\n            return False\n        # Check for empty translation\n        return \"\" in targets\n\n    def check_single(self, source, target, unit):\n        \"\"\"We don't check target strings here.\"\"\"\n        return False\n\n\nclass SamePluralsCheck(TargetCheck):\n    \"\"\"Check for same plural forms.\"\"\"\n\n    check_id = \"same-plurals\"\n    name = _(\"Same plurals\")\n    description = _(\"Some plural forms are translated in the same way\")\n\n    def check_target_unit(self, sources, targets, unit):\n        # Is this plural?\n        if len(sources) == 1 or len(targets) == 1:\n            return False\n        if not targets[0]:\n            return False\n        return len(set(targets)) == 1\n\n    def check_single(self, source, target, unit):\n        \"\"\"We don't check target strings here.\"\"\"\n        return False\n\n\nclass ConsistencyCheck(TargetCheck):\n    \"\"\"Check for inconsistent translations.\"\"\"\n\n    check_id = \"inconsistent\"\n    name = _(\"Inconsistent\")\n    description = _(\n        \"This string has more than one translation in this project \"\n        \"or is untranslated in some components.\"\n    )\n    ignore_untranslated = False\n    propagates = True\n    batch_project_wide = True\n    skip_suggestions = True\n\n    def check_target_unit(self, sources, targets, unit):\n        component = unit.translation.component\n        if not component.allow_translation_propagation:\n            return False\n\n        # Use last result if checks are batched\n        if component.batch_checks:\n            return self.handle_batch(unit, component)\n\n        for other in unit.same_source_units:\n            if unit.target == other.target:\n                continue\n            if unit.translated or other.translated:\n                return True\n        return False\n\n    def check_single(self, source, target, unit):\n        \"\"\"We don't check target strings here.\"\"\"\n        return False\n\n    def check_component(self, component):\n        from weblate.trans.models import Unit\n\n        units = Unit.objects.filter(\n            translation__component__project=component.project,\n            translation__component__allow_translation_propagation=True,\n        )\n\n        # List strings with different targets\n        # Limit this to 100 strings, otherwise the resulting query is way too complex\n        matches = (\n            units.values(\"id_hash\", \"translation__language\", \"translation__plural\")\n            .annotate(Count(\"target\", distinct=True))\n            .filter(target__count__gt=1)\n            .order_by(\"id_hash\")[:100]\n        )\n\n        if not matches:\n            return []\n\n        return (\n            units.filter(\n                reduce(\n                    lambda x, y: x\n                    | (\n                        Q(id_hash=y[\"id_hash\"])\n                        & Q(translation__language=y[\"translation__language\"])\n                        & Q(translation__plural=y[\"translation__plural\"])\n                    ),\n                    matches,\n                    Q(),\n                )\n            )\n            .prefetch()\n            .prefetch_bulk()\n        )\n\n\nclass TranslatedCheck(TargetCheck):\n    \"\"\"Check for inconsistent translations.\"\"\"\n\n    check_id = \"translated\"\n    name = _(\"Has been translated\")\n    description = _(\"This string has been translated in the past\")\n    ignore_untranslated = False\n    skip_suggestions = True\n\n    def get_description(self, check_obj):\n        unit = check_obj.unit\n        target = self.check_target_unit(unit.source, unit.target, unit)\n        if not target:\n            return super().get_description(check_obj)\n        return _('Previous translation was \"%s\".') % target\n\n    def check_target_unit(self, sources, targets, unit):\n        if unit.translated:\n            return False\n\n        component = unit.translation.component\n\n        if component.batch_checks:\n            return self.handle_batch(unit, component)\n\n        from weblate.trans.models import Change\n\n        changes = unit.change_set.filter(action__in=Change.ACTIONS_CONTENT).order()\n\n        for action, target in changes.values_list(\"action\", \"target\"):\n            if action == Change.ACTION_SOURCE_CHANGE:\n                break\n            if target and target != unit.target:\n                return target\n\n        return False\n\n    def check_single(self, source, target, unit):\n        \"\"\"We don't check target strings here.\"\"\"\n        return False\n\n    def get_fixup(self, unit):\n        target = self.check_target_unit(unit.source, unit.target, unit)\n        if not target:\n            return None\n        return [(\".*\", target, \"u\")]\n\n    def check_component(self, component):\n        from weblate.trans.models import Change, Unit\n\n        units = (\n            Unit.objects.filter(\n                translation__component=component,\n                change__action__in=Change.ACTIONS_CONTENT,\n                state__lt=STATE_TRANSLATED,\n            )\n            .prefetch_related(\n                Prefetch(\n                    \"change_set\",\n                    queryset=Change.objects.filter(\n                        action__in=Change.ACTIONS_CONTENT,\n                    ).order(),\n                    to_attr=\"recent_consistency_changes\",\n                )\n            )\n            .prefetch()\n            .prefetch_bulk()\n        )\n\n        for unit in units:\n            for change in unit.recent_consistency_changes:\n                if change.action == Change.ACTION_SOURCE_CHANGE:\n                    break\n                if change.target:\n                    yield unit\n", "path": "weblate/checks/consistency.py"}], "after_files": [{"content": "# Copyright \u00a9 Michal \u010ciha\u0159 <michal@weblate.org>\n#\n# SPDX-License-Identifier: GPL-3.0-or-later\n\nfrom functools import reduce\n\nfrom django.db.models import Count, Prefetch, Q\nfrom django.utils.translation import gettext_lazy as _\n\nfrom weblate.checks.base import TargetCheck\nfrom weblate.utils.state import STATE_TRANSLATED\n\n\nclass PluralsCheck(TargetCheck):\n    \"\"\"Check for incomplete plural forms.\"\"\"\n\n    check_id = \"plurals\"\n    name = _(\"Missing plurals\")\n    description = _(\"Some plural forms are untranslated\")\n\n    def should_skip(self, unit):\n        if unit.translation.component.is_multivalue:\n            return True\n        return super().should_skip(unit)\n\n    def check_target_unit(self, sources, targets, unit):\n        # Is this plural?\n        if len(sources) == 1:\n            return False\n        # Is at least something translated?\n        if targets == len(targets) * [\"\"]:\n            return False\n        # Check for empty translation\n        return \"\" in targets\n\n    def check_single(self, source, target, unit):\n        \"\"\"We don't check target strings here.\"\"\"\n        return False\n\n\nclass SamePluralsCheck(TargetCheck):\n    \"\"\"Check for same plural forms.\"\"\"\n\n    check_id = \"same-plurals\"\n    name = _(\"Same plurals\")\n    description = _(\"Some plural forms are translated in the same way\")\n\n    def check_target_unit(self, sources, targets, unit):\n        # Is this plural?\n        if len(sources) == 1 or len(targets) == 1:\n            return False\n        if not targets[0]:\n            return False\n        return len(set(targets)) == 1\n\n    def check_single(self, source, target, unit):\n        \"\"\"We don't check target strings here.\"\"\"\n        return False\n\n\nclass ConsistencyCheck(TargetCheck):\n    \"\"\"Check for inconsistent translations.\"\"\"\n\n    check_id = \"inconsistent\"\n    name = _(\"Inconsistent\")\n    description = _(\n        \"This string has more than one translation in this project \"\n        \"or is untranslated in some components.\"\n    )\n    ignore_untranslated = False\n    propagates = True\n    batch_project_wide = True\n    skip_suggestions = True\n\n    def check_target_unit(self, sources, targets, unit):\n        component = unit.translation.component\n        if not component.allow_translation_propagation:\n            return False\n\n        # Use last result if checks are batched\n        if component.batch_checks:\n            return self.handle_batch(unit, component)\n\n        for other in unit.same_source_units:\n            if unit.target == other.target:\n                continue\n            if unit.translated or other.translated:\n                return True\n        return False\n\n    def check_single(self, source, target, unit):\n        \"\"\"We don't check target strings here.\"\"\"\n        return False\n\n    def check_component(self, component):\n        from weblate.trans.models import Unit\n\n        units = Unit.objects.filter(\n            translation__component__project=component.project,\n            translation__component__allow_translation_propagation=True,\n        )\n\n        # List strings with different targets\n        # Limit this to 100 strings, otherwise the resulting query is way too complex\n        matches = (\n            units.values(\"id_hash\", \"translation__language\", \"translation__plural\")\n            .annotate(Count(\"target\", distinct=True))\n            .filter(target__count__gt=1)\n            .order_by(\"id_hash\")[:100]\n        )\n\n        if not matches:\n            return []\n\n        return (\n            units.filter(\n                reduce(\n                    lambda x, y: x\n                    | (\n                        Q(id_hash=y[\"id_hash\"])\n                        & Q(translation__language=y[\"translation__language\"])\n                        & Q(translation__plural=y[\"translation__plural\"])\n                    ),\n                    matches,\n                    Q(),\n                )\n            )\n            .prefetch()\n            .prefetch_bulk()\n        )\n\n\nclass TranslatedCheck(TargetCheck):\n    \"\"\"Check for inconsistent translations.\"\"\"\n\n    check_id = \"translated\"\n    name = _(\"Has been translated\")\n    description = _(\"This string has been translated in the past\")\n    ignore_untranslated = False\n    skip_suggestions = True\n\n    def get_description(self, check_obj):\n        unit = check_obj.unit\n        target = self.check_target_unit(unit.source, unit.target, unit)\n        if not target:\n            return super().get_description(check_obj)\n        return _('Previous translation was \"%s\".') % target\n\n    def should_skip_change(self, change, unit):\n        from weblate.trans.models import Change\n\n        # Skip automatic translation entries adding needs editing string\n        return (\n            change.action == Change.ACTION_AUTO\n            and change.details.get(\"state\", STATE_TRANSLATED) < STATE_TRANSLATED\n        )\n\n    @staticmethod\n    def should_break_changes(change):\n        from weblate.trans.models import Change\n\n        # Stop changes processin on source string change or on\n        # intentional marking as needing edit\n        return change.action in (Change.ACTION_SOURCE_CHANGE, Change.ACTION_MARKED_EDIT)\n\n    def check_target_unit(self, sources, targets, unit):\n        if unit.translated:\n            return False\n\n        component = unit.translation.component\n\n        if component.batch_checks:\n            return self.handle_batch(unit, component)\n\n        from weblate.trans.models import Change\n\n        changes = unit.change_set.filter(action__in=Change.ACTIONS_CONTENT).order()\n\n        for change in changes:\n            if self.should_break_changes(change):\n                break\n            if self.should_skip_change(change, unit):\n                continue\n            if change.target and change.target != unit.target:\n                return change.target\n\n        return False\n\n    def check_single(self, source, target, unit):\n        \"\"\"We don't check target strings here.\"\"\"\n        return False\n\n    def get_fixup(self, unit):\n        target = self.check_target_unit(unit.source, unit.target, unit)\n        if not target:\n            return None\n        return [(\".*\", target, \"u\")]\n\n    def check_component(self, component):\n        from weblate.trans.models import Change, Unit\n\n        units = (\n            Unit.objects.filter(\n                translation__component=component,\n                change__action__in=Change.ACTIONS_CONTENT,\n                state__lt=STATE_TRANSLATED,\n            )\n            .prefetch_related(\n                Prefetch(\n                    \"change_set\",\n                    queryset=Change.objects.filter(\n                        action__in=Change.ACTIONS_CONTENT,\n                    ).order(),\n                    to_attr=\"recent_consistency_changes\",\n                )\n            )\n            .prefetch()\n            .prefetch_bulk()\n        )\n\n        for unit in units:\n            for change in unit.recent_consistency_changes:\n                if self.should_break_changes(change):\n                    break\n                if self.should_skip_change(change, unit):\n                    continue\n                if change.target:\n                    yield unit\n", "path": "weblate/checks/consistency.py"}]}