prompt: 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()
  
  ```
  
golden_diff: 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):
  
verification_info: {"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"}]}