feat: add oikos-locale-picker component and language settings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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);
|
||||||
@@ -508,7 +508,9 @@
|
|||||||
"logout": "Abmelden",
|
"logout": "Abmelden",
|
||||||
"synchronizing": "Synchronisiere…",
|
"synchronizing": "Synchronisiere…",
|
||||||
"googleDisconnectConfirm": "Google Calendar-Verbindung trennen?",
|
"googleDisconnectConfirm": "Google Calendar-Verbindung trennen?",
|
||||||
"appleDisconnectConfirm": "Apple Calendar-Verbindung trennen?"
|
"appleDisconnectConfirm": "Apple Calendar-Verbindung trennen?",
|
||||||
|
"localeSystem": "System",
|
||||||
|
"languageTitle": "Sprache"
|
||||||
},
|
},
|
||||||
|
|
||||||
"login": {
|
"login": {
|
||||||
|
|||||||
@@ -508,7 +508,9 @@
|
|||||||
"logout": "Log out",
|
"logout": "Log out",
|
||||||
"synchronizing": "Syncing…",
|
"synchronizing": "Syncing…",
|
||||||
"googleDisconnectConfirm": "Disconnect Google Calendar?",
|
"googleDisconnectConfirm": "Disconnect Google Calendar?",
|
||||||
"appleDisconnectConfirm": "Disconnect Apple Calendar?"
|
"appleDisconnectConfirm": "Disconnect Apple Calendar?",
|
||||||
|
"localeSystem": "System",
|
||||||
|
"languageTitle": "Language"
|
||||||
},
|
},
|
||||||
|
|
||||||
"login": {
|
"login": {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import { api, auth } from '/api.js';
|
import { api, auth } from '/api.js';
|
||||||
import { t, formatDate, formatTime } from '/i18n.js';
|
import { t, formatDate, formatTime } from '/i18n.js';
|
||||||
|
import '/components/oikos-locale-picker.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {HTMLElement} container
|
* @param {HTMLElement} container
|
||||||
@@ -74,6 +75,14 @@ export async function render(container, { user }) {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Sprache -->
|
||||||
|
<section class="settings-section">
|
||||||
|
<h2 class="settings-section__title">${t('settings.languageTitle')}</h2>
|
||||||
|
<div class="settings-card">
|
||||||
|
<oikos-locale-picker></oikos-locale-picker>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Mein Konto -->
|
<!-- Mein Konto -->
|
||||||
<section class="settings-section">
|
<section class="settings-section">
|
||||||
<h2 class="settings-section__title">${t('settings.sectionAccount')}</h2>
|
<h2 class="settings-section__title">${t('settings.sectionAccount')}</h2>
|
||||||
|
|||||||
Reference in New Issue
Block a user