Repository: WeblateOrg/weblate

Issue:
Highlight search match in results
It is difficult to spot matching words in case string is too long, so the matched phrase should be highlighted.

* Right now only full search phrase is highlighted even though it is searched by words.
* The highlighter does not understand the search syntax, so it looks for `source:literal` in all strings instead of looking for `literal` in the source string.



Discussion:

Resolving patch:
diff --git a/trans/templatetags/translations.py b/trans/templatetags/translations.py
--- a/trans/templatetags/translations.py
+++ b/trans/templatetags/translations.py
@@ -70,7 +70,7 @@ def fmt_whitespace(value):
 
 @register.filter
 @stringfilter
-def fmttranslation(value, language=None, diff=None):
+def fmttranslation(value, language=None, diff=None, search_match=None):
     '''
     Formats translation to show whitespace, plural forms or diff.
     '''
@@ -101,6 +101,19 @@ def fmttranslation(value, language=None, diff=None):
             diffvalue = escape(force_unicode(diff[idx]))
             value = html_diff(diffvalue, value)
 
+        # Format search term
+        if search_match is not None:
+            # Since the search ignored case, we need to highlight any
+            # combination of upper and lower case we find. This is too
+            # advanced for str.replace().
+            caseless = re.compile(re.escape(search_match), re.IGNORECASE)
+            for variation in re.findall(caseless, value):
+                value = re.sub(
+                    caseless,
+                    '<span class="hlmatch">%s</span>' % (variation),
+                    value,
+                )
+
         # Normalize newlines
         value = NEWLINES_RE.sub('\n', value)
 
@@ -143,6 +156,15 @@ def fmttranslationdiff(value, other):
     return fmttranslation(value, other.translation.language, other.target)
 
 
+@register.filter
+@stringfilter
+def fmtsearchmatch(value, term):
+    '''
+    Formats terms matching a search query.
+    '''
+    return fmttranslation(value, search_match=term)
+
+
 @register.filter
 @stringfilter
 def fmtsourcediff(value, other):
diff --git a/trans/views/edit.py b/trans/views/edit.py
--- a/trans/views/edit.py
+++ b/trans/views/edit.py
@@ -103,6 +103,7 @@ def search(translation, request):
     search_form = SearchForm(request.GET)
     review_form = ReviewForm(request.GET)
 
+    search_query = None
     if review_form.is_valid():
         # Review
         allunits = translation.unit_set.review(
@@ -125,9 +126,10 @@ def search(translation, request):
             search_form.cleaned_data['tgt'],
         )
 
+        search_query = search_form.cleaned_data['q']
         name = get_search_name(
             search_form.cleaned_data['search'],
-            search_form.cleaned_data['q'],
+            search_query,
         )
     else:
         # Filtering by type
@@ -159,6 +161,7 @@ def search(translation, request):
     # Store in cache and return
     search_id = str(uuid.uuid1())
     search_result = {
+        'query': search_query,
         'name': name,
         'ids': unit_ids,
         'search_id': search_id,
@@ -466,6 +469,7 @@ def translate(request, project, subproject, lang):
                 'last_changes_url': urlencode(obj.get_kwargs()),
                 'total': obj.unit_set.all().count(),
                 'search_id': search_result['search_id'],
+                'search_query': search_result['query'],
                 'offset': offset,
                 'filter_name': search_result['name'],
                 'filter_count': num_results,


Test patch: