Repository: WeblateOrg/weblate

Issue:
Diff in history events does not show the real changes
### Describe the issue

The history events do not show the real diff.
Are there some history events missing or is it a diff rendering bug?

### I already tried

- [X] I've read and searched [the documentation](https://docs.weblate.org/).
- [X] I've searched for similar issues in this repository.

### Steps to reproduce the behavior

https://hosted.weblate.org/translate/weblate/application/zh_Hans/?checksum=97a6aaa4a3cf7d34#history

### Expected behavior

The actual translation text change is

```diff
---由 {username} 邀请至 {site_title}。
+++由 {username} 邀请至 {project} 项目。
```

The addition (green part) should cover `project} 项目` instead of only `project}`. Currently ` 项目` is not covered as green in this example.
But the amount of edited characters is right🤔.

### Screenshots

![image](https://github.com/WeblateOrg/weblate/assets/49396421/5ecd0bc6-ab06-4ed1-9af4-a5d1d7bebadf)
![image](https://github.com/WeblateOrg/weblate/assets/49396421/08f7206f-f407-43ab-af75-536575c666eb)

### Exception traceback

_No response_

### How do you run Weblate?

weblate.org service

### Weblate versions

Weblate 5.0.1-dev (weblate-5.0-208-ge6843a560e)

### Weblate deploy checks

_No response_

### Additional context

_No response_


Discussion:
@Geeyun-JY3 

It's a rendering bug, as I pointed out on https://github.com/WeblateOrg/weblate/issues/9832

> In this [example](https://hosted.weblate.org/translate/flathub/frontend/pl/?checksum=2df913c5b01b45f4), the diff view only highlights `{{appName}}` does not highlight other characters.
> 
> ![Screenshot_2023-08-30-16-33-57-547_com lemurbrowser exts-edit](https://user-images.githubusercontent.com/108261729/264295071-f0cd2180-d615-4cb2-9562-df684fc1ef1b.jpg)


It seems to be related to the placeables🤔.

Resolving patch:
diff --git a/weblate/trans/templatetags/translations.py b/weblate/trans/templatetags/translations.py
--- a/weblate/trans/templatetags/translations.py
+++ b/weblate/trans/templatetags/translations.py
@@ -139,6 +139,7 @@ def parse_diff(self):  # noqa: C901
                 formatter.parse()
                 self.tags[offset].append(f"<del>{formatter.format()}</del>")
             elif op == self.differ.DIFF_INSERT:
+                end = offset + len(data)
                 # Rearrange space highlighting
                 move_space = False
                 start_space = -1
@@ -172,10 +173,46 @@ def parse_diff(self):  # noqa: C901
                     self.tags[offset].append("<ins>")
                 if move_space:
                     self.tags[offset].append(SPACE_START)
-                offset += len(data)
-                self.tags[offset].append("</ins>")
+                self.tags[end].append("</ins>")
                 if start_space != -1:
-                    self.tags[offset].append(SPACE_START)
+                    self.tags[end].append(SPACE_START)
+
+                # Rearange other tags
+                open_tags = 0
+                process = False
+                for i in range(offset, end + 1):
+                    remove = []
+                    for pos, tag in enumerate(self.tags[i]):
+                        if not process:
+                            if tag.startswith("<ins"):
+                                process = True
+                            continue
+                        if tag.startswith("</ins>"):
+                            break
+                        if tag.startswith("<span"):
+                            open_tags += 1
+                        elif tag.startswith("</span"):
+                            if open_tags == 0:
+                                # Remove tags spanning over <ins>
+                                remove.append(pos)
+                                found = None
+                                for back in range(offset - 1, 0, -1):
+                                    for child_pos, child in reversed(
+                                        list(enumerate(self.tags[back]))
+                                    ):
+                                        if child.startswith("<span"):
+                                            found = child_pos
+                                            break
+                                    if found is not None:
+                                        del self.tags[back][found]
+                                        break
+                            else:
+                                open_tags -= 1
+                    # Remove closing tags (do this outside the loop)
+                    for pos in reversed(remove):
+                        del self.tags[i][pos]
+
+                offset = end
             elif op == self.differ.DIFF_EQUAL:
                 offset += len(data)
 


Test patch:
diff --git a/weblate/trans/tests/test_templatetags.py b/weblate/trans/tests/test_templatetags.py
--- a/weblate/trans/tests/test_templatetags.py
+++ b/weblate/trans/tests/test_templatetags.py
@@ -262,6 +262,24 @@ def test_diff(self):
             """,
         )
 
+    def test_diff_github_9821(self):
+        unit = Unit(translation=self.translation)
+        unit.all_flags = {"python-brace-format"}
+        self.assertHTMLEqual(
+            format_translation(
+                ["由 {username} 邀请至 {project} 项目。"],
+                self.component.source_language,
+                diff="由 {username} 邀请至 {site_title}。",
+                unit=unit,
+            )["items"][0]["content"],
+            """
+            由
+            <span class="hlcheck" data-value="{username}"><span class="highlight-number"></span>{username}</span>
+             邀请至
+             {<del>site_title}</del><ins>project} 项目</ins>。
+            """,
+        )
+
     def test_diff_whitespace(self):
         self.assertHTMLEqual(
             format_translation(
diff --git a/weblate/utils/tests/test_diff.py b/weblate/utils/tests/test_diff.py
--- a/weblate/utils/tests/test_diff.py
+++ b/weblate/utils/tests/test_diff.py
@@ -85,3 +85,12 @@ def test_sentry_4428(self):
 <del></del> site_perl directory.<ins>
 ]]&gt;</ins>""",
         )
+
+    def test_github_9821(self):
+        self.assertEqual(
+            self.differ.highlight(
+                "由 {username} 邀请至 {project} 项目。",
+                "由 {username} 邀请至 {site_title}。",
+            ),
+            "由 {username} 邀请至 {<del>site_title}</del><ins>project} 项目</ins>。",
+        )