We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
App title and description must be available in English
Both can be localized however we don't expect everything to be translated. Because we use English as fallback if a language is not present we should require the English contents in the info.xml


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `nextcloudappstore/core/api/v1/release/parser.py`
Content:
```
1 import re
2 import tarfile  # type: ignore
3 import lxml.etree  # type: ignore
4 from typing import Dict, Any, Tuple, List, Set
5 
6 from nextcloudappstore.core.api.v1.release import ReleaseConfig
7 from nextcloudappstore.core.versioning import pad_max_version, pad_min_version
8 from rest_framework.exceptions import APIException  # type: ignore
9 
10 
11 class MaxSizeAppMetadataXmlException(APIException):
12     pass
13 
14 
15 class InvalidAppMetadataXmlException(APIException):
16     pass
17 
18 
19 class UnsupportedAppArchiveException(APIException):
20     pass
21 
22 
23 class InvalidAppPackageStructureException(APIException):
24     pass
25 
26 
27 class XMLSyntaxError(APIException):
28     pass
29 
30 
31 class GunZipAppMetadataExtractor:
32     def __init__(self, config: ReleaseConfig) -> None:
33         """
34         :argument config the config
35         """
36         self.config = config
37         self.app_folder_regex = re.compile(r'^[a-z]+[a-z_]*(?:/.*)*$')
38 
39     def extract_app_metadata(self, archive_path: str) -> Tuple[str, str]:
40         """
41         Extracts the info.xml from an tar.gz archive
42         :argument archive_path the path to the tar.gz archive
43         :raises InvalidAppPackageStructureException if the first level folder
44         does not equal the app_id or no info.xml file could be found in the
45         appinfo folder
46         :return the info.xml as string
47         """
48         if not tarfile.is_tarfile(archive_path):
49             msg = '%s is not a valid tar.gz archive ' % archive_path
50             raise UnsupportedAppArchiveException(msg)
51 
52         with tarfile.open(archive_path, 'r:gz') as tar:
53             result = self._parse_archive(tar)
54         return result
55 
56     def _parse_archive(self, tar: Any) -> Tuple[str, str]:
57         folders = self._find_app_folders(tar.getnames())
58         if len(folders) > 1:
59             msg = 'More than one possible app folder found'
60             raise InvalidAppPackageStructureException(msg)
61         elif len(folders) == 0:
62             msg = 'No possible app folder found. App folder must contain ' \
63                   'only lowercase ASCII characters or underscores'
64             raise InvalidAppPackageStructureException(msg)
65 
66         app_id = folders.pop()
67         info_path = '%s/appinfo/info.xml' % app_id
68         try:
69             info_member = tar.getmember(info_path)
70             possible_links = [info_member]
71             # its complicated, sometimes there are single members, sometimes
72             # there aren't
73             try:
74                 possible_links.append(tar.getmember(app_id))
75             except KeyError:
76                 pass
77             try:
78                 possible_links.append(tar.getmember('%s/appinfo' % app_id))
79             except KeyError:
80                 pass
81 
82             for possible_link in possible_links:
83                 if possible_link.issym() or possible_link.islnk():
84                     msg = 'Symlinks and hard links can not be used for %s' % \
85                           possible_link
86                     raise InvalidAppPackageStructureException(msg)
87             info_file = tar.extractfile(info_member)
88             contents = self._stream_read_file(info_file,
89                                               self.config.max_info_size)
90             return contents, app_id
91         except KeyError:
92             msg = 'Could not find %s file inside the archive' % info_path
93             raise InvalidAppPackageStructureException(msg)
94 
95     def _stream_read_file(self, info_file: Any, max_info_size: int) -> str:
96         """
97         Instead of reading everything in one go which is vulnerable to
98         zip bombs, stream and accumulate the bytes
99         :argument info_file: buffered io reader
100         :argument max_info_size: maximum file size in bytes
101         :raises MaxSizeAppMetadataXmlException if the maximum size was reached
102         :return: the parsed info.xml
103         """
104         # FIXME: If someone finds a less ugly version, please feel free to
105         #        improve it
106         size = 0
107         result = b''
108         while True:
109             size += 1024
110             if size > max_info_size:
111                 msg = 'info.xml was bigger than allowed %i bytes' % \
112                       max_info_size
113                 raise MaxSizeAppMetadataXmlException(msg)
114 
115             chunk = info_file.read(1024)
116             if not chunk:
117                 break
118             result += chunk
119 
120         return result.decode('utf-8')
121 
122     def _find_app_folders(self, members: List[str]) -> Set[str]:
123         regex = self.app_folder_regex
124         matching_members = filter(lambda f: re.match(regex, f), members)
125         folders = map(lambda m: m.split('/')[0], matching_members)
126         return set(folders)
127 
128 
129 def element_to_dict(element: Any) -> Dict:
130     type = element.get('type')
131     key = element.tag.replace('-', '_')
132     if type == 'int':
133         return {key: int(element.text)}
134     elif type == 'list':
135         return {key: list(map(element_to_dict, element.iterchildren()))}
136     elif type == 'min-version':
137         return {key: pad_min_version(element.text)}
138     elif type == 'max-version':
139         return {key: pad_max_version(element.text)}
140     elif len(list(element)) > 0:
141         contents = {}
142         for child in element.iterchildren():
143             contents.update(element_to_dict(child))
144         return {key: contents}
145     else:
146         return {key: element.text}
147 
148 
149 def parse_app_metadata(xml: str, schema: str, pre_xslt: str,
150                        xslt: str) -> Dict:
151     """
152     Parses, validates and maps the xml onto a dict
153     :argument xml the info.xml string to parse
154     :argument schema the schema xml as string
155     :argument pre_xslt xslt which is run before validation to ensure that
156     everything is in the correct order and that unknown elements are excluded
157     :argument xslt the xslt to transform it to a matching structure
158     :raises InvalidAppMetadataXmlException if the schema does not validate
159     :return the parsed xml as dict
160     """
161     parser = lxml.etree.XMLParser(resolve_entities=False, no_network=True,
162                                   remove_comments=True, load_dtd=False,
163                                   remove_blank_text=True, dtd_validation=False
164                                   )
165     try:
166         doc = lxml.etree.fromstring(bytes(xml, encoding='utf-8'), parser)
167     except lxml.etree.XMLSyntaxError as e:
168         msg = 'info.xml contains malformed xml: %s' % e
169         raise XMLSyntaxError(msg)
170     for _ in doc.iter(lxml.etree.Entity):
171         raise InvalidAppMetadataXmlException('Must not contain entities')
172     pre_transform = lxml.etree.XSLT(lxml.etree.XML(pre_xslt))
173     pre_transformed_doc = pre_transform(doc)
174     schema_doc = lxml.etree.fromstring(bytes(schema, encoding='utf-8'), parser)
175     schema = lxml.etree.XMLSchema(schema_doc)
176     try:
177         schema.assertValid(pre_transformed_doc)  # type: ignore
178     except lxml.etree.DocumentInvalid as e:
179         msg = 'info.xml did not validate: %s' % e
180         raise InvalidAppMetadataXmlException(msg)
181     transform = lxml.etree.XSLT(lxml.etree.XML(xslt))
182     transformed_doc = transform(pre_transformed_doc)
183     mapped = element_to_dict(transformed_doc.getroot())
184     return mapped
185
```
--- 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/nextcloudappstore/core/api/v1/release/parser.py b/nextcloudappstore/core/api/v1/release/parser.py
--- a/nextcloudappstore/core/api/v1/release/parser.py
+++ b/nextcloudappstore/core/api/v1/release/parser.py
@@ -181,4 +181,20 @@
     transform = lxml.etree.XSLT(lxml.etree.XML(xslt))
     transformed_doc = transform(pre_transformed_doc)
     mapped = element_to_dict(transformed_doc.getroot())
+    validate_english_present(mapped)
     return mapped
+
+
+def validate_english_present(info: Dict) -> None:
+    """
+    Validates that name, summary and description are present in english
+    :param info: the parsed xml
+    :raises: InvalidAppMetadataXmlException if at least one of the required
+     fields is not present in english
+    """
+    app = info['app']
+    translated_fields = ['name', 'summary', 'description']
+    for field in translated_fields:
+        if 'en' not in app[field]:
+            msg = 'At least one element "%s" with lang "en" required' % field
+            raise InvalidAppMetadataXmlException(msg)

{"golden_diff": "diff --git a/nextcloudappstore/core/api/v1/release/parser.py b/nextcloudappstore/core/api/v1/release/parser.py\n--- a/nextcloudappstore/core/api/v1/release/parser.py\n+++ b/nextcloudappstore/core/api/v1/release/parser.py\n@@ -181,4 +181,20 @@\n     transform = lxml.etree.XSLT(lxml.etree.XML(xslt))\n     transformed_doc = transform(pre_transformed_doc)\n     mapped = element_to_dict(transformed_doc.getroot())\n+    validate_english_present(mapped)\n     return mapped\n+\n+\n+def validate_english_present(info: Dict) -> None:\n+    \"\"\"\n+    Validates that name, summary and description are present in english\n+    :param info: the parsed xml\n+    :raises: InvalidAppMetadataXmlException if at least one of the required\n+     fields is not present in english\n+    \"\"\"\n+    app = info['app']\n+    translated_fields = ['name', 'summary', 'description']\n+    for field in translated_fields:\n+        if 'en' not in app[field]:\n+            msg = 'At least one element \"%s\" with lang \"en\" required' % field\n+            raise InvalidAppMetadataXmlException(msg)\n", "issue": "App title and description must be available in English\nBoth can be localized however we don't expect everything to be translated. Because we use English as fallback if a language is not present we should require the English contents in the info.xml\n\n", "before_files": [{"content": "import re\nimport tarfile  # type: ignore\nimport lxml.etree  # type: ignore\nfrom typing import Dict, Any, Tuple, List, Set\n\nfrom nextcloudappstore.core.api.v1.release import ReleaseConfig\nfrom nextcloudappstore.core.versioning import pad_max_version, pad_min_version\nfrom rest_framework.exceptions import APIException  # type: ignore\n\n\nclass MaxSizeAppMetadataXmlException(APIException):\n    pass\n\n\nclass InvalidAppMetadataXmlException(APIException):\n    pass\n\n\nclass UnsupportedAppArchiveException(APIException):\n    pass\n\n\nclass InvalidAppPackageStructureException(APIException):\n    pass\n\n\nclass XMLSyntaxError(APIException):\n    pass\n\n\nclass GunZipAppMetadataExtractor:\n    def __init__(self, config: ReleaseConfig) -> None:\n        \"\"\"\n        :argument config the config\n        \"\"\"\n        self.config = config\n        self.app_folder_regex = re.compile(r'^[a-z]+[a-z_]*(?:/.*)*$')\n\n    def extract_app_metadata(self, archive_path: str) -> Tuple[str, str]:\n        \"\"\"\n        Extracts the info.xml from an tar.gz archive\n        :argument archive_path the path to the tar.gz archive\n        :raises InvalidAppPackageStructureException if the first level folder\n        does not equal the app_id or no info.xml file could be found in the\n        appinfo folder\n        :return the info.xml as string\n        \"\"\"\n        if not tarfile.is_tarfile(archive_path):\n            msg = '%s is not a valid tar.gz archive ' % archive_path\n            raise UnsupportedAppArchiveException(msg)\n\n        with tarfile.open(archive_path, 'r:gz') as tar:\n            result = self._parse_archive(tar)\n        return result\n\n    def _parse_archive(self, tar: Any) -> Tuple[str, str]:\n        folders = self._find_app_folders(tar.getnames())\n        if len(folders) > 1:\n            msg = 'More than one possible app folder found'\n            raise InvalidAppPackageStructureException(msg)\n        elif len(folders) == 0:\n            msg = 'No possible app folder found. App folder must contain ' \\\n                  'only lowercase ASCII characters or underscores'\n            raise InvalidAppPackageStructureException(msg)\n\n        app_id = folders.pop()\n        info_path = '%s/appinfo/info.xml' % app_id\n        try:\n            info_member = tar.getmember(info_path)\n            possible_links = [info_member]\n            # its complicated, sometimes there are single members, sometimes\n            # there aren't\n            try:\n                possible_links.append(tar.getmember(app_id))\n            except KeyError:\n                pass\n            try:\n                possible_links.append(tar.getmember('%s/appinfo' % app_id))\n            except KeyError:\n                pass\n\n            for possible_link in possible_links:\n                if possible_link.issym() or possible_link.islnk():\n                    msg = 'Symlinks and hard links can not be used for %s' % \\\n                          possible_link\n                    raise InvalidAppPackageStructureException(msg)\n            info_file = tar.extractfile(info_member)\n            contents = self._stream_read_file(info_file,\n                                              self.config.max_info_size)\n            return contents, app_id\n        except KeyError:\n            msg = 'Could not find %s file inside the archive' % info_path\n            raise InvalidAppPackageStructureException(msg)\n\n    def _stream_read_file(self, info_file: Any, max_info_size: int) -> str:\n        \"\"\"\n        Instead of reading everything in one go which is vulnerable to\n        zip bombs, stream and accumulate the bytes\n        :argument info_file: buffered io reader\n        :argument max_info_size: maximum file size in bytes\n        :raises MaxSizeAppMetadataXmlException if the maximum size was reached\n        :return: the parsed info.xml\n        \"\"\"\n        # FIXME: If someone finds a less ugly version, please feel free to\n        #        improve it\n        size = 0\n        result = b''\n        while True:\n            size += 1024\n            if size > max_info_size:\n                msg = 'info.xml was bigger than allowed %i bytes' % \\\n                      max_info_size\n                raise MaxSizeAppMetadataXmlException(msg)\n\n            chunk = info_file.read(1024)\n            if not chunk:\n                break\n            result += chunk\n\n        return result.decode('utf-8')\n\n    def _find_app_folders(self, members: List[str]) -> Set[str]:\n        regex = self.app_folder_regex\n        matching_members = filter(lambda f: re.match(regex, f), members)\n        folders = map(lambda m: m.split('/')[0], matching_members)\n        return set(folders)\n\n\ndef element_to_dict(element: Any) -> Dict:\n    type = element.get('type')\n    key = element.tag.replace('-', '_')\n    if type == 'int':\n        return {key: int(element.text)}\n    elif type == 'list':\n        return {key: list(map(element_to_dict, element.iterchildren()))}\n    elif type == 'min-version':\n        return {key: pad_min_version(element.text)}\n    elif type == 'max-version':\n        return {key: pad_max_version(element.text)}\n    elif len(list(element)) > 0:\n        contents = {}\n        for child in element.iterchildren():\n            contents.update(element_to_dict(child))\n        return {key: contents}\n    else:\n        return {key: element.text}\n\n\ndef parse_app_metadata(xml: str, schema: str, pre_xslt: str,\n                       xslt: str) -> Dict:\n    \"\"\"\n    Parses, validates and maps the xml onto a dict\n    :argument xml the info.xml string to parse\n    :argument schema the schema xml as string\n    :argument pre_xslt xslt which is run before validation to ensure that\n    everything is in the correct order and that unknown elements are excluded\n    :argument xslt the xslt to transform it to a matching structure\n    :raises InvalidAppMetadataXmlException if the schema does not validate\n    :return the parsed xml as dict\n    \"\"\"\n    parser = lxml.etree.XMLParser(resolve_entities=False, no_network=True,\n                                  remove_comments=True, load_dtd=False,\n                                  remove_blank_text=True, dtd_validation=False\n                                  )\n    try:\n        doc = lxml.etree.fromstring(bytes(xml, encoding='utf-8'), parser)\n    except lxml.etree.XMLSyntaxError as e:\n        msg = 'info.xml contains malformed xml: %s' % e\n        raise XMLSyntaxError(msg)\n    for _ in doc.iter(lxml.etree.Entity):\n        raise InvalidAppMetadataXmlException('Must not contain entities')\n    pre_transform = lxml.etree.XSLT(lxml.etree.XML(pre_xslt))\n    pre_transformed_doc = pre_transform(doc)\n    schema_doc = lxml.etree.fromstring(bytes(schema, encoding='utf-8'), parser)\n    schema = lxml.etree.XMLSchema(schema_doc)\n    try:\n        schema.assertValid(pre_transformed_doc)  # type: ignore\n    except lxml.etree.DocumentInvalid as e:\n        msg = 'info.xml did not validate: %s' % e\n        raise InvalidAppMetadataXmlException(msg)\n    transform = lxml.etree.XSLT(lxml.etree.XML(xslt))\n    transformed_doc = transform(pre_transformed_doc)\n    mapped = element_to_dict(transformed_doc.getroot())\n    return mapped\n", "path": "nextcloudappstore/core/api/v1/release/parser.py"}], "after_files": [{"content": "import re\nimport tarfile  # type: ignore\nimport lxml.etree  # type: ignore\nfrom typing import Dict, Any, Tuple, List, Set\n\nfrom nextcloudappstore.core.api.v1.release import ReleaseConfig\nfrom nextcloudappstore.core.versioning import pad_max_version, pad_min_version\nfrom rest_framework.exceptions import APIException  # type: ignore\n\n\nclass MaxSizeAppMetadataXmlException(APIException):\n    pass\n\n\nclass InvalidAppMetadataXmlException(APIException):\n    pass\n\n\nclass UnsupportedAppArchiveException(APIException):\n    pass\n\n\nclass InvalidAppPackageStructureException(APIException):\n    pass\n\n\nclass XMLSyntaxError(APIException):\n    pass\n\n\nclass GunZipAppMetadataExtractor:\n    def __init__(self, config: ReleaseConfig) -> None:\n        \"\"\"\n        :argument config the config\n        \"\"\"\n        self.config = config\n        self.app_folder_regex = re.compile(r'^[a-z]+[a-z_]*(?:/.*)*$')\n\n    def extract_app_metadata(self, archive_path: str) -> Tuple[str, str]:\n        \"\"\"\n        Extracts the info.xml from an tar.gz archive\n        :argument archive_path the path to the tar.gz archive\n        :raises InvalidAppPackageStructureException if the first level folder\n        does not equal the app_id or no info.xml file could be found in the\n        appinfo folder\n        :return the info.xml as string\n        \"\"\"\n        if not tarfile.is_tarfile(archive_path):\n            msg = '%s is not a valid tar.gz archive ' % archive_path\n            raise UnsupportedAppArchiveException(msg)\n\n        with tarfile.open(archive_path, 'r:gz') as tar:\n            result = self._parse_archive(tar)\n        return result\n\n    def _parse_archive(self, tar: Any) -> Tuple[str, str]:\n        folders = self._find_app_folders(tar.getnames())\n        if len(folders) > 1:\n            msg = 'More than one possible app folder found'\n            raise InvalidAppPackageStructureException(msg)\n        elif len(folders) == 0:\n            msg = 'No possible app folder found. App folder must contain ' \\\n                  'only lowercase ASCII characters or underscores'\n            raise InvalidAppPackageStructureException(msg)\n\n        app_id = folders.pop()\n        info_path = '%s/appinfo/info.xml' % app_id\n        try:\n            info_member = tar.getmember(info_path)\n            possible_links = [info_member]\n            # its complicated, sometimes there are single members, sometimes\n            # there aren't\n            try:\n                possible_links.append(tar.getmember(app_id))\n            except KeyError:\n                pass\n            try:\n                possible_links.append(tar.getmember('%s/appinfo' % app_id))\n            except KeyError:\n                pass\n\n            for possible_link in possible_links:\n                if possible_link.issym() or possible_link.islnk():\n                    msg = 'Symlinks and hard links can not be used for %s' % \\\n                          possible_link\n                    raise InvalidAppPackageStructureException(msg)\n            info_file = tar.extractfile(info_member)\n            contents = self._stream_read_file(info_file,\n                                              self.config.max_info_size)\n            return contents, app_id\n        except KeyError:\n            msg = 'Could not find %s file inside the archive' % info_path\n            raise InvalidAppPackageStructureException(msg)\n\n    def _stream_read_file(self, info_file: Any, max_info_size: int) -> str:\n        \"\"\"\n        Instead of reading everything in one go which is vulnerable to\n        zip bombs, stream and accumulate the bytes\n        :argument info_file: buffered io reader\n        :argument max_info_size: maximum file size in bytes\n        :raises MaxSizeAppMetadataXmlException if the maximum size was reached\n        :return: the parsed info.xml\n        \"\"\"\n        # FIXME: If someone finds a less ugly version, please feel free to\n        #        improve it\n        size = 0\n        result = b''\n        while True:\n            size += 1024\n            if size > max_info_size:\n                msg = 'info.xml was bigger than allowed %i bytes' % \\\n                      max_info_size\n                raise MaxSizeAppMetadataXmlException(msg)\n\n            chunk = info_file.read(1024)\n            if not chunk:\n                break\n            result += chunk\n\n        return result.decode('utf-8')\n\n    def _find_app_folders(self, members: List[str]) -> Set[str]:\n        regex = self.app_folder_regex\n        matching_members = filter(lambda f: re.match(regex, f), members)\n        folders = map(lambda m: m.split('/')[0], matching_members)\n        return set(folders)\n\n\ndef element_to_dict(element: Any) -> Dict:\n    type = element.get('type')\n    key = element.tag.replace('-', '_')\n    if type == 'int':\n        return {key: int(element.text)}\n    elif type == 'list':\n        return {key: list(map(element_to_dict, element.iterchildren()))}\n    elif type == 'min-version':\n        return {key: pad_min_version(element.text)}\n    elif type == 'max-version':\n        return {key: pad_max_version(element.text)}\n    elif len(list(element)) > 0:\n        contents = {}\n        for child in element.iterchildren():\n            contents.update(element_to_dict(child))\n        return {key: contents}\n    else:\n        return {key: element.text}\n\n\ndef parse_app_metadata(xml: str, schema: str, pre_xslt: str,\n                       xslt: str) -> Dict:\n    \"\"\"\n    Parses, validates and maps the xml onto a dict\n    :argument xml the info.xml string to parse\n    :argument schema the schema xml as string\n    :argument pre_xslt xslt which is run before validation to ensure that\n    everything is in the correct order and that unknown elements are excluded\n    :argument xslt the xslt to transform it to a matching structure\n    :raises InvalidAppMetadataXmlException if the schema does not validate\n    :return the parsed xml as dict\n    \"\"\"\n    parser = lxml.etree.XMLParser(resolve_entities=False, no_network=True,\n                                  remove_comments=True, load_dtd=False,\n                                  remove_blank_text=True, dtd_validation=False\n                                  )\n    try:\n        doc = lxml.etree.fromstring(bytes(xml, encoding='utf-8'), parser)\n    except lxml.etree.XMLSyntaxError as e:\n        msg = 'info.xml contains malformed xml: %s' % e\n        raise XMLSyntaxError(msg)\n    for _ in doc.iter(lxml.etree.Entity):\n        raise InvalidAppMetadataXmlException('Must not contain entities')\n    pre_transform = lxml.etree.XSLT(lxml.etree.XML(pre_xslt))\n    pre_transformed_doc = pre_transform(doc)\n    schema_doc = lxml.etree.fromstring(bytes(schema, encoding='utf-8'), parser)\n    schema = lxml.etree.XMLSchema(schema_doc)\n    try:\n        schema.assertValid(pre_transformed_doc)  # type: ignore\n    except lxml.etree.DocumentInvalid as e:\n        msg = 'info.xml did not validate: %s' % e\n        raise InvalidAppMetadataXmlException(msg)\n    transform = lxml.etree.XSLT(lxml.etree.XML(xslt))\n    transformed_doc = transform(pre_transformed_doc)\n    mapped = element_to_dict(transformed_doc.getroot())\n    validate_english_present(mapped)\n    return mapped\n\n\ndef validate_english_present(info: Dict) -> None:\n    \"\"\"\n    Validates that name, summary and description are present in english\n    :param info: the parsed xml\n    :raises: InvalidAppMetadataXmlException if at least one of the required\n     fields is not present in english\n    \"\"\"\n    app = info['app']\n    translated_fields = ['name', 'summary', 'description']\n    for field in translated_fields:\n        if 'en' not in app[field]:\n            msg = 'At least one element \"%s\" with lang \"en\" required' % field\n            raise InvalidAppMetadataXmlException(msg)\n", "path": "nextcloudappstore/core/api/v1/release/parser.py"}]}