diff --git a/public/components/oikos-locale-picker.js b/public/components/oikos-locale-picker.js
new file mode 100644
index 0000000..bc9d411
--- /dev/null
+++ b/public/components/oikos-locale-picker.js
@@ -0,0 +1,80 @@
+/**
+ * oikos-locale-picker — Sprachauswahl-Web-Component
+ * Zeigt Radio-Buttons für System/Deutsch/English.
+ * Bei Auswahl: setLocale() oder localStorage-Eintrag löschen (System).
+ * Dependencies: i18n.js
+ */
+
+import { t, setLocale, getLocale, getSupportedLocales } from '/i18n.js';
+
+const LOCALE_LABELS = {
+ de: 'Deutsch',
+ en: 'English',
+};
+
+class OikosLocalePicker extends HTMLElement {
+ connectedCallback() {
+ this._render();
+ this._onLocaleChanged = () => this._render();
+ window.addEventListener('locale-changed', this._onLocaleChanged);
+ }
+
+ disconnectedCallback() {
+ window.removeEventListener('locale-changed', this._onLocaleChanged);
+ }
+
+ _render() {
+ this.textContent = '';
+
+ const stored = localStorage.getItem('oikos-locale');
+
+ const wrapper = document.createElement('div');
+ wrapper.className = 'locale-picker';
+
+ // System-Option
+ const systemOption = this._createOption(
+ 'system',
+ t('settings.localeSystem'),
+ !stored,
+ () => {
+ localStorage.removeItem('oikos-locale');
+ location.reload();
+ }
+ );
+ wrapper.appendChild(systemOption);
+
+ // Sprach-Optionen
+ for (const locale of getSupportedLocales()) {
+ const option = this._createOption(
+ locale,
+ LOCALE_LABELS[locale] || locale,
+ stored === locale,
+ () => setLocale(locale)
+ );
+ wrapper.appendChild(option);
+ }
+
+ this.appendChild(wrapper);
+ }
+
+ _createOption(value, label, checked, onChange) {
+ const item = document.createElement('label');
+ item.className = 'locale-picker__option';
+
+ const radio = document.createElement('input');
+ radio.type = 'radio';
+ radio.name = 'locale';
+ radio.value = value;
+ radio.checked = checked;
+ radio.addEventListener('change', onChange);
+
+ const span = document.createElement('span');
+ span.textContent = label;
+
+ item.appendChild(radio);
+ item.appendChild(span);
+ return item;
+ }
+}
+
+customElements.define('oikos-locale-picker', OikosLocalePicker);
diff --git a/public/locales/de.json b/public/locales/de.json
index 28ef092..c80f640 100644
--- a/public/locales/de.json
+++ b/public/locales/de.json
@@ -508,7 +508,9 @@
"logout": "Abmelden",
"synchronizing": "Synchronisiere…",
"googleDisconnectConfirm": "Google Calendar-Verbindung trennen?",
- "appleDisconnectConfirm": "Apple Calendar-Verbindung trennen?"
+ "appleDisconnectConfirm": "Apple Calendar-Verbindung trennen?",
+ "localeSystem": "System",
+ "languageTitle": "Sprache"
},
"login": {
diff --git a/public/locales/en.json b/public/locales/en.json
index c33f4a4..d2f94a0 100644
--- a/public/locales/en.json
+++ b/public/locales/en.json
@@ -508,7 +508,9 @@
"logout": "Log out",
"synchronizing": "Syncing…",
"googleDisconnectConfirm": "Disconnect Google Calendar?",
- "appleDisconnectConfirm": "Disconnect Apple Calendar?"
+ "appleDisconnectConfirm": "Disconnect Apple Calendar?",
+ "localeSystem": "System",
+ "languageTitle": "Language"
},
"login": {
diff --git a/public/pages/settings.js b/public/pages/settings.js
index 03a15d5..e47f380 100644
--- a/public/pages/settings.js
+++ b/public/pages/settings.js
@@ -6,6 +6,7 @@
import { api, auth } from '/api.js';
import { t, formatDate, formatTime } from '/i18n.js';
+import '/components/oikos-locale-picker.js';
/**
* @param {HTMLElement} container
@@ -74,6 +75,14 @@ export async function render(container, { user }) {
+
+
+ ${t('settings.languageTitle')}
+
+
+
+
+
${t('settings.sectionAccount')}