We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Pretranslation issues with multiline strings
Pretranslation struggles to translate Fluent strings where line breaks are used to limit the line width, as it treats each line as a separate sentence.

```
rec-pw-1-2 =
  Make this password unique and different from any others you use.
  A good strategy to follow is to combine two or more unrelated
  words to create an entire pass phrase, and include numbers and symbols.
```

I don't think we can completely ignore line breaks, because there are some cases where these have an effect on display ([example](https://searchfox.org/mozilla-central/rev/169bf38e150667afac81ab73ef8b5ace8f1dfa8d/browser/locales/en-US/browser/downloads.ftl#244-248)). But maybe we can strip line breaks (i.e. replace them with a whitespace) when sending the translation to the machine translation engine, hoping that translators will catch edge cases when reviewing?

Cc @eemeli because that's a topic that we discussed at some point for the Fluent editor.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pontoon/pretranslation/pretranslate.py`
Content:
```
1 import logging
2 import operator
3 import re
4 
5 from django.db.models import CharField, Value as V
6 from django.db.models.functions import Concat
7 
8 from fluent.syntax import FluentParser, FluentSerializer
9 from functools import reduce
10 
11 from pontoon.base.models import User, TranslatedResource
12 from pontoon.base.fluent import FlatTransformer, create_locale_plural_variants
13 from pontoon.machinery.utils import (
14     get_google_translate_data,
15     get_translation_memory_data,
16 )
17 
18 
19 log = logging.getLogger(__name__)
20 
21 parser = FluentParser()
22 serializer = FluentSerializer()
23 
24 
25 class PretranslationTransformer(FlatTransformer):
26     def __init__(self, locale):
27         self.services = []
28         self.locale = locale
29 
30     def visit_SelectExpression(self, node):
31         create_locale_plural_variants(node, self.locale)
32         return self.generic_visit(node)
33 
34     def visit_TextElement(self, node):
35         pretranslation, service = get_pretranslated_data(node.value, self.locale)
36 
37         if pretranslation is None:
38             raise ValueError(
39                 f"Pretranslation for `{node.value}` to {self.locale.code} not available."
40             )
41 
42         node.value = pretranslation
43         self.services.append(service)
44         return node
45 
46 
47 def get_pretranslations(entity, locale):
48     """
49     Get pretranslations for the entity-locale pair using internal translation memory and
50     Google's machine translation.
51 
52     For Fluent strings, uplift SelectExpressions, serialize Placeables as TextElements
53     and then only pretranslate TextElements. Set the most frequent TextElement
54     pretranslation author as the author of the entire pretranslation.
55 
56     :arg Entity entity: the Entity object
57     :arg Locale locale: the Locale object
58 
59     :returns: a list of tuples, consisting of:
60         - a pretranslation of the entity
61         - a plural form
62         - a user (representing TM or GT service)
63     """
64     source = entity.string
65     services = {
66         "tm": User.objects.get(email="pontoon-tm@example.com"),
67         "gt": User.objects.get(email="pontoon-gt@example.com"),
68     }
69 
70     if entity.resource.format == "ftl":
71         source_ast = parser.parse_entry(source)
72         pt_transformer = PretranslationTransformer(locale)
73 
74         try:
75             pretranslated_ast = pt_transformer.visit(source_ast)
76         except ValueError as e:
77             log.info(f"Fluent pretranslation error: {e}")
78             return []
79 
80         pretranslation = serializer.serialize_entry(pretranslated_ast)
81 
82         authors = [services[service] for service in pt_transformer.services]
83         author = max(set(authors), key=authors.count) if authors else services["tm"]
84 
85         return [(pretranslation, None, author)]
86 
87     else:
88         pretranslation, service = get_pretranslated_data(source, locale)
89 
90         if pretranslation is None:
91             return []
92 
93         author = services[service]
94         if entity.string_plural == "":
95             return [(pretranslation, None, author)]
96         else:
97             plural_forms = range(0, locale.nplurals or 1)
98             return [
99                 (pretranslation, plural_form, author) for plural_form in plural_forms
100             ]
101 
102 
103 def get_pretranslated_data(source, locale):
104     # Empty strings do not need translation
105     if re.search("^\\s*$", source):
106         return source, "tm"
107 
108     # Try to get matches from Translation Memory
109     tm_response = get_translation_memory_data(text=source, locale=locale)
110     tm_perfect = [t for t in tm_response if int(t["quality"]) == 100]
111     if tm_perfect:
112         return tm_perfect[0]["target"], "tm"
113 
114     # Fetch from Google Translate
115     elif locale.google_translate_code:
116         gt_response = get_google_translate_data(text=source, locale=locale)
117         if gt_response["status"]:
118             return gt_response["translation"], "gt"
119 
120     return None, None
121 
122 
123 def update_changed_instances(tr_filter, tr_dict, translations):
124     """
125     Update the latest activity and stats for changed Locales, ProjectLocales
126     & TranslatedResources
127     """
128     tr_filter = tuple(tr_filter)
129     # Combine all generated filters with an OK operator.
130     # `operator.ior` is the '|' Python operator, which turns into a logical OR
131     # when used between django ORM query objects.
132     tr_query = reduce(operator.ior, tr_filter)
133 
134     translatedresources = TranslatedResource.objects.filter(tr_query).annotate(
135         locale_resource=Concat(
136             "locale_id", V("-"), "resource_id", output_field=CharField()
137         )
138     )
139 
140     translatedresources.update_stats()
141 
142     for tr in translatedresources:
143         index = tr_dict[tr.locale_resource]
144         translation = translations[index]
145         translation.update_latest_translation()
146
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pontoon/pretranslation/pretranslate.py b/pontoon/pretranslation/pretranslate.py
--- a/pontoon/pretranslation/pretranslate.py
+++ b/pontoon/pretranslation/pretranslate.py
@@ -32,11 +32,15 @@
         return self.generic_visit(node)
 
     def visit_TextElement(self, node):
-        pretranslation, service = get_pretranslated_data(node.value, self.locale)
+        # Machine translation treats each line as separate sentence,
+        # hence we replace newline characters with spaces.
+        source = node.value.replace("\n", " ")
+
+        pretranslation, service = get_pretranslated_data(source, self.locale)
 
         if pretranslation is None:
             raise ValueError(
-                f"Pretranslation for `{node.value}` to {self.locale.code} not available."
+                f"Pretranslation for `{source}` to {self.locale.code} not available."
             )
 
         node.value = pretranslation

{"golden_diff": "diff --git a/pontoon/pretranslation/pretranslate.py b/pontoon/pretranslation/pretranslate.py\n--- a/pontoon/pretranslation/pretranslate.py\n+++ b/pontoon/pretranslation/pretranslate.py\n@@ -32,11 +32,15 @@\n         return self.generic_visit(node)\n \n     def visit_TextElement(self, node):\n-        pretranslation, service = get_pretranslated_data(node.value, self.locale)\n+        # Machine translation treats each line as separate sentence,\n+        # hence we replace newline characters with spaces.\n+        source = node.value.replace(\"\\n\", \" \")\n+\n+        pretranslation, service = get_pretranslated_data(source, self.locale)\n \n         if pretranslation is None:\n             raise ValueError(\n-                f\"Pretranslation for `{node.value}` to {self.locale.code} not available.\"\n+                f\"Pretranslation for `{source}` to {self.locale.code} not available.\"\n             )\n \n         node.value = pretranslation\n", "issue": "Pretranslation issues with multiline strings\nPretranslation struggles to translate Fluent strings where line breaks are used to limit the line width, as it treats each line as a separate sentence.\r\n\r\n```\r\nrec-pw-1-2 =\r\n  Make this password unique and different from any others you use.\r\n  A good strategy to follow is to combine two or more unrelated\r\n  words to create an entire pass phrase, and include numbers and symbols.\r\n```\r\n\r\nI don't think we can completely ignore line breaks, because there are some cases where these have an effect on display ([example](https://searchfox.org/mozilla-central/rev/169bf38e150667afac81ab73ef8b5ace8f1dfa8d/browser/locales/en-US/browser/downloads.ftl#244-248)). But maybe we can strip line breaks (i.e. replace them with a whitespace) when sending the translation to the machine translation engine, hoping that translators will catch edge cases when reviewing?\r\n\r\nCc @eemeli because that's a topic that we discussed at some point for the Fluent editor.\n", "before_files": [{"content": "import logging\nimport operator\nimport re\n\nfrom django.db.models import CharField, Value as V\nfrom django.db.models.functions import Concat\n\nfrom fluent.syntax import FluentParser, FluentSerializer\nfrom functools import reduce\n\nfrom pontoon.base.models import User, TranslatedResource\nfrom pontoon.base.fluent import FlatTransformer, create_locale_plural_variants\nfrom pontoon.machinery.utils import (\n    get_google_translate_data,\n    get_translation_memory_data,\n)\n\n\nlog = logging.getLogger(__name__)\n\nparser = FluentParser()\nserializer = FluentSerializer()\n\n\nclass PretranslationTransformer(FlatTransformer):\n    def __init__(self, locale):\n        self.services = []\n        self.locale = locale\n\n    def visit_SelectExpression(self, node):\n        create_locale_plural_variants(node, self.locale)\n        return self.generic_visit(node)\n\n    def visit_TextElement(self, node):\n        pretranslation, service = get_pretranslated_data(node.value, self.locale)\n\n        if pretranslation is None:\n            raise ValueError(\n                f\"Pretranslation for `{node.value}` to {self.locale.code} not available.\"\n            )\n\n        node.value = pretranslation\n        self.services.append(service)\n        return node\n\n\ndef get_pretranslations(entity, locale):\n    \"\"\"\n    Get pretranslations for the entity-locale pair using internal translation memory and\n    Google's machine translation.\n\n    For Fluent strings, uplift SelectExpressions, serialize Placeables as TextElements\n    and then only pretranslate TextElements. Set the most frequent TextElement\n    pretranslation author as the author of the entire pretranslation.\n\n    :arg Entity entity: the Entity object\n    :arg Locale locale: the Locale object\n\n    :returns: a list of tuples, consisting of:\n        - a pretranslation of the entity\n        - a plural form\n        - a user (representing TM or GT service)\n    \"\"\"\n    source = entity.string\n    services = {\n        \"tm\": User.objects.get(email=\"pontoon-tm@example.com\"),\n        \"gt\": User.objects.get(email=\"pontoon-gt@example.com\"),\n    }\n\n    if entity.resource.format == \"ftl\":\n        source_ast = parser.parse_entry(source)\n        pt_transformer = PretranslationTransformer(locale)\n\n        try:\n            pretranslated_ast = pt_transformer.visit(source_ast)\n        except ValueError as e:\n            log.info(f\"Fluent pretranslation error: {e}\")\n            return []\n\n        pretranslation = serializer.serialize_entry(pretranslated_ast)\n\n        authors = [services[service] for service in pt_transformer.services]\n        author = max(set(authors), key=authors.count) if authors else services[\"tm\"]\n\n        return [(pretranslation, None, author)]\n\n    else:\n        pretranslation, service = get_pretranslated_data(source, locale)\n\n        if pretranslation is None:\n            return []\n\n        author = services[service]\n        if entity.string_plural == \"\":\n            return [(pretranslation, None, author)]\n        else:\n            plural_forms = range(0, locale.nplurals or 1)\n            return [\n                (pretranslation, plural_form, author) for plural_form in plural_forms\n            ]\n\n\ndef get_pretranslated_data(source, locale):\n    # Empty strings do not need translation\n    if re.search(\"^\\\\s*$\", source):\n        return source, \"tm\"\n\n    # Try to get matches from Translation Memory\n    tm_response = get_translation_memory_data(text=source, locale=locale)\n    tm_perfect = [t for t in tm_response if int(t[\"quality\"]) == 100]\n    if tm_perfect:\n        return tm_perfect[0][\"target\"], \"tm\"\n\n    # Fetch from Google Translate\n    elif locale.google_translate_code:\n        gt_response = get_google_translate_data(text=source, locale=locale)\n        if gt_response[\"status\"]:\n            return gt_response[\"translation\"], \"gt\"\n\n    return None, None\n\n\ndef update_changed_instances(tr_filter, tr_dict, translations):\n    \"\"\"\n    Update the latest activity and stats for changed Locales, ProjectLocales\n    & TranslatedResources\n    \"\"\"\n    tr_filter = tuple(tr_filter)\n    # Combine all generated filters with an OK operator.\n    # `operator.ior` is the '|' Python operator, which turns into a logical OR\n    # when used between django ORM query objects.\n    tr_query = reduce(operator.ior, tr_filter)\n\n    translatedresources = TranslatedResource.objects.filter(tr_query).annotate(\n        locale_resource=Concat(\n            \"locale_id\", V(\"-\"), \"resource_id\", output_field=CharField()\n        )\n    )\n\n    translatedresources.update_stats()\n\n    for tr in translatedresources:\n        index = tr_dict[tr.locale_resource]\n        translation = translations[index]\n        translation.update_latest_translation()\n", "path": "pontoon/pretranslation/pretranslate.py"}], "after_files": [{"content": "import logging\nimport operator\nimport re\n\nfrom django.db.models import CharField, Value as V\nfrom django.db.models.functions import Concat\n\nfrom fluent.syntax import FluentParser, FluentSerializer\nfrom functools import reduce\n\nfrom pontoon.base.models import User, TranslatedResource\nfrom pontoon.base.fluent import FlatTransformer, create_locale_plural_variants\nfrom pontoon.machinery.utils import (\n    get_google_translate_data,\n    get_translation_memory_data,\n)\n\n\nlog = logging.getLogger(__name__)\n\nparser = FluentParser()\nserializer = FluentSerializer()\n\n\nclass PretranslationTransformer(FlatTransformer):\n    def __init__(self, locale):\n        self.services = []\n        self.locale = locale\n\n    def visit_SelectExpression(self, node):\n        create_locale_plural_variants(node, self.locale)\n        return self.generic_visit(node)\n\n    def visit_TextElement(self, node):\n        # Machine translation treats each line as separate sentence,\n        # hence we replace newline characters with spaces.\n        source = node.value.replace(\"\\n\", \" \")\n\n        pretranslation, service = get_pretranslated_data(source, self.locale)\n\n        if pretranslation is None:\n            raise ValueError(\n                f\"Pretranslation for `{source}` to {self.locale.code} not available.\"\n            )\n\n        node.value = pretranslation\n        self.services.append(service)\n        return node\n\n\ndef get_pretranslations(entity, locale):\n    \"\"\"\n    Get pretranslations for the entity-locale pair using internal translation memory and\n    Google's machine translation.\n\n    For Fluent strings, uplift SelectExpressions, serialize Placeables as TextElements\n    and then only pretranslate TextElements. Set the most frequent TextElement\n    pretranslation author as the author of the entire pretranslation.\n\n    :arg Entity entity: the Entity object\n    :arg Locale locale: the Locale object\n\n    :returns: a list of tuples, consisting of:\n        - a pretranslation of the entity\n        - a plural form\n        - a user (representing TM or GT service)\n    \"\"\"\n    source = entity.string\n    services = {\n        \"tm\": User.objects.get(email=\"pontoon-tm@example.com\"),\n        \"gt\": User.objects.get(email=\"pontoon-gt@example.com\"),\n    }\n\n    if entity.resource.format == \"ftl\":\n        source_ast = parser.parse_entry(source)\n        pt_transformer = PretranslationTransformer(locale)\n\n        try:\n            pretranslated_ast = pt_transformer.visit(source_ast)\n        except ValueError as e:\n            log.info(f\"Fluent pretranslation error: {e}\")\n            return []\n\n        pretranslation = serializer.serialize_entry(pretranslated_ast)\n\n        authors = [services[service] for service in pt_transformer.services]\n        author = max(set(authors), key=authors.count) if authors else services[\"tm\"]\n\n        return [(pretranslation, None, author)]\n\n    else:\n        pretranslation, service = get_pretranslated_data(source, locale)\n\n        if pretranslation is None:\n            return []\n\n        author = services[service]\n        if entity.string_plural == \"\":\n            return [(pretranslation, None, author)]\n        else:\n            plural_forms = range(0, locale.nplurals or 1)\n            return [\n                (pretranslation, plural_form, author) for plural_form in plural_forms\n            ]\n\n\ndef get_pretranslated_data(source, locale):\n    # Empty strings do not need translation\n    if re.search(\"^\\\\s*$\", source):\n        return source, \"tm\"\n\n    # Try to get matches from Translation Memory\n    tm_response = get_translation_memory_data(text=source, locale=locale)\n    tm_perfect = [t for t in tm_response if int(t[\"quality\"]) == 100]\n    if tm_perfect:\n        return tm_perfect[0][\"target\"], \"tm\"\n\n    # Fetch from Google Translate\n    elif locale.google_translate_code:\n        gt_response = get_google_translate_data(text=source, locale=locale)\n        if gt_response[\"status\"]:\n            return gt_response[\"translation\"], \"gt\"\n\n    return None, None\n\n\ndef update_changed_instances(tr_filter, tr_dict, translations):\n    \"\"\"\n    Update the latest activity and stats for changed Locales, ProjectLocales\n    & TranslatedResources\n    \"\"\"\n    tr_filter = tuple(tr_filter)\n    # Combine all generated filters with an OK operator.\n    # `operator.ior` is the '|' Python operator, which turns into a logical OR\n    # when used between django ORM query objects.\n    tr_query = reduce(operator.ior, tr_filter)\n\n    translatedresources = TranslatedResource.objects.filter(tr_query).annotate(\n        locale_resource=Concat(\n            \"locale_id\", V(\"-\"), \"resource_id\", output_field=CharField()\n        )\n    )\n\n    translatedresources.update_stats()\n\n    for tr in translatedresources:\n        index = tr_dict[tr.locale_resource]\n        translation = translations[index]\n        translation.update_latest_translation()\n", "path": "pontoon/pretranslation/pretranslate.py"}]}