We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Pretranslate access keys using the algorithm to extract candidate keys
Fluent Rich editor has a special UI for messages with access keys, which lists access key candidates.

We should use the same logic when pretranslating accesskeys and use the first candidate as the translation.

We should also take into account #2717.

--- 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/transformer.py`
Content:
```
1 from copy import deepcopy
2 from typing import Callable, Optional, cast
3 
4 from fluent.syntax import ast as FTL
5 from fluent.syntax.serializer import serialize_expression
6 from fluent.syntax.visitor import Transformer
7 
8 from pontoon.base.fluent import is_plural_expression
9 from pontoon.base.models import Locale
10 
11 
12 def flatten_select_expressions(pattern: FTL.Pattern):
13     """
14     If the pattern contains any select expressions,
15     flatten it to only contain select expressions.
16     Leading and trailing elements are copied into each variant,
17     and any single leading or trailing spaces are lifted out of the select expressions.
18     """
19 
20     def isSelExp(el: FTL.PatternElement):
21         return isinstance(el, FTL.Placeable) and isinstance(
22             el.expression, FTL.SelectExpression
23         )
24 
25     def patternStartsWithSpace(pat: list[FTL.PatternElement]):
26         return isinstance(pat[0], FTL.TextElement) and pat[0].value.startswith(" ")
27 
28     def patternEndsWithSpace(pat: list[FTL.PatternElement]):
29         return isinstance(pat[-1], FTL.TextElement) and pat[-1].value.endswith(" ")
30 
31     prev = -1
32     select = None
33     for idx, placeable in filter(lambda x: isSelExp(x[1]), enumerate(pattern.elements)):
34         before = pattern.elements[prev + 1 : idx]
35         if before:
36             select = cast(FTL.SelectExpression, placeable.expression)
37             for variant in select.variants:
38                 variant.value.elements[0:0] = deepcopy(before)
39         prev = idx
40     if select:
41         after = pattern.elements[prev + 1 :]
42         if after:
43             for variant in select.variants:
44                 variant.value.elements += deepcopy(after)
45 
46         res: list[FTL.PatternElement] = []
47         for placeable in filter(isSelExp, pattern.elements):
48             patterns = tuple(
49                 map(lambda var: var.value.elements, placeable.expression.variants)
50             )
51 
52             # Collect leading spaces
53             if all(map(patternStartsWithSpace, patterns)):
54                 res.append(FTL.Placeable(FTL.StringLiteral(" ")))
55                 for pat in patterns:
56                     pat[0].value = pat[0].value[1:]
57 
58             res.append(placeable)
59 
60             # Collect trailing spaces
61             if all(map(patternEndsWithSpace, patterns)):
62                 res.append(FTL.Placeable(FTL.StringLiteral(" ")))
63                 for pat in patterns:
64                     pat[-1].value = pat[-1].value[:-1]
65         pattern.elements = res
66 
67 
68 def create_locale_plural_variants(node: FTL.SelectExpression, locale: Locale):
69     variants: list[FTL.Variant] = []
70     source_plurals: dict[str, FTL.Variant] = {}
71     default = cast(FTL.Variant, None)
72 
73     for variant in node.variants:
74         key = variant.key
75         if isinstance(key, FTL.NumberLiteral):
76             variants.append(variant)
77         else:
78             source_plurals[key.name] = variant
79         if variant.default:
80             default = variant
81 
82     for plural in locale.cldr_plurals_list():
83         if plural in source_plurals.keys():
84             variant = source_plurals[plural]
85         else:
86             variant = deepcopy(default)
87             variant.key.name = plural
88         variant.default = False
89         variants.append(variant)
90 
91     variants[-1].default = True
92 
93     node.variants = variants
94 
95 
96 class PreparePretranslation(Transformer):
97     """
98     Flattens the given Pattern, uplifting selectors to the highest possible level and
99     duplicating shared parts in the variants. Transforms plural variants to match the
100     locale.
101     """
102 
103     def __init__(self, locale: Locale):
104         self.locale = locale
105 
106     def visit_Attribute(self, node: FTL.Attribute):
107         flatten_select_expressions(node.value)
108         return self.generic_visit(node)
109 
110     def visit_Message(self, node: FTL.Message):
111         if node.value:
112             flatten_select_expressions(node.value)
113         return self.generic_visit(node)
114 
115     def visit_SelectExpression(self, node: FTL.SelectExpression):
116         if is_plural_expression(node):
117             create_locale_plural_variants(node, self.locale)
118         return self.generic_visit(node)
119 
120 
121 class ApplyPretranslation(Transformer):
122     """
123     During `visit()`, calls `callback(source, locale) -> (translation, service)` for each pattern.
124     """
125 
126     def __init__(
127         self,
128         locale: Locale,
129         entry: FTL.EntryType,
130         callback: Callable[[str, str], tuple[Optional[str], str]],
131     ):
132         prep = PreparePretranslation(locale)
133         prep.visit(entry)
134         self.callback = callback
135         self.locale = locale
136         self.services: list[str] = []
137 
138     def visit_Attribute(self, node):
139         if (
140             node.id.name.endswith("accesskey")
141             and not self.locale.accesskey_localization
142         ):
143             return node
144         return self.generic_visit(node)
145 
146     def visit_Pattern(self, node: FTL.Pattern):
147         has_selects = False
148         source = ""
149         for el in node.elements:
150             if isinstance(el, FTL.TextElement):
151                 source += el.value
152             elif isinstance(el.expression, FTL.SelectExpression):
153                 self.generic_visit(el.expression)
154                 has_selects = True
155             else:
156                 source += serialize_expression(el)
157         if not has_selects and source != "":
158             # Machine translation treats each line as a separate sentence,
159             # hence we replace newline characters with spaces.
160             source = source.replace("\n", " ")
161 
162             translation, service = self.callback(source, self.locale)
163             if translation is None:
164                 raise ValueError(
165                     f"Pretranslation for `{source}` to {self.locale.code} not available."
166                 )
167             node.elements = [FTL.TextElement(translation)]
168             self.services.append(service)
169         return node
170
```
--- 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/transformer.py b/pontoon/pretranslation/transformer.py
--- a/pontoon/pretranslation/transformer.py
+++ b/pontoon/pretranslation/transformer.py
@@ -1,3 +1,5 @@
+import re
+
 from copy import deepcopy
 from typing import Callable, Optional, cast
 
@@ -93,6 +95,51 @@
     node.variants = variants
 
 
+def extract_accesskey_candidates(message: FTL.Message, label: str, variant_name=None):
+    def get_source(names):
+        for attribute in message.attributes:
+            if attribute.id.name in names:
+                element = attribute.value.elements[0]
+
+                if isinstance(element, FTL.TextElement):
+                    return element.value
+                elif isinstance(element.expression, FTL.SelectExpression):
+                    variants = element.expression.variants
+                    variant = next(
+                        (v for v in variants if v.key.name == variant_name), variants[0]
+                    )
+                    variant_element = variant.value.elements[0]
+
+                    if isinstance(variant_element, FTL.TextElement):
+                        return variant_element.value
+
+        return None
+
+    prefix_end = label.index("accesskey")
+    prefix = label[0:prefix_end]
+
+    # Generate access key candidates:
+    if prefix:
+        # From a prefixed "label" attribute
+        name = f"{prefix}label"
+        source = get_source([name])
+    else:
+        # From a pre-defined list of attribute names
+        source = get_source(["label", "value", "aria-label"])
+        # From a message value
+        if not source and message.value:
+            source = message.value.elements[0].value
+
+    if not source:
+        return []
+
+    # Exclude placeables (message is flat). See bug 1447103 for details.
+    keys = re.sub(r"(?s){.*?}|[\W_]", "", source)
+
+    # Extract unique candidates
+    return list(dict.fromkeys(keys))
+
+
 class PreparePretranslation(Transformer):
     """
     Flattens the given Pattern, uplifting selectors to the highest possible level and
@@ -132,15 +179,43 @@
         prep = PreparePretranslation(locale)
         prep.visit(entry)
         self.callback = callback
+        self.entry = entry
         self.locale = locale
         self.services: list[str] = []
 
-    def visit_Attribute(self, node):
-        if (
-            node.id.name.endswith("accesskey")
-            and not self.locale.accesskey_localization
-        ):
-            return node
+    def visit_Attribute(self, node: FTL.Pattern):
+        name = node.id.name
+
+        def set_accesskey(element, variant_name=None):
+            if isinstance(element, FTL.TextElement) and len(element.value) <= 1:
+                candidates = extract_accesskey_candidates(
+                    self.entry, name, variant_name
+                )
+                if candidates:
+                    element.value = candidates[0]
+                    return True
+
+        if name.endswith("accesskey"):
+            if self.locale.accesskey_localization:
+                element = node.value.elements[0]
+
+                if set_accesskey(element):
+                    return node
+                elif isinstance(element, FTL.Placeable) and isinstance(
+                    element.expression, FTL.SelectExpression
+                ):
+                    variants = element.expression.variants
+                    processed_variants = 0
+                    for variant in variants:
+                        variant_element = variant.value.elements[0]
+                        if set_accesskey(variant_element, variant.key.name):
+                            processed_variants += 1
+                    if processed_variants == len(variants):
+                        return node
+
+            else:
+                return node
+
         return self.generic_visit(node)
 
     def visit_Pattern(self, node: FTL.Pattern):

{"golden_diff": "diff --git a/pontoon/pretranslation/transformer.py b/pontoon/pretranslation/transformer.py\n--- a/pontoon/pretranslation/transformer.py\n+++ b/pontoon/pretranslation/transformer.py\n@@ -1,3 +1,5 @@\n+import re\n+\n from copy import deepcopy\n from typing import Callable, Optional, cast\n \n@@ -93,6 +95,51 @@\n     node.variants = variants\n \n \n+def extract_accesskey_candidates(message: FTL.Message, label: str, variant_name=None):\n+    def get_source(names):\n+        for attribute in message.attributes:\n+            if attribute.id.name in names:\n+                element = attribute.value.elements[0]\n+\n+                if isinstance(element, FTL.TextElement):\n+                    return element.value\n+                elif isinstance(element.expression, FTL.SelectExpression):\n+                    variants = element.expression.variants\n+                    variant = next(\n+                        (v for v in variants if v.key.name == variant_name), variants[0]\n+                    )\n+                    variant_element = variant.value.elements[0]\n+\n+                    if isinstance(variant_element, FTL.TextElement):\n+                        return variant_element.value\n+\n+        return None\n+\n+    prefix_end = label.index(\"accesskey\")\n+    prefix = label[0:prefix_end]\n+\n+    # Generate access key candidates:\n+    if prefix:\n+        # From a prefixed \"label\" attribute\n+        name = f\"{prefix}label\"\n+        source = get_source([name])\n+    else:\n+        # From a pre-defined list of attribute names\n+        source = get_source([\"label\", \"value\", \"aria-label\"])\n+        # From a message value\n+        if not source and message.value:\n+            source = message.value.elements[0].value\n+\n+    if not source:\n+        return []\n+\n+    # Exclude placeables (message is flat). See bug 1447103 for details.\n+    keys = re.sub(r\"(?s){.*?}|[\\W_]\", \"\", source)\n+\n+    # Extract unique candidates\n+    return list(dict.fromkeys(keys))\n+\n+\n class PreparePretranslation(Transformer):\n     \"\"\"\n     Flattens the given Pattern, uplifting selectors to the highest possible level and\n@@ -132,15 +179,43 @@\n         prep = PreparePretranslation(locale)\n         prep.visit(entry)\n         self.callback = callback\n+        self.entry = entry\n         self.locale = locale\n         self.services: list[str] = []\n \n-    def visit_Attribute(self, node):\n-        if (\n-            node.id.name.endswith(\"accesskey\")\n-            and not self.locale.accesskey_localization\n-        ):\n-            return node\n+    def visit_Attribute(self, node: FTL.Pattern):\n+        name = node.id.name\n+\n+        def set_accesskey(element, variant_name=None):\n+            if isinstance(element, FTL.TextElement) and len(element.value) <= 1:\n+                candidates = extract_accesskey_candidates(\n+                    self.entry, name, variant_name\n+                )\n+                if candidates:\n+                    element.value = candidates[0]\n+                    return True\n+\n+        if name.endswith(\"accesskey\"):\n+            if self.locale.accesskey_localization:\n+                element = node.value.elements[0]\n+\n+                if set_accesskey(element):\n+                    return node\n+                elif isinstance(element, FTL.Placeable) and isinstance(\n+                    element.expression, FTL.SelectExpression\n+                ):\n+                    variants = element.expression.variants\n+                    processed_variants = 0\n+                    for variant in variants:\n+                        variant_element = variant.value.elements[0]\n+                        if set_accesskey(variant_element, variant.key.name):\n+                            processed_variants += 1\n+                    if processed_variants == len(variants):\n+                        return node\n+\n+            else:\n+                return node\n+\n         return self.generic_visit(node)\n \n     def visit_Pattern(self, node: FTL.Pattern):\n", "issue": "Pretranslate access keys using the algorithm to extract candidate keys\nFluent Rich editor has a special UI for messages with access keys, which lists access key candidates.\r\n\r\nWe should use the same logic when pretranslating accesskeys and use the first candidate as the translation.\r\n\r\nWe should also take into account #2717.\n", "before_files": [{"content": "from copy import deepcopy\nfrom typing import Callable, Optional, cast\n\nfrom fluent.syntax import ast as FTL\nfrom fluent.syntax.serializer import serialize_expression\nfrom fluent.syntax.visitor import Transformer\n\nfrom pontoon.base.fluent import is_plural_expression\nfrom pontoon.base.models import Locale\n\n\ndef flatten_select_expressions(pattern: FTL.Pattern):\n    \"\"\"\n    If the pattern contains any select expressions,\n    flatten it to only contain select expressions.\n    Leading and trailing elements are copied into each variant,\n    and any single leading or trailing spaces are lifted out of the select expressions.\n    \"\"\"\n\n    def isSelExp(el: FTL.PatternElement):\n        return isinstance(el, FTL.Placeable) and isinstance(\n            el.expression, FTL.SelectExpression\n        )\n\n    def patternStartsWithSpace(pat: list[FTL.PatternElement]):\n        return isinstance(pat[0], FTL.TextElement) and pat[0].value.startswith(\" \")\n\n    def patternEndsWithSpace(pat: list[FTL.PatternElement]):\n        return isinstance(pat[-1], FTL.TextElement) and pat[-1].value.endswith(\" \")\n\n    prev = -1\n    select = None\n    for idx, placeable in filter(lambda x: isSelExp(x[1]), enumerate(pattern.elements)):\n        before = pattern.elements[prev + 1 : idx]\n        if before:\n            select = cast(FTL.SelectExpression, placeable.expression)\n            for variant in select.variants:\n                variant.value.elements[0:0] = deepcopy(before)\n        prev = idx\n    if select:\n        after = pattern.elements[prev + 1 :]\n        if after:\n            for variant in select.variants:\n                variant.value.elements += deepcopy(after)\n\n        res: list[FTL.PatternElement] = []\n        for placeable in filter(isSelExp, pattern.elements):\n            patterns = tuple(\n                map(lambda var: var.value.elements, placeable.expression.variants)\n            )\n\n            # Collect leading spaces\n            if all(map(patternStartsWithSpace, patterns)):\n                res.append(FTL.Placeable(FTL.StringLiteral(\" \")))\n                for pat in patterns:\n                    pat[0].value = pat[0].value[1:]\n\n            res.append(placeable)\n\n            # Collect trailing spaces\n            if all(map(patternEndsWithSpace, patterns)):\n                res.append(FTL.Placeable(FTL.StringLiteral(\" \")))\n                for pat in patterns:\n                    pat[-1].value = pat[-1].value[:-1]\n        pattern.elements = res\n\n\ndef create_locale_plural_variants(node: FTL.SelectExpression, locale: Locale):\n    variants: list[FTL.Variant] = []\n    source_plurals: dict[str, FTL.Variant] = {}\n    default = cast(FTL.Variant, None)\n\n    for variant in node.variants:\n        key = variant.key\n        if isinstance(key, FTL.NumberLiteral):\n            variants.append(variant)\n        else:\n            source_plurals[key.name] = variant\n        if variant.default:\n            default = variant\n\n    for plural in locale.cldr_plurals_list():\n        if plural in source_plurals.keys():\n            variant = source_plurals[plural]\n        else:\n            variant = deepcopy(default)\n            variant.key.name = plural\n        variant.default = False\n        variants.append(variant)\n\n    variants[-1].default = True\n\n    node.variants = variants\n\n\nclass PreparePretranslation(Transformer):\n    \"\"\"\n    Flattens the given Pattern, uplifting selectors to the highest possible level and\n    duplicating shared parts in the variants. Transforms plural variants to match the\n    locale.\n    \"\"\"\n\n    def __init__(self, locale: Locale):\n        self.locale = locale\n\n    def visit_Attribute(self, node: FTL.Attribute):\n        flatten_select_expressions(node.value)\n        return self.generic_visit(node)\n\n    def visit_Message(self, node: FTL.Message):\n        if node.value:\n            flatten_select_expressions(node.value)\n        return self.generic_visit(node)\n\n    def visit_SelectExpression(self, node: FTL.SelectExpression):\n        if is_plural_expression(node):\n            create_locale_plural_variants(node, self.locale)\n        return self.generic_visit(node)\n\n\nclass ApplyPretranslation(Transformer):\n    \"\"\"\n    During `visit()`, calls `callback(source, locale) -> (translation, service)` for each pattern.\n    \"\"\"\n\n    def __init__(\n        self,\n        locale: Locale,\n        entry: FTL.EntryType,\n        callback: Callable[[str, str], tuple[Optional[str], str]],\n    ):\n        prep = PreparePretranslation(locale)\n        prep.visit(entry)\n        self.callback = callback\n        self.locale = locale\n        self.services: list[str] = []\n\n    def visit_Attribute(self, node):\n        if (\n            node.id.name.endswith(\"accesskey\")\n            and not self.locale.accesskey_localization\n        ):\n            return node\n        return self.generic_visit(node)\n\n    def visit_Pattern(self, node: FTL.Pattern):\n        has_selects = False\n        source = \"\"\n        for el in node.elements:\n            if isinstance(el, FTL.TextElement):\n                source += el.value\n            elif isinstance(el.expression, FTL.SelectExpression):\n                self.generic_visit(el.expression)\n                has_selects = True\n            else:\n                source += serialize_expression(el)\n        if not has_selects and source != \"\":\n            # Machine translation treats each line as a separate sentence,\n            # hence we replace newline characters with spaces.\n            source = source.replace(\"\\n\", \" \")\n\n            translation, service = self.callback(source, self.locale)\n            if translation is None:\n                raise ValueError(\n                    f\"Pretranslation for `{source}` to {self.locale.code} not available.\"\n                )\n            node.elements = [FTL.TextElement(translation)]\n            self.services.append(service)\n        return node\n", "path": "pontoon/pretranslation/transformer.py"}], "after_files": [{"content": "import re\n\nfrom copy import deepcopy\nfrom typing import Callable, Optional, cast\n\nfrom fluent.syntax import ast as FTL\nfrom fluent.syntax.serializer import serialize_expression\nfrom fluent.syntax.visitor import Transformer\n\nfrom pontoon.base.fluent import is_plural_expression\nfrom pontoon.base.models import Locale\n\n\ndef flatten_select_expressions(pattern: FTL.Pattern):\n    \"\"\"\n    If the pattern contains any select expressions,\n    flatten it to only contain select expressions.\n    Leading and trailing elements are copied into each variant,\n    and any single leading or trailing spaces are lifted out of the select expressions.\n    \"\"\"\n\n    def isSelExp(el: FTL.PatternElement):\n        return isinstance(el, FTL.Placeable) and isinstance(\n            el.expression, FTL.SelectExpression\n        )\n\n    def patternStartsWithSpace(pat: list[FTL.PatternElement]):\n        return isinstance(pat[0], FTL.TextElement) and pat[0].value.startswith(\" \")\n\n    def patternEndsWithSpace(pat: list[FTL.PatternElement]):\n        return isinstance(pat[-1], FTL.TextElement) and pat[-1].value.endswith(\" \")\n\n    prev = -1\n    select = None\n    for idx, placeable in filter(lambda x: isSelExp(x[1]), enumerate(pattern.elements)):\n        before = pattern.elements[prev + 1 : idx]\n        if before:\n            select = cast(FTL.SelectExpression, placeable.expression)\n            for variant in select.variants:\n                variant.value.elements[0:0] = deepcopy(before)\n        prev = idx\n    if select:\n        after = pattern.elements[prev + 1 :]\n        if after:\n            for variant in select.variants:\n                variant.value.elements += deepcopy(after)\n\n        res: list[FTL.PatternElement] = []\n        for placeable in filter(isSelExp, pattern.elements):\n            patterns = tuple(\n                map(lambda var: var.value.elements, placeable.expression.variants)\n            )\n\n            # Collect leading spaces\n            if all(map(patternStartsWithSpace, patterns)):\n                res.append(FTL.Placeable(FTL.StringLiteral(\" \")))\n                for pat in patterns:\n                    pat[0].value = pat[0].value[1:]\n\n            res.append(placeable)\n\n            # Collect trailing spaces\n            if all(map(patternEndsWithSpace, patterns)):\n                res.append(FTL.Placeable(FTL.StringLiteral(\" \")))\n                for pat in patterns:\n                    pat[-1].value = pat[-1].value[:-1]\n        pattern.elements = res\n\n\ndef create_locale_plural_variants(node: FTL.SelectExpression, locale: Locale):\n    variants: list[FTL.Variant] = []\n    source_plurals: dict[str, FTL.Variant] = {}\n    default = cast(FTL.Variant, None)\n\n    for variant in node.variants:\n        key = variant.key\n        if isinstance(key, FTL.NumberLiteral):\n            variants.append(variant)\n        else:\n            source_plurals[key.name] = variant\n        if variant.default:\n            default = variant\n\n    for plural in locale.cldr_plurals_list():\n        if plural in source_plurals.keys():\n            variant = source_plurals[plural]\n        else:\n            variant = deepcopy(default)\n            variant.key.name = plural\n        variant.default = False\n        variants.append(variant)\n\n    variants[-1].default = True\n\n    node.variants = variants\n\n\ndef extract_accesskey_candidates(message: FTL.Message, label: str, variant_name=None):\n    def get_source(names):\n        for attribute in message.attributes:\n            if attribute.id.name in names:\n                element = attribute.value.elements[0]\n\n                if isinstance(element, FTL.TextElement):\n                    return element.value\n                elif isinstance(element.expression, FTL.SelectExpression):\n                    variants = element.expression.variants\n                    variant = next(\n                        (v for v in variants if v.key.name == variant_name), variants[0]\n                    )\n                    variant_element = variant.value.elements[0]\n\n                    if isinstance(variant_element, FTL.TextElement):\n                        return variant_element.value\n\n        return None\n\n    prefix_end = label.index(\"accesskey\")\n    prefix = label[0:prefix_end]\n\n    # Generate access key candidates:\n    if prefix:\n        # From a prefixed \"label\" attribute\n        name = f\"{prefix}label\"\n        source = get_source([name])\n    else:\n        # From a pre-defined list of attribute names\n        source = get_source([\"label\", \"value\", \"aria-label\"])\n        # From a message value\n        if not source and message.value:\n            source = message.value.elements[0].value\n\n    if not source:\n        return []\n\n    # Exclude placeables (message is flat). See bug 1447103 for details.\n    keys = re.sub(r\"(?s){.*?}|[\\W_]\", \"\", source)\n\n    # Extract unique candidates\n    return list(dict.fromkeys(keys))\n\n\nclass PreparePretranslation(Transformer):\n    \"\"\"\n    Flattens the given Pattern, uplifting selectors to the highest possible level and\n    duplicating shared parts in the variants. Transforms plural variants to match the\n    locale.\n    \"\"\"\n\n    def __init__(self, locale: Locale):\n        self.locale = locale\n\n    def visit_Attribute(self, node: FTL.Attribute):\n        flatten_select_expressions(node.value)\n        return self.generic_visit(node)\n\n    def visit_Message(self, node: FTL.Message):\n        if node.value:\n            flatten_select_expressions(node.value)\n        return self.generic_visit(node)\n\n    def visit_SelectExpression(self, node: FTL.SelectExpression):\n        if is_plural_expression(node):\n            create_locale_plural_variants(node, self.locale)\n        return self.generic_visit(node)\n\n\nclass ApplyPretranslation(Transformer):\n    \"\"\"\n    During `visit()`, calls `callback(source, locale) -> (translation, service)` for each pattern.\n    \"\"\"\n\n    def __init__(\n        self,\n        locale: Locale,\n        entry: FTL.EntryType,\n        callback: Callable[[str, str], tuple[Optional[str], str]],\n    ):\n        prep = PreparePretranslation(locale)\n        prep.visit(entry)\n        self.callback = callback\n        self.entry = entry\n        self.locale = locale\n        self.services: list[str] = []\n\n    def visit_Attribute(self, node: FTL.Pattern):\n        name = node.id.name\n\n        def set_accesskey(element, variant_name=None):\n            if isinstance(element, FTL.TextElement) and len(element.value) <= 1:\n                candidates = extract_accesskey_candidates(\n                    self.entry, name, variant_name\n                )\n                if candidates:\n                    element.value = candidates[0]\n                    return True\n\n        if name.endswith(\"accesskey\"):\n            if self.locale.accesskey_localization:\n                element = node.value.elements[0]\n\n                if set_accesskey(element):\n                    return node\n                elif isinstance(element, FTL.Placeable) and isinstance(\n                    element.expression, FTL.SelectExpression\n                ):\n                    variants = element.expression.variants\n                    processed_variants = 0\n                    for variant in variants:\n                        variant_element = variant.value.elements[0]\n                        if set_accesskey(variant_element, variant.key.name):\n                            processed_variants += 1\n                    if processed_variants == len(variants):\n                        return node\n\n            else:\n                return node\n\n        return self.generic_visit(node)\n\n    def visit_Pattern(self, node: FTL.Pattern):\n        has_selects = False\n        source = \"\"\n        for el in node.elements:\n            if isinstance(el, FTL.TextElement):\n                source += el.value\n            elif isinstance(el.expression, FTL.SelectExpression):\n                self.generic_visit(el.expression)\n                has_selects = True\n            else:\n                source += serialize_expression(el)\n        if not has_selects and source != \"\":\n            # Machine translation treats each line as a separate sentence,\n            # hence we replace newline characters with spaces.\n            source = source.replace(\"\\n\", \" \")\n\n            translation, service = self.callback(source, self.locale)\n            if translation is None:\n                raise ValueError(\n                    f\"Pretranslation for `{source}` to {self.locale.code} not available.\"\n                )\n            node.elements = [FTL.TextElement(translation)]\n            self.services.append(service)\n        return node\n", "path": "pontoon/pretranslation/transformer.py"}]}