feat(localization): expand language support and enhance UI for user settings
All checks were successful
Deploy to production / deploy (push) Successful in 3m0s
All checks were successful
Deploy to production / deploy (push) Successful in 3m0s
- Added support for additional UI locales including Cebuano and Spanish, improving accessibility for a broader user base. - Updated language selection components in the AppHeader and SettingsWidget to reflect new language options, enhancing user experience. - Enhanced localization of various UI elements across components, ensuring consistent language representation and improved user engagement. - Implemented logic to synchronize user language preferences with backend settings, providing a seamless experience when changing languages.
This commit is contained in:
@@ -4,10 +4,12 @@
|
||||
<div class="footer-system">
|
||||
<button class="footer-brand" type="button" @click="showFalukantDaemonStatus">
|
||||
<img src="/images/icons/logo_color.png" alt="YourPart" />
|
||||
<span>System</span>
|
||||
<span>{{ $t('appShell.footer.systemLabel') }}</span>
|
||||
</button>
|
||||
<span class="footer-caption">
|
||||
{{ openDialogs.length === 0 ? 'Keine offenen Dialoge' : `${openDialogs.length} Fenster aktiv` }}
|
||||
{{ openDialogs.length === 0
|
||||
? $t('appShell.footer.noOpenDialogs')
|
||||
: $t('appShell.footer.activeWindows', { count: openDialogs.length }) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -23,7 +25,7 @@
|
||||
<span class="button-text">{{ dialog.dialog.isTitleTranslated ? $t(dialog.dialog.localTitle) :
|
||||
dialog.dialog.localTitle }}</span>
|
||||
</button>
|
||||
<span v-if="openDialogs.length === 0" class="window-bar__empty">System bereit</span>
|
||||
<span v-if="openDialogs.length === 0" class="window-bar__empty">{{ $t('appShell.footer.systemReady') }}</span>
|
||||
</div>
|
||||
|
||||
<div class="static-block">
|
||||
@@ -72,7 +74,7 @@ export default {
|
||||
},
|
||||
// Daemon WebSocket deaktiviert - diese Funktionen sind nicht mehr verfügbar
|
||||
async showFalukantDaemonStatus() {
|
||||
showInfo(this, 'Der Systemstatus ist in dieser Ansicht derzeit nicht direkt verfügbar.');
|
||||
showInfo(this, this.$t('appShell.footer.systemStatusUnavailable'));
|
||||
},
|
||||
handleDaemonMessage() {
|
||||
// Status-Events werden hier bewusst nicht verarbeitet.
|
||||
|
||||
@@ -5,21 +5,34 @@
|
||||
<div class="logo"><img src="/images/logos/logo.png" alt="YourPart" /></div>
|
||||
<div class="brand-copy">
|
||||
<strong>YourPart</strong>
|
||||
<span>Community-Plattform</span>
|
||||
<span>{{ $t('appShell.header.tagline') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-meta">
|
||||
<div class="header-meta__context">
|
||||
<span class="header-pill">Beta</span>
|
||||
<span class="header-pill">{{ $t('appShell.header.beta') }}</span>
|
||||
<label class="header-lang">
|
||||
<span class="header-lang__label">{{ $t('appShell.header.language') }}</span>
|
||||
<select
|
||||
class="header-lang__select"
|
||||
:aria-label="$t('appShell.header.language')"
|
||||
:value="language"
|
||||
@change="onUiLanguageChange($event.target.value)"
|
||||
>
|
||||
<option v-for="opt in uiLocaleOptions" :key="opt.value" :value="opt.value">
|
||||
{{ $t(opt.labelTr) }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="connection-status" v-if="isLoggedIn">
|
||||
<div class="status-indicator" :class="backendStatusClass">
|
||||
<span class="status-dot"></span>
|
||||
<span class="status-text">Backend</span>
|
||||
<span class="status-text">{{ $t('appShell.header.backend') }}</span>
|
||||
</div>
|
||||
<div class="status-indicator" :class="daemonStatusClass">
|
||||
<span class="status-dot"></span>
|
||||
<span class="status-text">Daemon</span>
|
||||
<span class="status-text">{{ $t('appShell.header.daemon') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -29,11 +42,22 @@
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import apiClient from '@/utils/axios.js';
|
||||
|
||||
export default {
|
||||
name: 'AppHeader',
|
||||
data() {
|
||||
return {
|
||||
uiLocaleOptions: [
|
||||
{ value: 'de', labelTr: 'settings.personal.language.de' },
|
||||
{ value: 'en', labelTr: 'settings.personal.language.en' },
|
||||
{ value: 'ceb', labelTr: 'settings.personal.language.ceb' },
|
||||
{ value: 'es', labelTr: 'settings.personal.language.es' },
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['isLoggedIn', 'connectionStatus', 'daemonConnectionStatus']),
|
||||
...mapGetters(['isLoggedIn', 'user', 'language', 'connectionStatus', 'daemonConnectionStatus']),
|
||||
backendStatusClass() {
|
||||
return {
|
||||
'status-connected': this.connectionStatus === 'connected',
|
||||
@@ -50,7 +74,40 @@ export default {
|
||||
'status-error': this.daemonConnectionStatus === 'error'
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async onUiLanguageChange(code) {
|
||||
const supported = ['de', 'en', 'ceb', 'es'];
|
||||
if (!supported.includes(code)) {
|
||||
return;
|
||||
}
|
||||
await this.$store.dispatch('setLanguage', code);
|
||||
if (!this.isLoggedIn || !this.user?.id) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const { data } = await apiClient.post('/api/settings/filter', {
|
||||
userid: this.user.id,
|
||||
type: 'personal',
|
||||
});
|
||||
const langRow = data.find((s) => s.name === 'language');
|
||||
if (!langRow?.options?.length) {
|
||||
return;
|
||||
}
|
||||
const opt = langRow.options.find((o) => o.value === code);
|
||||
if (!opt) {
|
||||
return;
|
||||
}
|
||||
await apiClient.post('/api/settings/update', {
|
||||
userid: this.user.id,
|
||||
settingId: langRow.id,
|
||||
value: opt.id,
|
||||
});
|
||||
} catch (err) {
|
||||
console.warn('AppHeader: profile language could not be synced', err);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -144,6 +201,38 @@ export default {
|
||||
color: #8a5411;
|
||||
}
|
||||
|
||||
.header-lang {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin: 0;
|
||||
font-size: 0.72rem;
|
||||
color: rgba(95, 75, 57, 0.85);
|
||||
}
|
||||
|
||||
.header-lang__label {
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.header-lang__select {
|
||||
min-width: 7.5rem;
|
||||
max-width: 11rem;
|
||||
padding: 4px 8px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(93, 64, 55, 0.18);
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
color: #3a2a1b;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.header-lang__select:focus {
|
||||
outline: 2px solid rgba(248, 162, 43, 0.45);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
.connection-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
:data-widget-id="widgetId"
|
||||
>
|
||||
<header class="dashboard-widget__titlebar">
|
||||
<span class="dashboard-widget__drag-handle" title="Verschieben" draggable="true" @dragstart="onDragStart" @dragend="onDragEnd">⋮⋮</span>
|
||||
<span class="dashboard-widget__drag-handle" :title="$t('widgets.dashboard.dragHandle')" draggable="true" @dragstart="onDragStart" @dragend="onDragEnd">⋮⋮</span>
|
||||
<span class="dashboard-widget__title">{{ title }}</span>
|
||||
<slot name="title-actions"></slot>
|
||||
</header>
|
||||
<div class="dashboard-widget__frame">
|
||||
<div v-if="loading" class="dashboard-widget__state">Laden…</div>
|
||||
<div v-if="loading" class="dashboard-widget__state">{{ $t('widgets.dashboard.loading') }}</div>
|
||||
<div v-else-if="error" class="dashboard-widget__state dashboard-widget__error">{{ error }}</div>
|
||||
<div v-else class="dashboard-widget__body">
|
||||
<component :is="widgetComponent" :data="data" />
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{{ message }}
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
<button @click="close()" class="dialog-button">Ok</button>
|
||||
<button @click="close()" class="dialog-button">{{ $t('general.ok') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -103,10 +103,6 @@ export default {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: {
|
||||
settings: [],
|
||||
possibleVisibilities: [],
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['user']),
|
||||
@@ -170,6 +166,14 @@ export default {
|
||||
settingId: settingId,
|
||||
value: value
|
||||
});
|
||||
if (setting?.name === 'language' && Array.isArray(setting.options)) {
|
||||
const opt = setting.options.find((o) => String(o.id) === String(value));
|
||||
const code = opt?.value;
|
||||
const supported = ['de', 'en', 'ceb', 'es'];
|
||||
if (code && supported.includes(code)) {
|
||||
this.$store.dispatch('setLanguage', code);
|
||||
}
|
||||
}
|
||||
this.fetchSettings();
|
||||
} catch (err) {
|
||||
console.error('Error updating setting:', err);
|
||||
@@ -238,6 +242,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
settings: [],
|
||||
possibleVisibilities: [],
|
||||
userEmail: "",
|
||||
userUsername: "",
|
||||
};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="termine-widget">
|
||||
<h2>📅 Termine</h2>
|
||||
<div v-if="loading" class="loading">Lade Termine...</div>
|
||||
<h2>{{ $t('widgets.appointments.title') }}</h2>
|
||||
<div v-if="loading" class="loading">{{ $t('widgets.appointments.loading') }}</div>
|
||||
<div v-else-if="error" class="error">{{ error }}</div>
|
||||
<div v-else-if="termine.length === 0" class="no-termine">
|
||||
Keine bevorstehenden Termine
|
||||
{{ $t('widgets.appointments.empty') }}
|
||||
</div>
|
||||
<div v-else class="termine-list">
|
||||
<div v-for="termin in termine" :key="termin.datum + termin.titel" class="termin-item">
|
||||
@@ -50,7 +50,7 @@ export default {
|
||||
this.termine = response.data;
|
||||
} catch (error) {
|
||||
console.error('Error loading termine:', error);
|
||||
this.error = 'Termine konnten nicht geladen werden';
|
||||
this.error = this.$t('widgets.appointments.loadError');
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
@@ -64,7 +64,16 @@ export default {
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
};
|
||||
return date.toLocaleDateString('de-DE', options);
|
||||
return date.toLocaleDateString(this.getDateLocale(), options);
|
||||
},
|
||||
getDateLocale() {
|
||||
const locale = this.$i18n?.locale;
|
||||
return {
|
||||
de: 'de-DE',
|
||||
en: 'en-GB',
|
||||
es: 'es-ES',
|
||||
ceb: 'fil-PH'
|
||||
}[locale] || 'de-DE';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<th>{{ $t('falukant.branch.sale.quality') }}</th>
|
||||
<th>{{ $t('falukant.branch.sale.quantity') }}</th>
|
||||
<th>{{ $t('falukant.branch.sale.sell') }}</th>
|
||||
<th>Bessere Preise</th>
|
||||
<th>{{ $t('falukant.branch.revenue.betterPrices') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
showError(this, 'Fehler beim Kaufen eines Teils der Lagerkapazität.');
|
||||
showError(this, this.$t('falukant.branch.storage.buyPartialError'));
|
||||
}
|
||||
remainingAmount -= toBuy;
|
||||
}
|
||||
@@ -186,7 +186,7 @@
|
||||
.then(() => this.loadStorageData())
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
showError(this, 'Fehler beim Verkaufen der Lagerkapazität.');
|
||||
showError(this, this.$t('falukant.branch.storage.sellError'));
|
||||
});
|
||||
},
|
||||
getCostOfType(labelTr) {
|
||||
|
||||
@@ -9,19 +9,19 @@
|
||||
<div class="birthday-info">
|
||||
<div class="birthday-name">{{ birthday.username }}</div>
|
||||
<div class="birthday-date">
|
||||
<span v-if="birthday.daysUntil === 0" class="birthday-highlight">Heute!</span>
|
||||
<span v-else-if="birthday.daysUntil === 1">Morgen</span>
|
||||
<span v-if="birthday.daysUntil === 0" class="birthday-highlight">{{ $t('widgets.birthdays.today') }}</span>
|
||||
<span v-else-if="birthday.daysUntil === 1">{{ $t('widgets.birthdays.tomorrow') }}</span>
|
||||
<span v-else>{{ formatDate(birthday.nextDate) }}</span>
|
||||
<span class="birthday-age">(wird {{ birthday.turningAge }})</span>
|
||||
<span class="birthday-age">{{ $t('widgets.birthdays.turningAge', { age: birthday.turningAge }) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="birthday.daysUntil > 1" class="birthday-days">
|
||||
{{ birthday.daysUntil }} Tage
|
||||
{{ $t('widgets.birthdays.inDays', { count: birthday.daysUntil }) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="birthday-empty">
|
||||
Keine Geburtstage von Freunden sichtbar
|
||||
{{ $t('widgets.birthdays.empty') }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -37,10 +37,19 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDateLocale() {
|
||||
const locale = this.$i18n?.locale;
|
||||
return {
|
||||
de: 'de-DE',
|
||||
en: 'en-GB',
|
||||
es: 'es-ES',
|
||||
ceb: 'fil-PH'
|
||||
}[locale] || 'de-DE';
|
||||
},
|
||||
formatDate(dateStr) {
|
||||
if (!dateStr) return '';
|
||||
const d = new Date(dateStr);
|
||||
return d.toLocaleDateString('de-DE', {
|
||||
return d.toLocaleDateString(this.getDateLocale(), {
|
||||
day: 'numeric',
|
||||
month: 'short'
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</dd>
|
||||
</template>
|
||||
</dl>
|
||||
<span v-else>—</span>
|
||||
<span v-else>{{ $t('widgets.falukant.emptyValue') }}</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -62,7 +62,7 @@ export default {
|
||||
},
|
||||
falukantDisplayName() {
|
||||
const d = this.falukantData;
|
||||
if (!d) return '—';
|
||||
if (!d) return this.$t('widgets.falukant.emptyValue');
|
||||
const titleKey = d.titleLabelTr;
|
||||
const gender = d.gender;
|
||||
const nameWithoutTitle = d.nameWithoutTitle ?? d.characterName;
|
||||
@@ -71,11 +71,11 @@ export default {
|
||||
const translatedTitle = this.$t(key);
|
||||
if (translatedTitle !== key) return `${translatedTitle} ${nameWithoutTitle}`.trim();
|
||||
}
|
||||
return d.characterName || nameWithoutTitle || '—';
|
||||
return d.characterName || nameWithoutTitle || this.$t('widgets.falukant.emptyValue');
|
||||
},
|
||||
falukantGenderLabel() {
|
||||
const g = this.falukantData?.gender;
|
||||
if (g == null || g === '') return '—';
|
||||
if (g == null || g === '') return this.$t('widgets.falukant.emptyValue');
|
||||
|
||||
// Altersabhängige, (auf Wunsch) altertümlichere Bezeichnungen
|
||||
const years = this._ageYearsFromWidgetValue(this.falukantData?.age);
|
||||
@@ -93,9 +93,9 @@ export default {
|
||||
},
|
||||
falukantAgeLabel() {
|
||||
const ageValue = this.falukantData?.age;
|
||||
if (ageValue == null) return '—';
|
||||
if (ageValue == null) return this.$t('widgets.falukant.emptyValue');
|
||||
const years = this._ageYearsFromWidgetValue(ageValue);
|
||||
if (years == null) return '—';
|
||||
if (years == null) return this.$t('widgets.falukant.emptyValue');
|
||||
return `${years} ${this.$t('falukant.overview.metadata.years')}`;
|
||||
}
|
||||
},
|
||||
@@ -145,8 +145,17 @@ export default {
|
||||
},
|
||||
formatMoney(value) {
|
||||
const n = Number(value);
|
||||
if (Number.isNaN(n)) return '—';
|
||||
return n.toLocaleString('de-DE');
|
||||
if (Number.isNaN(n)) return this.$t('widgets.falukant.emptyValue');
|
||||
return n.toLocaleString(this.getNumberLocale());
|
||||
},
|
||||
getNumberLocale() {
|
||||
const locale = this.$i18n?.locale;
|
||||
return {
|
||||
de: 'de-DE',
|
||||
en: 'en-GB',
|
||||
es: 'es-ES',
|
||||
ceb: 'fil-PH'
|
||||
}[locale] || 'de-DE';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -30,21 +30,32 @@ export default {
|
||||
fallbackText() {
|
||||
if (this.data == null) return '';
|
||||
if (Array.isArray(this.data)) {
|
||||
return this.data.length === 0 ? 'Keine Einträge' : `(${this.data.length} Einträge)`;
|
||||
return this.data.length === 0
|
||||
? this.$t('widgets.list.noEntries')
|
||||
: this.$t('widgets.list.entriesCount', { count: this.data.length });
|
||||
}
|
||||
if (typeof this.data === 'object') {
|
||||
const keys = Object.keys(this.data);
|
||||
return keys.length === 0 ? '—' : `(${keys.length} Felder)`;
|
||||
return keys.length === 0 ? '—' : this.$t('widgets.list.fieldsCount', { count: keys.length });
|
||||
}
|
||||
return String(this.data);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDateLocale() {
|
||||
const locale = this.$i18n?.locale;
|
||||
return {
|
||||
de: 'de-DE',
|
||||
en: 'en-GB',
|
||||
es: 'es-ES',
|
||||
ceb: 'fil-PH'
|
||||
}[locale] || 'de-DE';
|
||||
},
|
||||
formatDatum(dateStr) {
|
||||
if (!dateStr) return '';
|
||||
const d = new Date(dateStr);
|
||||
if (Number.isNaN(d.getTime())) return String(dateStr);
|
||||
return d.toLocaleDateString('de-DE', {
|
||||
return d.toLocaleDateString(this.getDateLocale(), {
|
||||
weekday: 'short',
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
rel="noopener noreferrer"
|
||||
class="dashboard-widget__news-title"
|
||||
>
|
||||
{{ article.title || '—' }}
|
||||
{{ article.title || $t('widgets.news.emptyValue') }}
|
||||
</a>
|
||||
<span v-else class="dashboard-widget__title-text">{{ article.title || '—' }}</span>
|
||||
<span v-else class="dashboard-widget__title-text">{{ article.title || $t('widgets.news.emptyValue') }}</span>
|
||||
<span v-if="article.pubDate" class="dashboard-widget__date">{{ formatNewsDate(article.pubDate) }}</span>
|
||||
<p v-if="article.description" class="dashboard-widget__desc">{{ article.description }}</p>
|
||||
</article>
|
||||
<span v-else>—</span>
|
||||
<span v-else>{{ $t('widgets.news.emptyValue') }}</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -32,11 +32,20 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDateLocale() {
|
||||
const locale = this.$i18n?.locale;
|
||||
return {
|
||||
de: 'de-DE',
|
||||
en: 'en-GB',
|
||||
es: 'es-ES',
|
||||
ceb: 'fil-PH'
|
||||
}[locale] || 'de-DE';
|
||||
},
|
||||
formatNewsDate(dateStr) {
|
||||
if (!dateStr) return '';
|
||||
const d = new Date(dateStr);
|
||||
if (Number.isNaN(d.getTime())) return String(dateStr);
|
||||
return d.toLocaleDateString('de-DE', {
|
||||
return d.toLocaleDateString(this.getDateLocale(), {
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
<div class="upcoming-date">
|
||||
{{ formatDate(event.datum) }}
|
||||
<span v-if="event.startTime && !event.allDay" class="upcoming-time">
|
||||
{{ event.startTime }} Uhr
|
||||
{{ $t('widgets.upcoming.timeAt', { time: event.startTime }) }}
|
||||
</span>
|
||||
<span v-if="event.allDay" class="upcoming-allday">Ganztägig</span>
|
||||
<span v-if="event.allDay" class="upcoming-allday">{{ $t('widgets.upcoming.allDay') }}</span>
|
||||
</div>
|
||||
<div v-if="event.beschreibung" class="upcoming-desc">{{ event.beschreibung }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="upcoming-empty">
|
||||
Keine anstehenden Termine
|
||||
{{ $t('widgets.upcoming.empty') }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -50,6 +50,15 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDateLocale() {
|
||||
const locale = this.$i18n?.locale;
|
||||
return {
|
||||
de: 'de-DE',
|
||||
en: 'en-GB',
|
||||
es: 'es-ES',
|
||||
ceb: 'fil-PH'
|
||||
}[locale] || 'de-DE';
|
||||
},
|
||||
formatDate(dateStr) {
|
||||
if (!dateStr) return '';
|
||||
const d = new Date(dateStr);
|
||||
@@ -58,13 +67,13 @@ export default {
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
|
||||
if (d.toDateString() === today.toDateString()) {
|
||||
return 'Heute';
|
||||
return this.$t('widgets.upcoming.today');
|
||||
}
|
||||
if (d.toDateString() === tomorrow.toDateString()) {
|
||||
return 'Morgen';
|
||||
return this.$t('widgets.upcoming.tomorrow');
|
||||
}
|
||||
|
||||
return d.toLocaleDateString('de-DE', {
|
||||
return d.toLocaleDateString(this.getDateLocale(), {
|
||||
weekday: 'short',
|
||||
day: 'numeric',
|
||||
month: 'short'
|
||||
|
||||
Reference in New Issue
Block a user