fix(i18n): translate shopping categories and recurrence UI fields
- Shopping category dropdown options now use CATEGORY_LABELS() for translated display text instead of raw German internal keys - rrule-ui.js now imports t() from /i18n.js; all hardcoded German strings (freq options, weekday labels, form labels, unit labels) replaced with i18n keys under the new 'rrule' namespace - Added 'rrule' section to de.json and en.json with 22 new keys Fixes #21
This commit is contained in:
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.11.4] - 2026-04-05
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Shopping list category dropdown now shows translated labels instead of hardcoded German strings (#21)
|
||||||
|
- Recurrence fields in task and calendar modals now fully translated (labels, frequency options, weekday abbreviations, unit labels) (#21)
|
||||||
|
|
||||||
## [0.11.3] - 2026-04-05
|
## [0.11.3] - 2026-04-05
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -552,5 +552,29 @@
|
|||||||
|
|
||||||
"modal": {
|
"modal": {
|
||||||
"closeLabel": "Schließen"
|
"closeLabel": "Schließen"
|
||||||
|
},
|
||||||
|
|
||||||
|
"rrule": {
|
||||||
|
"freqNone": "Keine Wiederholung",
|
||||||
|
"freqDaily": "Täglich",
|
||||||
|
"freqWeekly": "Wöchentlich",
|
||||||
|
"freqMonthly": "Monatlich",
|
||||||
|
"dayMo": "Mo",
|
||||||
|
"dayTu": "Di",
|
||||||
|
"dayWe": "Mi",
|
||||||
|
"dayTh": "Do",
|
||||||
|
"dayFr": "Fr",
|
||||||
|
"daySa": "Sa",
|
||||||
|
"daySu": "So",
|
||||||
|
"labelRepeat": "Wiederholung",
|
||||||
|
"labelEvery": "Alle",
|
||||||
|
"labelOnDays": "An diesen Tagen",
|
||||||
|
"labelUntil": "Endet am (optional)",
|
||||||
|
"unitDay": "Tag",
|
||||||
|
"unitDays": "Tage",
|
||||||
|
"unitWeek": "Woche",
|
||||||
|
"unitWeeks": "Wochen",
|
||||||
|
"unitMonth": "Monat",
|
||||||
|
"unitMonths": "Monate"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -552,5 +552,29 @@
|
|||||||
|
|
||||||
"modal": {
|
"modal": {
|
||||||
"closeLabel": "Close"
|
"closeLabel": "Close"
|
||||||
|
},
|
||||||
|
|
||||||
|
"rrule": {
|
||||||
|
"freqNone": "No recurrence",
|
||||||
|
"freqDaily": "Daily",
|
||||||
|
"freqWeekly": "Weekly",
|
||||||
|
"freqMonthly": "Monthly",
|
||||||
|
"dayMo": "Mo",
|
||||||
|
"dayTu": "Tu",
|
||||||
|
"dayWe": "We",
|
||||||
|
"dayTh": "Th",
|
||||||
|
"dayFr": "Fr",
|
||||||
|
"daySa": "Sa",
|
||||||
|
"daySu": "Su",
|
||||||
|
"labelRepeat": "Recurrence",
|
||||||
|
"labelEvery": "Every",
|
||||||
|
"labelOnDays": "On these days",
|
||||||
|
"labelUntil": "Ends on (optional)",
|
||||||
|
"unitDay": "day",
|
||||||
|
"unitDays": "days",
|
||||||
|
"unitWeek": "week",
|
||||||
|
"unitWeeks": "weeks",
|
||||||
|
"unitMonth": "month",
|
||||||
|
"unitMonths": "months"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,9 +155,7 @@ function renderListContent(container) {
|
|||||||
<div class="autocomplete-dropdown" id="autocomplete-dropdown" hidden></div>
|
<div class="autocomplete-dropdown" id="autocomplete-dropdown" hidden></div>
|
||||||
</div>
|
</div>
|
||||||
<select class="quick-add__cat" id="item-cat-select" aria-label="${t('shopping.categoryLabel')}">
|
<select class="quick-add__cat" id="item-cat-select" aria-label="${t('shopping.categoryLabel')}">
|
||||||
${ITEM_CATEGORIES.map((c) =>
|
${(() => { const labels = CATEGORY_LABELS(); return ITEM_CATEGORIES.map((c) => `<option value="${c}">${labels[c] || c}</option>`).join(''); })()}
|
||||||
`<option value="${c}">${c}</option>`
|
|
||||||
).join('')}
|
|
||||||
</select>
|
</select>
|
||||||
<button class="quick-add__btn" type="submit" aria-label="${t('shopping.addItemLabel')}">
|
<button class="quick-add__btn" type="submit" aria-label="${t('shopping.addItemLabel')}">
|
||||||
<i data-lucide="plus" style="width:20px;height:20px" aria-hidden="true"></i>
|
<i data-lucide="plus" style="width:20px;height:20px" aria-hidden="true"></i>
|
||||||
|
|||||||
+25
-23
@@ -1,24 +1,26 @@
|
|||||||
/**
|
/**
|
||||||
* Modul: RRULE UI-Helfer
|
* Modul: RRULE UI-Helfer
|
||||||
* Zweck: Wiederholungs-Formular (HTML + Logik) für Aufgaben- und Kalender-Modals
|
* Zweck: Wiederholungs-Formular (HTML + Logik) für Aufgaben- und Kalender-Modals
|
||||||
* Abhängigkeiten: keine
|
* Abhängigkeiten: /i18n.js
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const FREQ_OPTIONS = [
|
import { t } from '/i18n.js';
|
||||||
{ value: '', label: 'Keine Wiederholung' },
|
|
||||||
{ value: 'DAILY', label: 'Täglich' },
|
const FREQ_OPTIONS = () => [
|
||||||
{ value: 'WEEKLY', label: 'Wöchentlich' },
|
{ value: '', label: t('rrule.freqNone') },
|
||||||
{ value: 'MONTHLY', label: 'Monatlich' },
|
{ value: 'DAILY', label: t('rrule.freqDaily') },
|
||||||
|
{ value: 'WEEKLY', label: t('rrule.freqWeekly') },
|
||||||
|
{ value: 'MONTHLY', label: t('rrule.freqMonthly') },
|
||||||
];
|
];
|
||||||
|
|
||||||
const WEEKDAYS = [
|
const WEEKDAYS = () => [
|
||||||
{ value: 'MO', label: 'Mo' },
|
{ value: 'MO', label: t('rrule.dayMo') },
|
||||||
{ value: 'TU', label: 'Di' },
|
{ value: 'TU', label: t('rrule.dayTu') },
|
||||||
{ value: 'WE', label: 'Mi' },
|
{ value: 'WE', label: t('rrule.dayWe') },
|
||||||
{ value: 'TH', label: 'Do' },
|
{ value: 'TH', label: t('rrule.dayTh') },
|
||||||
{ value: 'FR', label: 'Fr' },
|
{ value: 'FR', label: t('rrule.dayFr') },
|
||||||
{ value: 'SA', label: 'Sa' },
|
{ value: 'SA', label: t('rrule.daySa') },
|
||||||
{ value: 'SU', label: 'So' },
|
{ value: 'SU', label: t('rrule.daySu') },
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,11 +78,11 @@ export function buildRRule({ freq, interval, byday, until }) {
|
|||||||
export function renderRRuleFields(prefix, existingRule) {
|
export function renderRRuleFields(prefix, existingRule) {
|
||||||
const parsed = parseRRule(existingRule);
|
const parsed = parseRRule(existingRule);
|
||||||
|
|
||||||
const freqOpts = FREQ_OPTIONS.map(o =>
|
const freqOpts = FREQ_OPTIONS().map(o =>
|
||||||
`<option value="${o.value}" ${parsed.freq === o.value ? 'selected' : ''}>${o.label}</option>`
|
`<option value="${o.value}" ${parsed.freq === o.value ? 'selected' : ''}>${o.label}</option>`
|
||||||
).join('');
|
).join('');
|
||||||
|
|
||||||
const dayBtns = WEEKDAYS.map(d =>
|
const dayBtns = WEEKDAYS().map(d =>
|
||||||
`<button type="button" class="rrule-day ${parsed.byday.includes(d.value) ? 'rrule-day--active' : ''}"
|
`<button type="button" class="rrule-day ${parsed.byday.includes(d.value) ? 'rrule-day--active' : ''}"
|
||||||
data-day="${d.value}" aria-label="${d.label}" aria-pressed="${parsed.byday.includes(d.value)}">${d.label}</button>`
|
data-day="${d.value}" aria-label="${d.label}" aria-pressed="${parsed.byday.includes(d.value)}">${d.label}</button>`
|
||||||
).join('');
|
).join('');
|
||||||
@@ -88,7 +90,7 @@ export function renderRRuleFields(prefix, existingRule) {
|
|||||||
return `
|
return `
|
||||||
<div class="rrule-fields" id="${prefix}-rrule-fields">
|
<div class="rrule-fields" id="${prefix}-rrule-fields">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="label form-label" for="${prefix}-rrule-freq">Wiederholung</label>
|
<label class="label form-label" for="${prefix}-rrule-freq">${t('rrule.labelRepeat')}</label>
|
||||||
<select class="input form-input" id="${prefix}-rrule-freq" style="min-height:44px">
|
<select class="input form-input" id="${prefix}-rrule-freq" style="min-height:44px">
|
||||||
${freqOpts}
|
${freqOpts}
|
||||||
</select>
|
</select>
|
||||||
@@ -97,7 +99,7 @@ export function renderRRuleFields(prefix, existingRule) {
|
|||||||
<div class="rrule-details" id="${prefix}-rrule-details" ${parsed.freq ? '' : 'hidden'}>
|
<div class="rrule-details" id="${prefix}-rrule-details" ${parsed.freq ? '' : 'hidden'}>
|
||||||
<div class="rrule-row">
|
<div class="rrule-row">
|
||||||
<div class="form-group" style="margin-bottom:0">
|
<div class="form-group" style="margin-bottom:0">
|
||||||
<label class="label form-label" for="${prefix}-rrule-interval">Alle</label>
|
<label class="label form-label" for="${prefix}-rrule-interval">${t('rrule.labelEvery')}</label>
|
||||||
<div class="rrule-interval-wrap">
|
<div class="rrule-interval-wrap">
|
||||||
<input class="input form-input" type="number" id="${prefix}-rrule-interval"
|
<input class="input form-input" type="number" id="${prefix}-rrule-interval"
|
||||||
min="1" max="99" value="${parsed.interval}" inputmode="numeric" style="width:64px;text-align:center">
|
min="1" max="99" value="${parsed.interval}" inputmode="numeric" style="width:64px;text-align:center">
|
||||||
@@ -107,12 +109,12 @@ export function renderRRuleFields(prefix, existingRule) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rrule-weekdays" id="${prefix}-rrule-weekdays" ${parsed.freq === 'WEEKLY' ? '' : 'hidden'}>
|
<div class="rrule-weekdays" id="${prefix}-rrule-weekdays" ${parsed.freq === 'WEEKLY' ? '' : 'hidden'}>
|
||||||
<label class="label form-label">An diesen Tagen</label>
|
<label class="label form-label">${t('rrule.labelOnDays')}</label>
|
||||||
<div class="rrule-day-grid">${dayBtns}</div>
|
<div class="rrule-day-grid">${dayBtns}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group" style="margin-top:var(--space-3)">
|
<div class="form-group" style="margin-top:var(--space-3)">
|
||||||
<label class="label form-label" for="${prefix}-rrule-until">Endet am (optional)</label>
|
<label class="label form-label" for="${prefix}-rrule-until">${t('rrule.labelUntil')}</label>
|
||||||
<input class="input form-input" type="date" id="${prefix}-rrule-until" value="${parsed.until}">
|
<input class="input form-input" type="date" id="${prefix}-rrule-until" value="${parsed.until}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -122,9 +124,9 @@ export function renderRRuleFields(prefix, existingRule) {
|
|||||||
|
|
||||||
function unitLabel(freq, interval) {
|
function unitLabel(freq, interval) {
|
||||||
const n = interval > 1;
|
const n = interval > 1;
|
||||||
if (freq === 'DAILY') return n ? 'Tage' : 'Tag';
|
if (freq === 'DAILY') return n ? t('rrule.unitDays') : t('rrule.unitDay');
|
||||||
if (freq === 'WEEKLY') return n ? 'Wochen' : 'Woche';
|
if (freq === 'WEEKLY') return n ? t('rrule.unitWeeks') : t('rrule.unitWeek');
|
||||||
if (freq === 'MONTHLY') return n ? 'Monate' : 'Monat';
|
if (freq === 'MONTHLY') return n ? t('rrule.unitMonths') : t('rrule.unitMonth');
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user