Repository: freedomofpress/securedrop

Issue:
`i18n_tool.py update-from-weblate` no longer detects translators for attribution
## Description

After #6580, including with the fix proposed in #6629, `i18n_tool.py update-from-weblate` fails to detect the translators to credit for each per-language commit.

## Steps to Reproduce

```sh-session
user@sd-dev:~/securedrop$ securedrop/bin/dev-shell ./i18n_tool.py update-from-weblate
```

## Expected Behavior

```sh-session
user@sd-dev:~/securedrop$ git log -n 1 --no-show-signature i18n-merge
commit eb99e5c2f98ee3b901294251399280e0abf0c043 (origin/i18n-merge, i18n-merge)
Author: Cory Francis Myers <cory@freedom.press>
Date:   Mon Oct 17 23:58:21 2022 +0000

    l10n: updated bn (bn)
    
    contributors:
      Oymate
      diyaf
    
    updated from:
      repo: https://github.com/freedomofpress/securedrop-i18n
      commit: 95b4cc8f2cdf2bb7f338b4c2cc996704a1f1909
```

## Actual Behavior

```sh-session
user@sd-dev:~/securedrop$ git log -n 1 --no-show-signature
commit e7642f527c09172304dafe578aec4cd182d9cd0d (HEAD -> develop)
Author: Cory Francis Myers <cory@freedom.press>
Date:   Tue Oct 18 00:57:00 2022 +0000

    l10n: updated bn (bn)
    
    contributors:
    
    updated from:
      repo: https://github.com/freedomofpress/securedrop-i18n
      commit: 95b4cc8f2cdf2bb7f338b4c2cc996704a1f1909d
```

## Comments

I haven't had time to debug this as part of the v2.5.0 localization merge, so for #6646 I've worked around it locally with:

```sh-session
user@sd-dev:~/securedrop$ git revert -m1 -n 94c6bbb
```


Discussion:
Previously it was:
```python
        log_lines = subprocess.check_output(log_command).decode("utf-8").strip().split("\n")
```

And now it is:
```python
        log_lines = subprocess.check_output(log_command, encoding="utf-8").strip().splitlines()
```

Resolving patch:
diff --git a/securedrop/i18n_tool.py b/securedrop/i18n_tool.py
--- a/securedrop/i18n_tool.py
+++ b/securedrop/i18n_tool.py
@@ -389,7 +389,10 @@ def translators(
 
         log_command.extend([args.target, "--", path])
 
-        log_lines = subprocess.check_output(log_command, encoding="utf-8").strip().splitlines()
+        # NB. We use an explicit str.split("\n") here because str.splitlines() splits on a
+        # set of characters that includes the \x1e "record separator" we pass to "git log
+        # --format" in log_command.  See #6648.
+        log_lines = subprocess.check_output(log_command, encoding="utf-8").strip().split("\n")
         path_changes = [c.split("\x1e") for c in log_lines]
         path_changes = [
             c


Test patch:
diff --git a/securedrop/tests/test_i18n_tool.py b/securedrop/tests/test_i18n_tool.py
--- a/securedrop/tests/test_i18n_tool.py
+++ b/securedrop/tests/test_i18n_tool.py
@@ -392,7 +392,9 @@ def r():
         subprocess.check_call(["git", "add", str(po_file)], **k)
         subprocess.check_call(["git", "config", "user.email", "somone@else.com"], **k)
         subprocess.check_call(["git", "config", "user.name", "Someone Else"], **k)
-        subprocess.check_call(["git", "commit", "-m", "translation change", str(po_file)], **k)
+        subprocess.check_call(
+            ["git", "commit", "-m", "Translated using Weblate", str(po_file)], **k
+        )
 
         k = {"cwd": join(d, "securedrop")}
         subprocess.check_call(["git", "config", "user.email", "somone@else.com"], **k)
@@ -417,6 +419,8 @@ def r():
         )
         assert "l10n: updated Dutch (nl)" in r()
         assert "l10n: updated German (de_DE)" not in r()
+
+        # The translator is credited in Git history.
         message = subprocess.check_output(
             ["git", "--no-pager", "-C", "securedrop", "show"],
             cwd=d,
@@ -424,3 +428,18 @@ def r():
         )
         assert "Someone Else" in message
         assert "Loïc" not in message
+
+        # The "list-translators" command correctly reads the translator from Git history.
+        caplog.clear()
+        i18n_tool.I18NTool().main(
+            [
+                "--verbose",
+                "list-translators",
+                "--all",
+                "--root",
+                join(str(tmpdir), "securedrop"),
+                "--url",
+                join(str(tmpdir), "i18n"),
+            ]
+        )
+        assert "Someone Else" in caplog.text