Repository: WeblateOrg/weblate

Issue:
Improved presentation of differences in machine translations
**Is your feature request related to a problem? Please describe.**
When Weblate gives me suggestions for machine translations there is an indication on how similar the source string is to the one I'm translating. Unless the string is short, it can require a close read to discover exactly what the differences are.

**Describe the solution you'd like**
If the differences were highlighted, for example similarly to how a message that has been changed is marked with red and green sections, it would be immediately obvious what the differences were. Then I could more quickly make the necessary adjustments to the translated string.


Discussion:
<img width="1272" alt="Zrzut ekranu 2022-07-21 o 00 22 02" src="https://user-images.githubusercontent.com/9288014/180092618-9c4d400e-d5cf-45bc-8452-84d9b555fa6f.png">
@goeranu isn't it done already?
In the particular case when the suggested translation is prefilled, I do indeed get markers of the changes nowadays. But not when there is separate suggestion, like here for example.
![Screenshot_20220721_093852](https://user-images.githubusercontent.com/1842587/180157970-9ffea457-1988-4ea3-8692-84c1c8f06765.png)

Similarly, there are no indication what is changed if you select “automatic suggestions” (approximate name, I'm not running in English.) You get an indication there is a 91% similarity, but you are not told what 9% differs.
![Screenshot_20220721_094601](https://user-images.githubusercontent.com/1842587/180158906-f7b79aa0-b6f6-4ee2-998b-0dd7989f4a41.png)

Do you want separate reports for each of these cases?
I guess OP wants what Crowdin provides like:
![image](https://user-images.githubusercontent.com/49396421/181191089-daf80895-a456-4f80-b9f9-38a9d4ac64d5.png)

Pontoon too: https://github.com/WeblateOrg/weblate/issues/4513#issue-700909169

Resolving patch:
diff --git a/weblate/machinery/views.py b/weblate/machinery/views.py
--- a/weblate/machinery/views.py
+++ b/weblate/machinery/views.py
@@ -24,6 +24,7 @@
 from weblate.machinery.base import MachineTranslationError
 from weblate.machinery.models import MACHINERY
 from weblate.trans.models import Unit
+from weblate.utils.diff import Differ
 from weblate.utils.errors import report_error
 from weblate.utils.views import get_project
 from weblate.wladmin.views import MENU as MANAGE_MENU
@@ -314,6 +315,8 @@ def handle_machinery(request, service, unit, search=None):
     }
 
     machinery_settings = component.project.get_machinery_settings()
+    differ = Differ()
+    targets = unit.get_target_plurals()
 
     try:
         translation_service = translation_service_class(machinery_settings[service])
@@ -322,15 +325,18 @@ def handle_machinery(request, service, unit, search=None):
     else:
         try:
             if search:
-                response["translations"] = translation_service.search(
-                    unit, search, request.user
-                )
+                translations = translation_service.search(unit, search, request.user)
             else:
                 translations = translation_service.translate(unit, request.user)
                 for plural_form, possible_translations in enumerate(translations):
                     for item in possible_translations:
                         item["plural_form"] = plural_form
-                response["translations"] = list(chain.from_iterable(translations))
+                        if targets[plural_form]:
+                            item["diff"] = differ.highlight(
+                                item["text"], targets[plural_form]
+                            )
+                translations = list(chain.from_iterable(translations))
+            response["translations"] = translations
             response["responseStatus"] = 200
         except MachineTranslationError as exc:
             response["responseDetails"] = str(exc)
diff --git a/weblate/utils/diff.py b/weblate/utils/diff.py
new file mode 100644
--- /dev/null
+++ b/weblate/utils/diff.py
@@ -0,0 +1,27 @@
+# Copyright © Michal Čihař <michal@weblate.org>
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+
+from diff_match_patch import diff_match_patch
+from django.utils.html import format_html
+
+
+class Differ:
+    def __init__(self):
+        self.dmp = diff_match_patch()
+
+    def highlight(self, new, old):
+        dmp = self.dmp
+        diff = dmp.diff_main(old, new)
+        dmp.diff_cleanupSemantic(diff)
+        output = []
+        for op, data in diff:
+            if op == dmp.DIFF_DELETE:
+                template = "<del>{}</del>"
+            elif op == dmp.DIFF_INSERT:
+                template = "<ins>{}</ins>"
+            elif op == dmp.DIFF_EQUAL:
+                template = "{}"
+            output.append(format_html(template, data))
+        return "".join(output)


Test patch: