Repository: WeblateOrg/weblate

Issue:
Source strings needing work locks all translations
### Describe the issue

If for whatever reason the source string is marked as needing work,
it means all translations thereof are locked.

This means no other issues in the translate to-languages can be fixed meanwhile.

### I already tried

- [X] I've read and searched [the documentation](https://docs.weblate.org/).
- [X] I've searched for similar filed issues in this repository.

### Steps to reproduce the behavior

0. (Source string is marked as needing work.)
1. https://hosted.weblate.org/translate/hedy/web-texts/nb_NO/?checksum=1636e86e15277e57
2. Can't edit in nb_NO

### Expected behavior

Would expect all translatable strings to be editable.

### Screenshots

![bilde](https://github.com/WeblateOrg/weblate/assets/13802408/8b5ed2e0-cf1f-48db-bbbc-8925c6d2c1f0)

Here it should be "E-post-oppsettsveiviser"
### Exception traceback

_No response_

### How do you run Weblate?

weblate.org service

### Weblate versions

_No response_

### Weblate deploy checks

_No response_

### Additional context
Also, https://hosted.weblate.org/translate/ubports/app-dekko/nb_NO/?checksum=40f7a65819757880

As a rule I want to correct the mistakes of others and myself when I am able to, and not on the assumption that
the source string is always the issue.

As long as the string is used, it at least removes insult from injury.
It is better to have a correctly typed string rather than one that is wrong _and_ badly mistyped.
If that removes the "needs work" in the translated to-language, it is a problem with having one
checkbox.

Just the one checkbox creates similar issues when there is assumptions made over what the original error was, and its correction.

I think having it editable now, and then also possibly notifying all people adding "needs work" that their issue was attemptedly fixed is a good quickfix.


Discussion:
This is intentional, if somebody is going to rewrite the source string, the translations will need to be fixed after that anyway.
**Mistakes in source strings don't always propagate to the translation** though.
Similarly, it is **possible the string just needs _an_ improvement**, that isn't obvious to anyone.
Moreover, it **can also be that the fix is obvious**.

Lets say the source string is "Url" when it should have been "URL". (It happens X)

Someone could fix that in their own language, and logically go to the source string to mark it as needing work.
Except it isn't at all explained that this locks the string for everyone else.
So someone else can come and toggle the source string needing work only to be able to fix it in their own language.
This sends more e-mails to the admins than they strictly need.

Or fix it in all translated languages, and then mark as needing work for the source? That locks all new languages.

So what problems are buried here?
I have thousands and thousands of strings marked as needing work in nb_NO when the problem exists in the source string for this reason.
Now it is functionality I rely on others not undoing for actual nb_NO mistakes, when I use it for even other things.

Does the platform want to facilitate quality, or try to minimize the amount of actual work done?

From my point of view **I want to fix things when I am there**, not down the road.

I'd rather take the marked as fuzzy after an update when the string is correct for the user.
You get that more often with non-locking.
This was originally introduced for #3270. It might make sense to limit this to the workflow with intermediate translation only.
This issue has been automatically marked as stale because there wasn’t any recent activity.

It will be closed soon if no further action occurs.

Thank you for your contributions!

Resolving patch:
diff --git a/weblate/trans/models/unit.py b/weblate/trans/models/unit.py
--- a/weblate/trans/models/unit.py
+++ b/weblate/trans/models/unit.py
@@ -659,7 +659,11 @@ def get_unit_state(self, unit, flags: str, string_changed: bool = False):
 
         if flags is not None:
             # Read only from the source
-            if not self.is_source and self.source_unit.state < STATE_TRANSLATED:
+            if (
+                not self.is_source
+                and self.source_unit.state < STATE_TRANSLATED
+                and self.translation.component.intermediate
+            ):
                 return STATE_READONLY
 
             # Read only from flags
@@ -928,7 +932,9 @@ def update_state(self) -> None:
         * Where source string is untranslated
         """
         if "read-only" in self.all_flags or (
-            not self.is_source and self.source_unit.state < STATE_TRANSLATED
+            not self.is_source
+            and self.source_unit.state < STATE_TRANSLATED
+            and self.translation.component.intermediate
         ):
             if not self.readonly:
                 self.original_state = self.state


Test patch:
diff --git a/weblate/trans/tests/test_edit.py b/weblate/trans/tests/test_edit.py
--- a/weblate/trans/tests/test_edit.py
+++ b/weblate/trans/tests/test_edit.py
@@ -16,7 +16,7 @@
 from weblate.trans.tests.test_views import ViewTestCase
 from weblate.trans.util import join_plural
 from weblate.utils.hash import hash_to_checksum
-from weblate.utils.state import STATE_FUZZY, STATE_READONLY, STATE_TRANSLATED
+from weblate.utils.state import STATE_FUZZY, STATE_TRANSLATED
 
 
 class EditTest(ViewTestCase):
@@ -366,12 +366,12 @@ def test_needs_edit(self) -> None:
         # Change state
         self.edit_unit("Hello, world!\n", "Hello, world!\n", "en", fuzzy="yes")
         unit = translation.unit_set.get(context="hello")
-        self.assertEqual(unit.state, STATE_READONLY)
+        self.assertEqual(unit.state, STATE_TRANSLATED)
 
         # Change state and source
         self.edit_unit("Hello, world!\n", "Hello, universe!\n", "en", fuzzy="yes")
         unit = translation.unit_set.get(context="hello")
-        self.assertEqual(unit.state, STATE_READONLY)
+        self.assertEqual(unit.state, STATE_FUZZY)
 
         # Change state and source
         self.edit_unit("Hello, universe!\n", "Hello, universe!\n", "en")
diff --git a/weblate/trans/tests/test_search.py b/weblate/trans/tests/test_search.py
--- a/weblate/trans/tests/test_search.py
+++ b/weblate/trans/tests/test_search.py
@@ -444,8 +444,8 @@ def test_source_state(self) -> None:
             url, {"q": "language:en", "state": STATE_FUZZY}, follow=True
         )
         self.assertContains(response, "Bulk edit completed, 4 strings were updated.")
-        self.assertEqual(translation.unit_set.filter(state=STATE_READONLY).count(), 4)
-        self.assertEqual(translation.unit_set.filter(state=STATE_TRANSLATED).count(), 0)
+        self.assertEqual(translation.unit_set.filter(state=STATE_READONLY).count(), 0)
+        self.assertEqual(translation.unit_set.filter(state=STATE_TRANSLATED).count(), 1)
 
         # Mark all source strings as needing edit and that should turn all
         # translated strings back to translated