diff --git a/app/lang/en.json b/app/lang/en.json
index 3b63df26ba3c4e63d275c2a4e760e8e6017f232d..4a55883c43ecaab870c08e4def8c71721a44608c 100644
--- a/app/lang/en.json
+++ b/app/lang/en.json
@@ -49,5 +49,12 @@
     "longer": "longer",
     "shorter": "shorter",
     "own position": "Own Position",
-    "add own position": "Add Own Position"
+    "add own position": "Add Own Position",
+    "settings": "Settings",
+    "usage of cookies in settings": "All changed settings are stored in your browser using cookies.",
+    "close": "Close",
+    "language": "Language",
+    "en": "English",
+    "de": "German",
+    "theme": "Theme"
 }
\ No newline at end of file
diff --git a/app/resources/js/Config.js b/app/resources/js/Config.js
index 1633f6d7ceaceee99ca81e1a48d0e48a133613fe..37f3f1b4e525cbd5b93a3d9f780bcc85f3000a2b 100644
--- a/app/resources/js/Config.js
+++ b/app/resources/js/Config.js
@@ -1,6 +1,8 @@
 import { bbox, bboxPolygon, circle } from "@turf/turf";
 import { LngLatBounds, CenterZoomBearing, LngLat } from "maplibre-gl";
 import { gpsManager } from "./GpsManager";
+import { UrlGenerator } from "./UrlGenerator";
+import { detectTheme, toggleTheme } from "./Theme";
 
 export const config = {
   localization: {
@@ -130,3 +132,36 @@ let module = document.querySelector("meta[name=module]");
 if (module) {
   config.init.module = module.content;
 }
+
+(() => {
+  let settings_container = document.getElementById("settings");
+  if ((new URLSearchParams(location.search)).has("settings")) {
+    settings_container.showModal();
+  }
+  // Make settings close button work
+  settings_container.querySelector("button.close").addEventListener("click", e => {
+    settings_container.close();
+  });
+
+  // Make Language switcher work
+  let language_switch_select = settings_container.querySelector(".settings-container #language");
+  if (language_switch_select) {
+    language_switch_select.value = config.localization.current_locale;
+    language_switch_select.addEventListener("change", e => {
+      let new_language = e.target.value;
+      if (new_language != config.localization.current_locale) {
+        let new_url = UrlGenerator.to(location.pathname + location.search, new_language);
+        location.replace(new_url);
+      }
+    });
+  } else { console.error("Language switch is not present") }
+
+  // Make theme option work
+  let theme_switch_select = settings_container.querySelector(".settings-container #theme");
+  if (theme_switch_select) {
+    theme_switch_select.value = detectTheme();
+    theme_switch_select.addEventListener("change", e => {
+      toggleTheme();
+    });
+  } else { console.error("Theme switch is not present") }
+})();
diff --git a/app/resources/js/SearchModule.js b/app/resources/js/SearchModule.js
index 9404c165f17cf1854e5de4c109b2a6294d453263..d8285fd92db22f8064db9e07da44159ab068dbf4 100644
--- a/app/resources/js/SearchModule.js
+++ b/app/resources/js/SearchModule.js
@@ -667,9 +667,20 @@ class SearchModule {
         }/${JSON.stringify(current_pos.toArray())}`;
     }
 
+    let options = {};
+    let params = {};
     if (["enabled", "disabled"].includes(this.bounded)) {
-      url += "?bounded=" + this.bounded;
+      params.bounded = this.bounded;
     }
+    options.settings = document.getElementById("settings").open;
+    if (options.settings) {
+      params.settings = "";
+    }
+
+    if (Object.keys(params).length > 0) {
+      url += "?" + (new URLSearchParams(params).toString())
+    }
+
 
     let state = {
       module: "search",
@@ -679,6 +690,7 @@ class SearchModule {
       reverse: this.reverse,
       bounded: this.bounded,
       timestamp: Date.now(),
+      options: options
     };
 
     if (
diff --git a/app/resources/js/Theme.js b/app/resources/js/Theme.js
index 5014da114e43eacf9d044cbb748c8404bb1c7d40..d8c7eb64bb6257e593847a2c9a615f2aae5db776 100644
--- a/app/resources/js/Theme.js
+++ b/app/resources/js/Theme.js
@@ -42,7 +42,7 @@ function getDefaultTheme() {
     }
 }
 
-function toggleTheme() {
+export function toggleTheme() {
     let theme = detectTheme();
     if (theme == "light") {
         theme = "dark";
diff --git a/app/resources/js/UrlGenerator.js b/app/resources/js/UrlGenerator.js
index f10f74e6de5ee23bca7dfd99cb99415d6985085e..057456acc1a531e4c57b1324a8093cde724a0c7c 100644
--- a/app/resources/js/UrlGenerator.js
+++ b/app/resources/js/UrlGenerator.js
@@ -13,6 +13,7 @@ export class UrlGenerator {
         if (!config.localization.supported_locales.includes(locale)) {
             locale = config.localization.fallback_locale;
         }
+
         for (let supported_locale of config.localization.supported_locales) {
             supported_locale = supported_locale.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); // Regex escape
             let reg = new RegExp(`^\/${supported_locale}`);
diff --git a/app/resources/js/app.js b/app/resources/js/app.js
index 5256d04dbcd1e9b3296d0313af34be1f9cbe3bf7..2e09ee0b8a60133987c2829127b129e88497ce01 100644
--- a/app/resources/js/app.js
+++ b/app/resources/js/app.js
@@ -76,6 +76,15 @@ function initializeInterface() {
 
   window.addEventListener("popstate", (event) => {
     event.preventDefault();
+    if (event.state.hasOwnProperty("options") && event.state.options.hasOwnProperty("settings")) {
+      if (document.getElementById("settings").open != event.state.options.settings) {
+        if (event.state.options.settings) {
+          document.getElementById("settings").showModal();
+        } else {
+          document.getElementById("settings").close();
+        }
+      }
+    }
     // Check which module the state is based on
     switch (event.state.module) {
       case "search":
@@ -236,4 +245,4 @@ export function switchModule(name, args) {
     default:
       return;
   }
-}
+}
\ No newline at end of file
diff --git a/app/resources/less/map.less b/app/resources/less/map.less
index d20d1368b4f9dc2b01838d024875e7a2c4cf35a6..bdd9a7fa252412040053c9595ba9c378b45e6c2b 100644
--- a/app/resources/less/map.less
+++ b/app/resources/less/map.less
@@ -3,6 +3,7 @@
 @import "../../node_modules/ol-popup/src/ol-popup.css";
 @import "./openlayers/controls.less";
 @import "./openlayers/popups.less";
+@import "./settings.less";
 
 .maplibregl-popup-content {
     background-color: var(--background-color);
diff --git a/app/resources/less/settings.less b/app/resources/less/settings.less
new file mode 100644
index 0000000000000000000000000000000000000000..46ae56ca70c9e9226190833f9ef04b9f96bca1da
--- /dev/null
+++ b/app/resources/less/settings.less
@@ -0,0 +1,44 @@
+#settings {
+    margin: 1rem 0 0 auto;
+    padding: 1rem;
+    width: 320px;
+    height: 100vh;
+    display: flex;
+    flex-direction: column;
+    row-gap: 1rem;
+
+    &::backdrop {
+        background-color: #0006;
+    }
+
+    >h1 {
+        font-size: 1.5rem;
+        text-align: center;
+        border-bottom: 1px solid;
+        padding-bottom: .5rem;
+    }
+
+    >.settings-container {
+        flex-grow: 1;
+        overflow-y: scroll;
+        padding: .25rem;
+        display: flex;
+        flex-direction: column;
+        row-gap: 1rem;
+
+        >.setting {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+
+            >select {
+                padding: .5rem 1rem;
+            }
+        }
+    }
+
+    >button.close {
+        cursor: pointer;
+        padding: .5rem 1rem;
+    }
+}
\ No newline at end of file
diff --git a/app/resources/views/map.blade.php b/app/resources/views/map.blade.php
index 8ec4893ef6983d552eb3d05ce7858fcf03fb9457..6295364429e7186392f0dd361a166bedc82ca45d 100644
--- a/app/resources/views/map.blade.php
+++ b/app/resources/views/map.blade.php
@@ -85,6 +85,28 @@
                 target="_blank">@lang('why?')</a>
         </div>
     </main>
+    <dialog id="settings">
+        <h1>@lang("settings")</h1>
+        <p>@lang("usage of cookies in settings")</p>
+        <div class="settings-container">
+            <div class="setting">
+                <label for="language">@lang("language")</label>
+                <select name="language" id="language">
+                    @foreach(App\Http\Middleware\Localization::SUPPORTED_LOCALES as $supported_locale)
+                        <option value="{{$supported_locale}}" @if(App::currentLocale() === $supported_locale)selected @endif>@lang($supported_locale)</option>
+                    @endforeach
+                </select>
+            </div>
+            <div class="setting">
+                <label for="theme">@lang("theme")</label>
+                <select name="theme" id="theme">
+                    <option value="light">@lang("light mode")</option>
+                    <option value="dark">@lang("dark mode")</option>
+                </select>
+            </div>
+        </div>
+        <button class="close">@lang("close")</button>
+    </dialog>
     <div id="nav-menu">
         <input type="checkbox" name="nav-opener" id="nav-opener">
         <label for="nav-opener">≡</label>
@@ -105,9 +127,11 @@
             <div class="updates">
                 <label>@lang('last openstreetmap update')</label>
                 <div>@lang('timezone'): <span class="data-date-timezone"></span></div>
-                <div>@lang('map'): <span class="data-date-tiles"><img src="/img/ajax-loader.gif" alt="@lang('loading data...')"></span>
+                <div>@lang('map'): <span class="data-date-tiles"><img src="/img/ajax-loader.gif" 
+a                            lt="@lang('loading data...')"></span>
                 </div>
-                <div>@lang('search'): <span class="data-date-search"><img src="/img/ajax-loader.gif" alt="@lang('loading data...')"></span>
+                <div>@lang('search'): <span class="data-date-search"><img src="/img/ajax-loader.gif"
+                            alt="@lang('loading data...')"></span>
                 </div>
                 <div>@lang('routes'): <span class="data-date-routing"><img src="/img/ajax-loader.gif"
                             alt="@lang('loading data...')"></span></div>