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:
@@ -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