We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[1.5.0rc1] Error on translation upload
#### What were you doing?

Uploading a translation file, attached.

[OctoPrint.1.5.0rc1.-.Pack.Langue.FR.zip](https://github.com/OctoPrint/OctoPrint/files/5540089/OctoPrint.1.5.0rc1.-.Pack.Langue.FR.zip)

#### What did you expect to happen?

File to upload and translation to be available.

#### What happened instead?

Nothing

#### Did the same happen when running OctoPrint in safe mode?

Yes

#### Version of OctoPrint

1.5.0rc1

#### Operating System running OctoPrint

octopi 0.18 nightly

#### Printer model & used firmware incl. version

N/A

#### Browser and version of browser, operating system running browser

Google Chrome Version 86.0.4240.198 (Official Build) (64-bit) on Windows 10

#### Link to octoprint.log

[octoprint.log](https://github.com/OctoPrint/OctoPrint/files/5540091/octoprint.log)

#### Link to contents of terminal tab or serial.log

N/A

#### Link to contents of Javascript console in the browser

Just a 500 Server error warning.

#### Screenshot(s)/video(s) showing the problem:

I have read the FAQ.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/octoprint/server/api/languages.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 from __future__ import absolute_import, division, print_function, unicode_literals
3 
4 __author__ = "Gina Häußge <osd@foosel.net>"
5 __license__ = "GNU Affero General Public License http://www.gnu.org/licenses/agpl.html"
6 __copyright__ = "Copyright (C) 2015 The OctoPrint Project - Released under terms of the AGPLv3 License"
7 
8 import io
9 import logging
10 import os
11 import tarfile
12 import zipfile
13 
14 try:
15     from os import scandir
16 except ImportError:
17     from scandir import scandir
18 
19 from collections import defaultdict
20 
21 from flask import jsonify, make_response, request
22 from flask_babel import Locale
23 
24 from octoprint.access.permissions import Permissions
25 from octoprint.plugin import plugin_manager
26 from octoprint.server.api import api
27 from octoprint.server.util.flask import no_firstrun_access
28 from octoprint.settings import settings
29 
30 
31 @api.route("/languages", methods=["GET"])
32 @no_firstrun_access
33 @Permissions.SETTINGS.require(403)
34 def getInstalledLanguagePacks():
35     translation_folder = settings().getBaseFolder("translations", check_writable=False)
36     if not os.path.exists(translation_folder):
37         return jsonify(language_packs={"_core": []})
38 
39     core_packs = []
40     plugin_packs = defaultdict(
41         lambda: {"identifier": None, "display": None, "languages": []}
42     )
43     for entry in scandir(translation_folder):
44         if not entry.is_dir():
45             continue
46 
47         def load_meta(path, locale):
48             meta = {}
49 
50             meta_path = os.path.join(path, "meta.yaml")
51             if os.path.isfile(meta_path):
52                 import yaml
53 
54                 try:
55                     with io.open(meta_path, "rt", encoding="utf-8") as f:
56                         meta = yaml.safe_load(f)
57                 except Exception:
58                     logging.getLogger(__name__).exception("Could not load %s", meta_path)
59                     pass
60                 else:
61                     import datetime
62 
63                     if "last_update" in meta and isinstance(
64                         meta["last_update"], datetime.datetime
65                     ):
66                         meta["last_update"] = (
67                             meta["last_update"] - datetime.datetime(1970, 1, 1)
68                         ).total_seconds()
69 
70             loc = Locale.parse(locale)
71             meta["locale"] = locale
72             meta["locale_display"] = loc.display_name
73             meta["locale_english"] = loc.english_name
74             return meta
75 
76         if entry.name == "_plugins":
77             for plugin_entry in scandir(entry.path):
78                 if not plugin_entry.is_dir():
79                     continue
80 
81                 if plugin_entry.name not in plugin_manager().plugins:
82                     continue
83 
84                 plugin_info = plugin_manager().plugins[plugin_entry.name]
85 
86                 plugin_packs[plugin_entry.name]["identifier"] = plugin_entry.name
87                 plugin_packs[plugin_entry.name]["display"] = plugin_info.name
88 
89                 for language_entry in scandir(plugin_entry.path):
90                     try:
91                         plugin_packs[plugin_entry.name]["languages"].append(
92                             load_meta(language_entry.path, language_entry.name)
93                         )
94                     except Exception:
95                         logging.getLogger(__name__).exception(
96                             "Error while parsing metadata for language pack {} from {} for plugin {}".format(
97                                 language_entry.name,
98                                 language_entry.path,
99                                 plugin_entry.name,
100                             )
101                         )
102                         continue
103         else:
104             try:
105                 core_packs.append(load_meta(entry.path, entry.name))
106             except ValueError:
107                 logging.getLogger(__name__).exception(
108                     "Core language pack {} doesn't appear to actually be one".format(
109                         entry.name
110                     )
111                 )
112             except Exception:
113                 logging.getLogger(__name__).exception(
114                     "Error while parsing metadata for core language pack {} from {}".format(
115                         entry.name, entry.path
116                     )
117                 )
118 
119     result = {
120         "_core": {"identifier": "_core", "display": "Core", "languages": core_packs}
121     }
122     result.update(plugin_packs)
123     return jsonify(language_packs=result)
124 
125 
126 @api.route("/languages", methods=["POST"])
127 @no_firstrun_access
128 @Permissions.SETTINGS.require(403)
129 def uploadLanguagePack():
130     input_name = "file"
131     input_upload_path = (
132         input_name + "." + settings().get(["server", "uploads", "pathSuffix"])
133     )
134     input_upload_name = (
135         input_name + "." + settings().get(["server", "uploads", "nameSuffix"])
136     )
137     if input_upload_path not in request.values or input_upload_name not in request.values:
138         return make_response("No file included", 400)
139 
140     upload_name = request.values[input_upload_name]
141     upload_path = request.values[input_upload_path]
142 
143     exts = filter(
144         lambda x: upload_name.lower().endswith(x), (".zip", ".tar.gz", ".tgz", ".tar")
145     )
146     if not len(exts):
147         return make_response(
148             "File doesn't have a valid extension for a language pack archive", 400
149         )
150 
151     target_path = settings().getBaseFolder("translations")
152 
153     if tarfile.is_tarfile(upload_path):
154         _unpack_uploaded_tarball(upload_path, target_path)
155     elif zipfile.is_zipfile(upload_path):
156         _unpack_uploaded_zipfile(upload_path, target_path)
157     else:
158         return make_response("Neither zip file nor tarball included", 400)
159 
160     return getInstalledLanguagePacks()
161 
162 
163 @api.route("/languages/<string:locale>/<string:pack>", methods=["DELETE"])
164 @no_firstrun_access
165 @Permissions.SETTINGS.require(403)
166 def deleteInstalledLanguagePack(locale, pack):
167 
168     if pack == "_core":
169         target_path = os.path.join(settings().getBaseFolder("translations"), locale)
170     else:
171         target_path = os.path.join(
172             settings().getBaseFolder("translations"), "_plugins", pack, locale
173         )
174 
175     if os.path.isdir(target_path):
176         import shutil
177 
178         shutil.rmtree(target_path)
179 
180     return getInstalledLanguagePacks()
181 
182 
183 def _unpack_uploaded_zipfile(path, target):
184     with zipfile.ZipFile(path, "r") as zip:
185         # sanity check
186         map(_validate_archive_name, zip.namelist())
187 
188         # unpack everything
189         zip.extractall(target)
190 
191 
192 def _unpack_uploaded_tarball(path, target):
193     with tarfile.open(path, "r") as tar:
194         # sanity check
195         map(_validate_archive_name, tar.getmembers())
196 
197         # unpack everything
198         tar.extractall(target)
199 
200 
201 def _validate_archive_name(name):
202     if name.startswith("/") or ".." in name:
203         raise InvalidLanguagePack(
204             "Provided language pack contains invalid name {name}".format(**locals())
205         )
206 
207 
208 class InvalidLanguagePack(Exception):
209     pass
210
```
--- 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/src/octoprint/server/api/languages.py b/src/octoprint/server/api/languages.py
--- a/src/octoprint/server/api/languages.py
+++ b/src/octoprint/server/api/languages.py
@@ -140,8 +140,10 @@
     upload_name = request.values[input_upload_name]
     upload_path = request.values[input_upload_path]
 
-    exts = filter(
-        lambda x: upload_name.lower().endswith(x), (".zip", ".tar.gz", ".tgz", ".tar")
+    exts = list(
+        filter(
+            lambda x: upload_name.lower().endswith(x), (".zip", ".tar.gz", ".tgz", ".tar")
+        )
     )
     if not len(exts):
         return make_response(

{"golden_diff": "diff --git a/src/octoprint/server/api/languages.py b/src/octoprint/server/api/languages.py\n--- a/src/octoprint/server/api/languages.py\n+++ b/src/octoprint/server/api/languages.py\n@@ -140,8 +140,10 @@\n     upload_name = request.values[input_upload_name]\n     upload_path = request.values[input_upload_path]\n \n-    exts = filter(\n-        lambda x: upload_name.lower().endswith(x), (\".zip\", \".tar.gz\", \".tgz\", \".tar\")\n+    exts = list(\n+        filter(\n+            lambda x: upload_name.lower().endswith(x), (\".zip\", \".tar.gz\", \".tgz\", \".tar\")\n+        )\n     )\n     if not len(exts):\n         return make_response(\n", "issue": "[1.5.0rc1] Error on translation upload\n#### What were you doing?\r\n\r\nUploading a translation file, attached.\r\n\r\n[OctoPrint.1.5.0rc1.-.Pack.Langue.FR.zip](https://github.com/OctoPrint/OctoPrint/files/5540089/OctoPrint.1.5.0rc1.-.Pack.Langue.FR.zip)\r\n\r\n#### What did you expect to happen?\r\n\r\nFile to upload and translation to be available.\r\n\r\n#### What happened instead?\r\n\r\nNothing\r\n\r\n#### Did the same happen when running OctoPrint in safe mode?\r\n\r\nYes\r\n\r\n#### Version of OctoPrint\r\n\r\n1.5.0rc1\r\n\r\n#### Operating System running OctoPrint\r\n\r\noctopi 0.18 nightly\r\n\r\n#### Printer model & used firmware incl. version\r\n\r\nN/A\r\n\r\n#### Browser and version of browser, operating system running browser\r\n\r\nGoogle Chrome Version 86.0.4240.198 (Official Build) (64-bit) on Windows 10\r\n\r\n#### Link to octoprint.log\r\n\r\n[octoprint.log](https://github.com/OctoPrint/OctoPrint/files/5540091/octoprint.log)\r\n\r\n#### Link to contents of terminal tab or serial.log\r\n\r\nN/A\r\n\r\n#### Link to contents of Javascript console in the browser\r\n\r\nJust a 500 Server error warning.\r\n\r\n#### Screenshot(s)/video(s) showing the problem:\r\n\r\nI have read the FAQ.\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\n__author__ = \"Gina H\u00e4u\u00dfge <osd@foosel.net>\"\n__license__ = \"GNU Affero General Public License http://www.gnu.org/licenses/agpl.html\"\n__copyright__ = \"Copyright (C) 2015 The OctoPrint Project - Released under terms of the AGPLv3 License\"\n\nimport io\nimport logging\nimport os\nimport tarfile\nimport zipfile\n\ntry:\n    from os import scandir\nexcept ImportError:\n    from scandir import scandir\n\nfrom collections import defaultdict\n\nfrom flask import jsonify, make_response, request\nfrom flask_babel import Locale\n\nfrom octoprint.access.permissions import Permissions\nfrom octoprint.plugin import plugin_manager\nfrom octoprint.server.api import api\nfrom octoprint.server.util.flask import no_firstrun_access\nfrom octoprint.settings import settings\n\n\n@api.route(\"/languages\", methods=[\"GET\"])\n@no_firstrun_access\n@Permissions.SETTINGS.require(403)\ndef getInstalledLanguagePacks():\n    translation_folder = settings().getBaseFolder(\"translations\", check_writable=False)\n    if not os.path.exists(translation_folder):\n        return jsonify(language_packs={\"_core\": []})\n\n    core_packs = []\n    plugin_packs = defaultdict(\n        lambda: {\"identifier\": None, \"display\": None, \"languages\": []}\n    )\n    for entry in scandir(translation_folder):\n        if not entry.is_dir():\n            continue\n\n        def load_meta(path, locale):\n            meta = {}\n\n            meta_path = os.path.join(path, \"meta.yaml\")\n            if os.path.isfile(meta_path):\n                import yaml\n\n                try:\n                    with io.open(meta_path, \"rt\", encoding=\"utf-8\") as f:\n                        meta = yaml.safe_load(f)\n                except Exception:\n                    logging.getLogger(__name__).exception(\"Could not load %s\", meta_path)\n                    pass\n                else:\n                    import datetime\n\n                    if \"last_update\" in meta and isinstance(\n                        meta[\"last_update\"], datetime.datetime\n                    ):\n                        meta[\"last_update\"] = (\n                            meta[\"last_update\"] - datetime.datetime(1970, 1, 1)\n                        ).total_seconds()\n\n            loc = Locale.parse(locale)\n            meta[\"locale\"] = locale\n            meta[\"locale_display\"] = loc.display_name\n            meta[\"locale_english\"] = loc.english_name\n            return meta\n\n        if entry.name == \"_plugins\":\n            for plugin_entry in scandir(entry.path):\n                if not plugin_entry.is_dir():\n                    continue\n\n                if plugin_entry.name not in plugin_manager().plugins:\n                    continue\n\n                plugin_info = plugin_manager().plugins[plugin_entry.name]\n\n                plugin_packs[plugin_entry.name][\"identifier\"] = plugin_entry.name\n                plugin_packs[plugin_entry.name][\"display\"] = plugin_info.name\n\n                for language_entry in scandir(plugin_entry.path):\n                    try:\n                        plugin_packs[plugin_entry.name][\"languages\"].append(\n                            load_meta(language_entry.path, language_entry.name)\n                        )\n                    except Exception:\n                        logging.getLogger(__name__).exception(\n                            \"Error while parsing metadata for language pack {} from {} for plugin {}\".format(\n                                language_entry.name,\n                                language_entry.path,\n                                plugin_entry.name,\n                            )\n                        )\n                        continue\n        else:\n            try:\n                core_packs.append(load_meta(entry.path, entry.name))\n            except ValueError:\n                logging.getLogger(__name__).exception(\n                    \"Core language pack {} doesn't appear to actually be one\".format(\n                        entry.name\n                    )\n                )\n            except Exception:\n                logging.getLogger(__name__).exception(\n                    \"Error while parsing metadata for core language pack {} from {}\".format(\n                        entry.name, entry.path\n                    )\n                )\n\n    result = {\n        \"_core\": {\"identifier\": \"_core\", \"display\": \"Core\", \"languages\": core_packs}\n    }\n    result.update(plugin_packs)\n    return jsonify(language_packs=result)\n\n\n@api.route(\"/languages\", methods=[\"POST\"])\n@no_firstrun_access\n@Permissions.SETTINGS.require(403)\ndef uploadLanguagePack():\n    input_name = \"file\"\n    input_upload_path = (\n        input_name + \".\" + settings().get([\"server\", \"uploads\", \"pathSuffix\"])\n    )\n    input_upload_name = (\n        input_name + \".\" + settings().get([\"server\", \"uploads\", \"nameSuffix\"])\n    )\n    if input_upload_path not in request.values or input_upload_name not in request.values:\n        return make_response(\"No file included\", 400)\n\n    upload_name = request.values[input_upload_name]\n    upload_path = request.values[input_upload_path]\n\n    exts = filter(\n        lambda x: upload_name.lower().endswith(x), (\".zip\", \".tar.gz\", \".tgz\", \".tar\")\n    )\n    if not len(exts):\n        return make_response(\n            \"File doesn't have a valid extension for a language pack archive\", 400\n        )\n\n    target_path = settings().getBaseFolder(\"translations\")\n\n    if tarfile.is_tarfile(upload_path):\n        _unpack_uploaded_tarball(upload_path, target_path)\n    elif zipfile.is_zipfile(upload_path):\n        _unpack_uploaded_zipfile(upload_path, target_path)\n    else:\n        return make_response(\"Neither zip file nor tarball included\", 400)\n\n    return getInstalledLanguagePacks()\n\n\n@api.route(\"/languages/<string:locale>/<string:pack>\", methods=[\"DELETE\"])\n@no_firstrun_access\n@Permissions.SETTINGS.require(403)\ndef deleteInstalledLanguagePack(locale, pack):\n\n    if pack == \"_core\":\n        target_path = os.path.join(settings().getBaseFolder(\"translations\"), locale)\n    else:\n        target_path = os.path.join(\n            settings().getBaseFolder(\"translations\"), \"_plugins\", pack, locale\n        )\n\n    if os.path.isdir(target_path):\n        import shutil\n\n        shutil.rmtree(target_path)\n\n    return getInstalledLanguagePacks()\n\n\ndef _unpack_uploaded_zipfile(path, target):\n    with zipfile.ZipFile(path, \"r\") as zip:\n        # sanity check\n        map(_validate_archive_name, zip.namelist())\n\n        # unpack everything\n        zip.extractall(target)\n\n\ndef _unpack_uploaded_tarball(path, target):\n    with tarfile.open(path, \"r\") as tar:\n        # sanity check\n        map(_validate_archive_name, tar.getmembers())\n\n        # unpack everything\n        tar.extractall(target)\n\n\ndef _validate_archive_name(name):\n    if name.startswith(\"/\") or \"..\" in name:\n        raise InvalidLanguagePack(\n            \"Provided language pack contains invalid name {name}\".format(**locals())\n        )\n\n\nclass InvalidLanguagePack(Exception):\n    pass\n", "path": "src/octoprint/server/api/languages.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\n__author__ = \"Gina H\u00e4u\u00dfge <osd@foosel.net>\"\n__license__ = \"GNU Affero General Public License http://www.gnu.org/licenses/agpl.html\"\n__copyright__ = \"Copyright (C) 2015 The OctoPrint Project - Released under terms of the AGPLv3 License\"\n\nimport io\nimport logging\nimport os\nimport tarfile\nimport zipfile\n\ntry:\n    from os import scandir\nexcept ImportError:\n    from scandir import scandir\n\nfrom collections import defaultdict\n\nfrom flask import jsonify, make_response, request\nfrom flask_babel import Locale\n\nfrom octoprint.access.permissions import Permissions\nfrom octoprint.plugin import plugin_manager\nfrom octoprint.server.api import api\nfrom octoprint.server.util.flask import no_firstrun_access\nfrom octoprint.settings import settings\n\n\n@api.route(\"/languages\", methods=[\"GET\"])\n@no_firstrun_access\n@Permissions.SETTINGS.require(403)\ndef getInstalledLanguagePacks():\n    translation_folder = settings().getBaseFolder(\"translations\", check_writable=False)\n    if not os.path.exists(translation_folder):\n        return jsonify(language_packs={\"_core\": []})\n\n    core_packs = []\n    plugin_packs = defaultdict(\n        lambda: {\"identifier\": None, \"display\": None, \"languages\": []}\n    )\n    for entry in scandir(translation_folder):\n        if not entry.is_dir():\n            continue\n\n        def load_meta(path, locale):\n            meta = {}\n\n            meta_path = os.path.join(path, \"meta.yaml\")\n            if os.path.isfile(meta_path):\n                import yaml\n\n                try:\n                    with io.open(meta_path, \"rt\", encoding=\"utf-8\") as f:\n                        meta = yaml.safe_load(f)\n                except Exception:\n                    logging.getLogger(__name__).exception(\"Could not load %s\", meta_path)\n                    pass\n                else:\n                    import datetime\n\n                    if \"last_update\" in meta and isinstance(\n                        meta[\"last_update\"], datetime.datetime\n                    ):\n                        meta[\"last_update\"] = (\n                            meta[\"last_update\"] - datetime.datetime(1970, 1, 1)\n                        ).total_seconds()\n\n            loc = Locale.parse(locale)\n            meta[\"locale\"] = locale\n            meta[\"locale_display\"] = loc.display_name\n            meta[\"locale_english\"] = loc.english_name\n            return meta\n\n        if entry.name == \"_plugins\":\n            for plugin_entry in scandir(entry.path):\n                if not plugin_entry.is_dir():\n                    continue\n\n                if plugin_entry.name not in plugin_manager().plugins:\n                    continue\n\n                plugin_info = plugin_manager().plugins[plugin_entry.name]\n\n                plugin_packs[plugin_entry.name][\"identifier\"] = plugin_entry.name\n                plugin_packs[plugin_entry.name][\"display\"] = plugin_info.name\n\n                for language_entry in scandir(plugin_entry.path):\n                    try:\n                        plugin_packs[plugin_entry.name][\"languages\"].append(\n                            load_meta(language_entry.path, language_entry.name)\n                        )\n                    except Exception:\n                        logging.getLogger(__name__).exception(\n                            \"Error while parsing metadata for language pack {} from {} for plugin {}\".format(\n                                language_entry.name,\n                                language_entry.path,\n                                plugin_entry.name,\n                            )\n                        )\n                        continue\n        else:\n            try:\n                core_packs.append(load_meta(entry.path, entry.name))\n            except ValueError:\n                logging.getLogger(__name__).exception(\n                    \"Core language pack {} doesn't appear to actually be one\".format(\n                        entry.name\n                    )\n                )\n            except Exception:\n                logging.getLogger(__name__).exception(\n                    \"Error while parsing metadata for core language pack {} from {}\".format(\n                        entry.name, entry.path\n                    )\n                )\n\n    result = {\n        \"_core\": {\"identifier\": \"_core\", \"display\": \"Core\", \"languages\": core_packs}\n    }\n    result.update(plugin_packs)\n    return jsonify(language_packs=result)\n\n\n@api.route(\"/languages\", methods=[\"POST\"])\n@no_firstrun_access\n@Permissions.SETTINGS.require(403)\ndef uploadLanguagePack():\n    input_name = \"file\"\n    input_upload_path = (\n        input_name + \".\" + settings().get([\"server\", \"uploads\", \"pathSuffix\"])\n    )\n    input_upload_name = (\n        input_name + \".\" + settings().get([\"server\", \"uploads\", \"nameSuffix\"])\n    )\n    if input_upload_path not in request.values or input_upload_name not in request.values:\n        return make_response(\"No file included\", 400)\n\n    upload_name = request.values[input_upload_name]\n    upload_path = request.values[input_upload_path]\n\n    exts = list(\n        filter(\n            lambda x: upload_name.lower().endswith(x), (\".zip\", \".tar.gz\", \".tgz\", \".tar\")\n        )\n    )\n    if not len(exts):\n        return make_response(\n            \"File doesn't have a valid extension for a language pack archive\", 400\n        )\n\n    target_path = settings().getBaseFolder(\"translations\")\n\n    if tarfile.is_tarfile(upload_path):\n        _unpack_uploaded_tarball(upload_path, target_path)\n    elif zipfile.is_zipfile(upload_path):\n        _unpack_uploaded_zipfile(upload_path, target_path)\n    else:\n        return make_response(\"Neither zip file nor tarball included\", 400)\n\n    return getInstalledLanguagePacks()\n\n\n@api.route(\"/languages/<string:locale>/<string:pack>\", methods=[\"DELETE\"])\n@no_firstrun_access\n@Permissions.SETTINGS.require(403)\ndef deleteInstalledLanguagePack(locale, pack):\n\n    if pack == \"_core\":\n        target_path = os.path.join(settings().getBaseFolder(\"translations\"), locale)\n    else:\n        target_path = os.path.join(\n            settings().getBaseFolder(\"translations\"), \"_plugins\", pack, locale\n        )\n\n    if os.path.isdir(target_path):\n        import shutil\n\n        shutil.rmtree(target_path)\n\n    return getInstalledLanguagePacks()\n\n\ndef _unpack_uploaded_zipfile(path, target):\n    with zipfile.ZipFile(path, \"r\") as zip:\n        # sanity check\n        map(_validate_archive_name, zip.namelist())\n\n        # unpack everything\n        zip.extractall(target)\n\n\ndef _unpack_uploaded_tarball(path, target):\n    with tarfile.open(path, \"r\") as tar:\n        # sanity check\n        map(_validate_archive_name, tar.getmembers())\n\n        # unpack everything\n        tar.extractall(target)\n\n\ndef _validate_archive_name(name):\n    if name.startswith(\"/\") or \"..\" in name:\n        raise InvalidLanguagePack(\n            \"Provided language pack contains invalid name {name}\".format(**locals())\n        )\n\n\nclass InvalidLanguagePack(Exception):\n    pass\n", "path": "src/octoprint/server/api/languages.py"}]}