Repository: WeblateOrg/weblate

Issue:
Stay in the translate view when there are no search results
### Describe the problem

It is very common usecase to search for various strings in the translation. I want to search for a string, check the results and then search for a different string. However the current implementation takes user to component overview page when there are no strings found which does not have search bar - i.e. user loses his/her context, has to go back and potentially fill search parameters again (advanced filter and sort options).

### Describe the solution you'd like

I would love for Weblate to stay on the translate page with the message "No strings found!". This will probably mean that the view has to be able to display without any translation unit available (i.e. don't show anything other than empty pagination, search bar with the filter and sort options).

### Describe alternatives you've considered

Alternative solution (maybe easier and cleaner to implement) would be to end up on the search page with the "No strings found!" message. The end goal is to **preserve and display** used search parameters.

### Screenshots

About to search for "foobar":

![image](https://github.com/WeblateOrg/weblate/assets/2012726/dddeaa3f-6e59-42aa-b595-ca1b4e2a9253)

No strings and my search parameters are lost (query and sorting):

![image](https://github.com/WeblateOrg/weblate/assets/2012726/26ef9e80-cc1e-4ef9-9744-b58cfc15f423)

If I now want to go search for "barbaz" instead, I have to go back. Much better solution would be to either stay on the translate page or on the search page with prefilled query/sorting that was used:

![image](https://github.com/WeblateOrg/weblate/assets/2012726/95267a16-cd9c-44ea-a255-0e5836e469bb)



### Additional context

_No response_


Discussion:
I have just discovered (should have checked first) that the search page behaves differently in the sense that it has dedicated results page which can show "empty results". So I am not sure how much valid is my feature request in that sense.

Update: Ah... the search page behaves differently when you are in the language context or in the component context. That is not very intuitive.

Resolving patch:
diff --git a/weblate/trans/views/edit.py b/weblate/trans/views/edit.py
--- a/weblate/trans/views/edit.py
+++ b/weblate/trans/views/edit.py
@@ -266,7 +266,7 @@ def search(
         # Check empty search results
         if not unit_ids and not blank:
             messages.warning(request, gettext("No strings found!"))
-            return redirect(base)
+            return redirect(f"{base.get_absolute_url()}#search")
 
         store_result = {
             "query": search_query,


Test patch:
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
@@ -25,13 +25,15 @@ def setUp(self):
         self.update_fulltext_index()
         reset_rate_limit("search", address="127.0.0.1")
 
-    def do_search(self, params, expected, url=None):
+    def do_search(self, params, expected, url=None, *, anchor="#search"):
         """Helper method for performing search test."""
         if url is None:
             url = self.translate_url
         response = self.client.get(url, params)
         if expected is None:
-            self.assertRedirects(response, self.translation.get_absolute_url())
+            self.assertRedirects(
+                response, f"{self.translation.get_absolute_url()}{anchor}"
+            )
         else:
             self.assertContains(response, expected)
         return response
@@ -149,7 +151,7 @@ def test_search_offset(self):
         """Test offset navigation."""
         self.do_search({"offset": 1}, "1 / 4")
         self.do_search({"offset": 4}, "4 / 4")
-        self.do_search({"offset": 5}, None)
+        self.do_search({"offset": 5}, None, anchor="")
 
     def test_search_type(self):
         self.do_search({"q": "state:<translated"}, "Unfinished strings")
@@ -167,7 +169,7 @@ def test_search_plural(self):
         self.assertNotContains(response, "Plural form ")
 
     def test_checksum(self):
-        self.do_search({"checksum": "invalid"}, None)
+        self.do_search({"checksum": "invalid"}, None, anchor="")
 
 
 class ReplaceTest(ViewTestCase):