diff --git a/backend/controllers/trainingCancellationController.js b/backend/controllers/trainingCancellationController.js
index b154b116..d86be40c 100644
--- a/backend/controllers/trainingCancellationController.js
+++ b/backend/controllers/trainingCancellationController.js
@@ -19,13 +19,14 @@ export const upsertTrainingCancellation = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { clubId } = req.params;
- const { date, startDate, endDate, reason } = req.body;
+ const { date, startDate, endDate, reason, trainingGroupIds } = req.body;
const result = await trainingCancellationService.upsertTrainingCancellation(
userToken,
clubId,
startDate || date,
reason,
- endDate || date || startDate
+ endDate || date || startDate,
+ trainingGroupIds
);
res.status(200).json(result);
} catch (error) {
diff --git a/backend/migrations/add_training_group_ids_to_training_cancellations.sql b/backend/migrations/add_training_group_ids_to_training_cancellations.sql
new file mode 100644
index 00000000..8385d8c8
--- /dev/null
+++ b/backend/migrations/add_training_group_ids_to_training_cancellations.sql
@@ -0,0 +1,2 @@
+ALTER TABLE training_cancellations
+ ADD COLUMN IF NOT EXISTS training_group_ids JSON NULL;
diff --git a/backend/migrations/create_training_cancellations_table.sql b/backend/migrations/create_training_cancellations_table.sql
index bfb90e4e..d444e8ad 100644
--- a/backend/migrations/create_training_cancellations_table.sql
+++ b/backend/migrations/create_training_cancellations_table.sql
@@ -5,6 +5,7 @@ CREATE TABLE IF NOT EXISTS training_cancellations (
end_date DATE NOT NULL,
date DATE NULL,
reason VARCHAR(255) NULL,
+ training_group_ids JSON NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uniq_training_cancellation_club_range (club_id, start_date, end_date),
diff --git a/backend/models/TrainingCancellation.js b/backend/models/TrainingCancellation.js
index 1cc9b89c..a53b2c64 100644
--- a/backend/models/TrainingCancellation.js
+++ b/backend/models/TrainingCancellation.js
@@ -36,6 +36,11 @@ const TrainingCancellation = sequelize.define('TrainingCancellation', {
type: DataTypes.STRING(255),
allowNull: true,
},
+ trainingGroupIds: {
+ type: DataTypes.JSON,
+ allowNull: true,
+ field: 'training_group_ids',
+ },
}, {
tableName: 'training_cancellations',
underscored: true,
diff --git a/backend/services/trainingCancellationService.js b/backend/services/trainingCancellationService.js
index e1cf3dba..92b3e003 100644
--- a/backend/services/trainingCancellationService.js
+++ b/backend/services/trainingCancellationService.js
@@ -24,10 +24,11 @@ class TrainingCancellationService {
});
}
- async upsertTrainingCancellation(userToken, clubId, date, reason, endDate = null) {
+ async upsertTrainingCancellation(userToken, clubId, date, reason, endDate = null, trainingGroupIds = []) {
await checkAccess(userToken, clubId);
const normalizedStartDate = this.normalizeDate(date);
const normalizedEndDate = this.normalizeDate(endDate || date);
+ const normalizedTrainingGroupIds = this.normalizeTrainingGroupIds(trainingGroupIds);
if (!normalizedStartDate || !normalizedEndDate) {
throw new HttpError('Ungültiges Datum', 400);
}
@@ -41,6 +42,7 @@ class TrainingCancellationService {
endDate: normalizedEndDate,
date: normalizedStartDate,
reason: String(reason || '').trim() || null,
+ trainingGroupIds: normalizedTrainingGroupIds,
});
return cancellation || await TrainingCancellation.findOne({
where: { clubId, startDate: normalizedStartDate, endDate: normalizedEndDate },
@@ -71,6 +73,30 @@ class TrainingCancellationService {
const text = String(date || '').slice(0, 10);
return /^\d{4}-\d{2}-\d{2}$/.test(text) ? text : null;
}
+
+ normalizeTrainingGroupIds(trainingGroupIds) {
+ const values = this.parseTrainingGroupIdsValue(trainingGroupIds);
+ return [...new Set(
+ values
+ .map(id => Number.parseInt(id, 10))
+ .filter(id => Number.isInteger(id) && id > 0)
+ )];
+ }
+
+ parseTrainingGroupIdsValue(trainingGroupIds) {
+ if (Array.isArray(trainingGroupIds)) return trainingGroupIds;
+ if (trainingGroupIds === null || trainingGroupIds === undefined || trainingGroupIds === '') return [];
+ if (typeof trainingGroupIds === 'string') {
+ try {
+ const parsed = JSON.parse(trainingGroupIds);
+ if (Array.isArray(parsed)) return parsed;
+ if (parsed !== null && parsed !== undefined) return [parsed];
+ } catch (error) {
+ return trainingGroupIds.split(',');
+ }
+ }
+ return [];
+ }
}
export default new TrainingCancellationService();
diff --git a/frontend/src/i18n/locales/de-CH.json b/frontend/src/i18n/locales/de-CH.json
index 695eaa0f..6bab6c70 100644
--- a/frontend/src/i18n/locales/de-CH.json
+++ b/frontend/src/i18n/locales/de-CH.json
@@ -62,6 +62,106 @@
"ok": "OK",
"saving": "Speichere..."
},
+ "calendar": {
+ "eyebrow": "Vereinskalender",
+ "title": "Kalender",
+ "description": "Trainingstage, Vereinsturniere und Punktspiele in einer Monatsansicht.",
+ "today": "Heute",
+ "loading": "Kalenderdaten werden geladen...",
+ "noClub": "Bitte zuerst einen Verein auswählen.",
+ "loadError": "Kalenderdaten konnten nicht geladen werden.",
+ "sourceWarning": "{source} konnte nicht geladen werden",
+ "agendaTitle": "Termine im Monat",
+ "agendaEmpty": "Keine Termine in diesem Monat.",
+ "recurringTrainingTime": "Regelmäßige Trainingszeit",
+ "participants": "{count} Teilnehmer",
+ "starts": "{count} Starts",
+ "options": {
+ "title": "Optionen",
+ "subtitle": "Ausfälle & eigene Termine"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Turnier",
+ "officialTournament": "Teilnahme",
+ "match": "Punktspiel",
+ "holiday": "Feiertag",
+ "schoolHoliday": "Ferien",
+ "trainingCancellation": "Ausfall",
+ "customEvent": "Termin"
+ },
+ "cancellation": {
+ "title": "Training fällt aus",
+ "description": "Blendet regelmäßige Trainingszeiten aus.",
+ "date": "Datum",
+ "untilOptional": "Bis optional",
+ "trainingGroups": "Trainingsgruppen",
+ "reasonPlaceholder": "Grund (optional)",
+ "saving": "Speichern...",
+ "submit": "Eintragen",
+ "fallbackTitle": "Training fällt aus",
+ "subtitle": "Trainingsausfall"
+ },
+ "customEvent": {
+ "title": "Eigene Termine",
+ "description": "Kreistage, Sitzungen, interne Meetings, ...",
+ "titlePlaceholder": "Titel",
+ "categoryPlaceholder": "Kategorie (optional)",
+ "saving": "Speichern...",
+ "submit": "Anlegen",
+ "subtitleFallback": "Eigener Termin"
+ },
+ "quickCancellation": {
+ "title": "Trainingsausfall",
+ "message": "„{title}“ als Trainingsausfall markieren?",
+ "useWholeRange": "Für den gesamten Zeitraum ({start} bis {end}) eintragen",
+ "trainingGroups": "Betroffene Trainingsgruppen",
+ "confirm": "Ausfall eintragen",
+ "noGroups": "Es sind keine Trainingsgruppen mit Trainingszeiten vorhanden."
+ },
+ "sources": {
+ "trainingDays": "Trainingstage",
+ "trainingTimes": "Trainingszeiten",
+ "trainingCancellations": "Trainingsausfälle",
+ "customEvents": "Eigene Termine",
+ "tournaments": "Turniere",
+ "officialTournaments": "Turnierteilnahmen",
+ "matches": "Punktspiele",
+ "holidays": "Ferien/Feiertage"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Turnier",
+ "officialTournament": "Turnierteilnahme",
+ "match": "Punktspiel"
+ },
+ "tournament": {
+ "open": "Offenes Turnier",
+ "club": "Vereinsturnier"
+ },
+ "match": {
+ "home": "Heim",
+ "guest": "Gast"
+ },
+ "holidayTypes": {
+ "holiday": "Feiertag",
+ "schoolHoliday": "Schulferien"
+ },
+ "weekdays": {
+ "monday": "Mo",
+ "tuesday": "Di",
+ "wednesday": "Mi",
+ "thursday": "Do",
+ "friday": "Fr",
+ "saturday": "Sa",
+ "sunday": "So"
+ },
+ "cancelCancellation": {
+ "title": "Trainingsausfall stornieren",
+ "message": "Trainingsausfall „{title}“ am {date} wirklich stornieren?",
+ "confirm": "Ausfall stornieren"
+ }
+ },
"unknown": "Unbekannt",
"navigation": {
"home": "Startseite",
diff --git a/frontend/src/i18n/locales/de-extended.json b/frontend/src/i18n/locales/de-extended.json
index 53d6acbb..49b94ac4 100644
--- a/frontend/src/i18n/locales/de-extended.json
+++ b/frontend/src/i18n/locales/de-extended.json
@@ -62,6 +62,106 @@
"period": "Zeitraum",
"saving": "Speichere..."
},
+ "calendar": {
+ "eyebrow": "Vereinskalender",
+ "title": "Kalender",
+ "description": "Trainingstage, Vereinsturniere und Punktspiele in einer Monatsansicht.",
+ "today": "Heute",
+ "loading": "Kalenderdaten werden geladen...",
+ "noClub": "Bitte zuerst einen Verein auswählen.",
+ "loadError": "Kalenderdaten konnten nicht geladen werden.",
+ "sourceWarning": "{source} konnte nicht geladen werden",
+ "agendaTitle": "Termine im Monat",
+ "agendaEmpty": "Keine Termine in diesem Monat.",
+ "recurringTrainingTime": "Regelmäßige Trainingszeit",
+ "participants": "{count} Teilnehmer",
+ "starts": "{count} Starts",
+ "options": {
+ "title": "Optionen",
+ "subtitle": "Ausfälle & eigene Termine"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Turnier",
+ "officialTournament": "Teilnahme",
+ "match": "Punktspiel",
+ "holiday": "Feiertag",
+ "schoolHoliday": "Ferien",
+ "trainingCancellation": "Ausfall",
+ "customEvent": "Termin"
+ },
+ "cancellation": {
+ "title": "Training fällt aus",
+ "description": "Blendet regelmäßige Trainingszeiten aus.",
+ "date": "Datum",
+ "untilOptional": "Bis optional",
+ "trainingGroups": "Trainingsgruppen",
+ "reasonPlaceholder": "Grund (optional)",
+ "saving": "Speichern...",
+ "submit": "Eintragen",
+ "fallbackTitle": "Training fällt aus",
+ "subtitle": "Trainingsausfall"
+ },
+ "customEvent": {
+ "title": "Eigene Termine",
+ "description": "Kreistage, Sitzungen, interne Meetings, ...",
+ "titlePlaceholder": "Titel",
+ "categoryPlaceholder": "Kategorie (optional)",
+ "saving": "Speichern...",
+ "submit": "Anlegen",
+ "subtitleFallback": "Eigener Termin"
+ },
+ "quickCancellation": {
+ "title": "Trainingsausfall",
+ "message": "„{title}“ als Trainingsausfall markieren?",
+ "useWholeRange": "Für den gesamten Zeitraum ({start} bis {end}) eintragen",
+ "trainingGroups": "Betroffene Trainingsgruppen",
+ "confirm": "Ausfall eintragen",
+ "noGroups": "Es sind keine Trainingsgruppen mit Trainingszeiten vorhanden."
+ },
+ "sources": {
+ "trainingDays": "Trainingstage",
+ "trainingTimes": "Trainingszeiten",
+ "trainingCancellations": "Trainingsausfälle",
+ "customEvents": "Eigene Termine",
+ "tournaments": "Turniere",
+ "officialTournaments": "Turnierteilnahmen",
+ "matches": "Punktspiele",
+ "holidays": "Ferien/Feiertage"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Turnier",
+ "officialTournament": "Turnierteilnahme",
+ "match": "Punktspiel"
+ },
+ "tournament": {
+ "open": "Offenes Turnier",
+ "club": "Vereinsturnier"
+ },
+ "match": {
+ "home": "Heim",
+ "guest": "Gast"
+ },
+ "holidayTypes": {
+ "holiday": "Feiertag",
+ "schoolHoliday": "Schulferien"
+ },
+ "weekdays": {
+ "monday": "Mo",
+ "tuesday": "Di",
+ "wednesday": "Mi",
+ "thursday": "Do",
+ "friday": "Fr",
+ "saturday": "Sa",
+ "sunday": "So"
+ },
+ "cancelCancellation": {
+ "title": "Trainingsausfall stornieren",
+ "message": "Trainingsausfall „{title}“ am {date} wirklich stornieren?",
+ "confirm": "Ausfall stornieren"
+ }
+ },
"unknown": "Unbekannt",
"navigation": {
"home": "Startseite",
diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json
index 9d369cd3..eec5012d 100644
--- a/frontend/src/i18n/locales/de.json
+++ b/frontend/src/i18n/locales/de.json
@@ -62,6 +62,106 @@
"period": "Zeitraum",
"saving": "Speichere..."
},
+ "calendar": {
+ "eyebrow": "Vereinskalender",
+ "title": "Kalender",
+ "description": "Trainingstage, Vereinsturniere und Punktspiele in einer Monatsansicht.",
+ "today": "Heute",
+ "loading": "Kalenderdaten werden geladen...",
+ "noClub": "Bitte zuerst einen Verein auswählen.",
+ "loadError": "Kalenderdaten konnten nicht geladen werden.",
+ "sourceWarning": "{source} konnte nicht geladen werden",
+ "agendaTitle": "Termine im Monat",
+ "agendaEmpty": "Keine Termine in diesem Monat.",
+ "recurringTrainingTime": "Regelmäßige Trainingszeit",
+ "participants": "{count} Teilnehmer",
+ "starts": "{count} Starts",
+ "options": {
+ "title": "Optionen",
+ "subtitle": "Ausfälle & eigene Termine"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Turnier",
+ "officialTournament": "Teilnahme",
+ "match": "Punktspiel",
+ "holiday": "Feiertag",
+ "schoolHoliday": "Ferien",
+ "trainingCancellation": "Ausfall",
+ "customEvent": "Termin"
+ },
+ "cancellation": {
+ "title": "Training fällt aus",
+ "description": "Blendet regelmäßige Trainingszeiten aus.",
+ "date": "Datum",
+ "untilOptional": "Bis optional",
+ "trainingGroups": "Trainingsgruppen",
+ "reasonPlaceholder": "Grund (optional)",
+ "saving": "Speichern...",
+ "submit": "Eintragen",
+ "fallbackTitle": "Training fällt aus",
+ "subtitle": "Trainingsausfall"
+ },
+ "customEvent": {
+ "title": "Eigene Termine",
+ "description": "Kreistage, Sitzungen, interne Meetings, ...",
+ "titlePlaceholder": "Titel",
+ "categoryPlaceholder": "Kategorie (optional)",
+ "saving": "Speichern...",
+ "submit": "Anlegen",
+ "subtitleFallback": "Eigener Termin"
+ },
+ "quickCancellation": {
+ "title": "Trainingsausfall",
+ "message": "„{title}“ als Trainingsausfall markieren?",
+ "useWholeRange": "Für den gesamten Zeitraum ({start} bis {end}) eintragen",
+ "trainingGroups": "Betroffene Trainingsgruppen",
+ "confirm": "Ausfall eintragen",
+ "noGroups": "Es sind keine Trainingsgruppen mit Trainingszeiten vorhanden."
+ },
+ "sources": {
+ "trainingDays": "Trainingstage",
+ "trainingTimes": "Trainingszeiten",
+ "trainingCancellations": "Trainingsausfälle",
+ "customEvents": "Eigene Termine",
+ "tournaments": "Turniere",
+ "officialTournaments": "Turnierteilnahmen",
+ "matches": "Punktspiele",
+ "holidays": "Ferien/Feiertage"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Turnier",
+ "officialTournament": "Turnierteilnahme",
+ "match": "Punktspiel"
+ },
+ "tournament": {
+ "open": "Offenes Turnier",
+ "club": "Vereinsturnier"
+ },
+ "match": {
+ "home": "Heim",
+ "guest": "Gast"
+ },
+ "holidayTypes": {
+ "holiday": "Feiertag",
+ "schoolHoliday": "Schulferien"
+ },
+ "weekdays": {
+ "monday": "Mo",
+ "tuesday": "Di",
+ "wednesday": "Mi",
+ "thursday": "Do",
+ "friday": "Fr",
+ "saturday": "Sa",
+ "sunday": "So"
+ },
+ "cancelCancellation": {
+ "title": "Trainingsausfall stornieren",
+ "message": "Trainingsausfall „{title}“ am {date} wirklich stornieren?",
+ "confirm": "Ausfall stornieren"
+ }
+ },
"unknown": "Unbekannt",
"navigation": {
"home": "Startseite",
diff --git a/frontend/src/i18n/locales/en-AU.json b/frontend/src/i18n/locales/en-AU.json
index a643c17b..5f85b76f 100644
--- a/frontend/src/i18n/locales/en-AU.json
+++ b/frontend/src/i18n/locales/en-AU.json
@@ -62,6 +62,106 @@
"years": "years",
"ok": "OK"
},
+ "calendar": {
+ "eyebrow": "Club calendar",
+ "title": "Calendar",
+ "description": "Training days, club tournaments and league matches in a monthly view.",
+ "today": "Today",
+ "loading": "Loading calendar data...",
+ "noClub": "Please select a club first.",
+ "loadError": "Calendar data could not be loaded.",
+ "sourceWarning": "{source} could not be loaded",
+ "agendaTitle": "Events this month",
+ "agendaEmpty": "No events this month.",
+ "recurringTrainingTime": "Regular training time",
+ "participants": "{count} participants",
+ "starts": "{count} starts",
+ "options": {
+ "title": "Options",
+ "subtitle": "Cancellations & own events"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Participation",
+ "match": "League match",
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays",
+ "trainingCancellation": "Cancelled",
+ "customEvent": "Event"
+ },
+ "cancellation": {
+ "title": "Training cancelled",
+ "description": "Hides regular training times.",
+ "date": "Date",
+ "untilOptional": "Until optional",
+ "trainingGroups": "Training groups",
+ "reasonPlaceholder": "Reason (optional)",
+ "saving": "Saving...",
+ "submit": "Add",
+ "fallbackTitle": "Training cancelled",
+ "subtitle": "Training cancellation"
+ },
+ "customEvent": {
+ "title": "Own events",
+ "description": "District meetings, sessions, internal meetings, ...",
+ "titlePlaceholder": "Title",
+ "categoryPlaceholder": "Category (optional)",
+ "saving": "Saving...",
+ "submit": "Create",
+ "subtitleFallback": "Own event"
+ },
+ "quickCancellation": {
+ "title": "Training cancellation",
+ "message": "Mark “{title}” as training cancellation?",
+ "useWholeRange": "Apply to the full period ({start} to {end})",
+ "trainingGroups": "Affected training groups",
+ "confirm": "Add cancellation",
+ "noGroups": "No training groups with training times are available."
+ },
+ "sources": {
+ "trainingDays": "Training days",
+ "trainingTimes": "Training times",
+ "trainingCancellations": "Training cancellations",
+ "customEvents": "Own events",
+ "tournaments": "Tournaments",
+ "officialTournaments": "Tournament participations",
+ "matches": "League matches",
+ "holidays": "Holidays/school holidays"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Tournament participation",
+ "match": "League match"
+ },
+ "tournament": {
+ "open": "Open tournament",
+ "club": "Club tournament"
+ },
+ "match": {
+ "home": "Home",
+ "guest": "Away"
+ },
+ "holidayTypes": {
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays"
+ },
+ "weekdays": {
+ "monday": "Mon",
+ "tuesday": "Tue",
+ "wednesday": "Wed",
+ "thursday": "Thu",
+ "friday": "Fri",
+ "saturday": "Sat",
+ "sunday": "Sun"
+ },
+ "cancelCancellation": {
+ "title": "Cancel training cancellation",
+ "message": "Really cancel the training cancellation “{title}” on {date}?",
+ "confirm": "Cancel cancellation"
+ }
+ },
"navigation": {
"home": "Home",
"members": "Members",
diff --git a/frontend/src/i18n/locales/en-GB.json b/frontend/src/i18n/locales/en-GB.json
index 4ea7073a..06f96b3e 100644
--- a/frontend/src/i18n/locales/en-GB.json
+++ b/frontend/src/i18n/locales/en-GB.json
@@ -62,6 +62,106 @@
"years": "years",
"ok": "OK"
},
+ "calendar": {
+ "eyebrow": "Club calendar",
+ "title": "Calendar",
+ "description": "Training days, club tournaments and league matches in a monthly view.",
+ "today": "Today",
+ "loading": "Loading calendar data...",
+ "noClub": "Please select a club first.",
+ "loadError": "Calendar data could not be loaded.",
+ "sourceWarning": "{source} could not be loaded",
+ "agendaTitle": "Events this month",
+ "agendaEmpty": "No events this month.",
+ "recurringTrainingTime": "Regular training time",
+ "participants": "{count} participants",
+ "starts": "{count} starts",
+ "options": {
+ "title": "Options",
+ "subtitle": "Cancellations & own events"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Participation",
+ "match": "League match",
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays",
+ "trainingCancellation": "Cancelled",
+ "customEvent": "Event"
+ },
+ "cancellation": {
+ "title": "Training cancelled",
+ "description": "Hides regular training times.",
+ "date": "Date",
+ "untilOptional": "Until optional",
+ "trainingGroups": "Training groups",
+ "reasonPlaceholder": "Reason (optional)",
+ "saving": "Saving...",
+ "submit": "Add",
+ "fallbackTitle": "Training cancelled",
+ "subtitle": "Training cancellation"
+ },
+ "customEvent": {
+ "title": "Own events",
+ "description": "District meetings, sessions, internal meetings, ...",
+ "titlePlaceholder": "Title",
+ "categoryPlaceholder": "Category (optional)",
+ "saving": "Saving...",
+ "submit": "Create",
+ "subtitleFallback": "Own event"
+ },
+ "quickCancellation": {
+ "title": "Training cancellation",
+ "message": "Mark “{title}” as training cancellation?",
+ "useWholeRange": "Apply to the full period ({start} to {end})",
+ "trainingGroups": "Affected training groups",
+ "confirm": "Add cancellation",
+ "noGroups": "No training groups with training times are available."
+ },
+ "sources": {
+ "trainingDays": "Training days",
+ "trainingTimes": "Training times",
+ "trainingCancellations": "Training cancellations",
+ "customEvents": "Own events",
+ "tournaments": "Tournaments",
+ "officialTournaments": "Tournament participations",
+ "matches": "League matches",
+ "holidays": "Holidays/school holidays"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Tournament participation",
+ "match": "League match"
+ },
+ "tournament": {
+ "open": "Open tournament",
+ "club": "Club tournament"
+ },
+ "match": {
+ "home": "Home",
+ "guest": "Away"
+ },
+ "holidayTypes": {
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays"
+ },
+ "weekdays": {
+ "monday": "Mon",
+ "tuesday": "Tue",
+ "wednesday": "Wed",
+ "thursday": "Thu",
+ "friday": "Fri",
+ "saturday": "Sat",
+ "sunday": "Sun"
+ },
+ "cancelCancellation": {
+ "title": "Cancel training cancellation",
+ "message": "Really cancel the training cancellation “{title}” on {date}?",
+ "confirm": "Cancel cancellation"
+ }
+ },
"navigation": {
"home": "Home",
"members": "Members",
diff --git a/frontend/src/i18n/locales/en-US.json b/frontend/src/i18n/locales/en-US.json
index 60a1e446..95102ec3 100644
--- a/frontend/src/i18n/locales/en-US.json
+++ b/frontend/src/i18n/locales/en-US.json
@@ -62,6 +62,106 @@
"years": "years",
"ok": "OK"
},
+ "calendar": {
+ "eyebrow": "Club calendar",
+ "title": "Calendar",
+ "description": "Training days, club tournaments and league matches in a monthly view.",
+ "today": "Today",
+ "loading": "Loading calendar data...",
+ "noClub": "Please select a club first.",
+ "loadError": "Calendar data could not be loaded.",
+ "sourceWarning": "{source} could not be loaded",
+ "agendaTitle": "Events this month",
+ "agendaEmpty": "No events this month.",
+ "recurringTrainingTime": "Regular training time",
+ "participants": "{count} participants",
+ "starts": "{count} starts",
+ "options": {
+ "title": "Options",
+ "subtitle": "Cancellations & own events"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Participation",
+ "match": "League match",
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays",
+ "trainingCancellation": "Cancelled",
+ "customEvent": "Event"
+ },
+ "cancellation": {
+ "title": "Training cancelled",
+ "description": "Hides regular training times.",
+ "date": "Date",
+ "untilOptional": "Until optional",
+ "trainingGroups": "Training groups",
+ "reasonPlaceholder": "Reason (optional)",
+ "saving": "Saving...",
+ "submit": "Add",
+ "fallbackTitle": "Training cancelled",
+ "subtitle": "Training cancellation"
+ },
+ "customEvent": {
+ "title": "Own events",
+ "description": "District meetings, sessions, internal meetings, ...",
+ "titlePlaceholder": "Title",
+ "categoryPlaceholder": "Category (optional)",
+ "saving": "Saving...",
+ "submit": "Create",
+ "subtitleFallback": "Own event"
+ },
+ "quickCancellation": {
+ "title": "Training cancellation",
+ "message": "Mark “{title}” as training cancellation?",
+ "useWholeRange": "Apply to the full period ({start} to {end})",
+ "trainingGroups": "Affected training groups",
+ "confirm": "Add cancellation",
+ "noGroups": "No training groups with training times are available."
+ },
+ "sources": {
+ "trainingDays": "Training days",
+ "trainingTimes": "Training times",
+ "trainingCancellations": "Training cancellations",
+ "customEvents": "Own events",
+ "tournaments": "Tournaments",
+ "officialTournaments": "Tournament participations",
+ "matches": "League matches",
+ "holidays": "Holidays/school holidays"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Tournament participation",
+ "match": "League match"
+ },
+ "tournament": {
+ "open": "Open tournament",
+ "club": "Club tournament"
+ },
+ "match": {
+ "home": "Home",
+ "guest": "Away"
+ },
+ "holidayTypes": {
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays"
+ },
+ "weekdays": {
+ "monday": "Mon",
+ "tuesday": "Tue",
+ "wednesday": "Wed",
+ "thursday": "Thu",
+ "friday": "Fri",
+ "saturday": "Sat",
+ "sunday": "Sun"
+ },
+ "cancelCancellation": {
+ "title": "Cancel training cancellation",
+ "message": "Really cancel the training cancellation “{title}” on {date}?",
+ "confirm": "Cancel cancellation"
+ }
+ },
"navigation": {
"home": "Home",
"members": "Members",
diff --git a/frontend/src/i18n/locales/es.json b/frontend/src/i18n/locales/es.json
index d43b4f90..3d20b8a6 100644
--- a/frontend/src/i18n/locales/es.json
+++ b/frontend/src/i18n/locales/es.json
@@ -62,6 +62,106 @@
"ok": "OK",
"period": "Periodo"
},
+ "calendar": {
+ "eyebrow": "Calendario del club",
+ "title": "Calendario",
+ "description": "Training days, club tournaments and league matches in a monthly view.",
+ "today": "Hoy",
+ "loading": "Cargando datos del calendario...",
+ "noClub": "Seleccione primero un club.",
+ "loadError": "Calendar data could not be loaded.",
+ "sourceWarning": "{source} could not be loaded",
+ "agendaTitle": "Eventos del mes",
+ "agendaEmpty": "No hay eventos este mes.",
+ "recurringTrainingTime": "Regular training time",
+ "participants": "{count} participants",
+ "starts": "{count} starts",
+ "options": {
+ "title": "Options",
+ "subtitle": "Cancellations & own events"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Participation",
+ "match": "League match",
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays",
+ "trainingCancellation": "Cancelled",
+ "customEvent": "Event"
+ },
+ "cancellation": {
+ "title": "Training cancelled",
+ "description": "Hides regular training times.",
+ "date": "Date",
+ "untilOptional": "Until optional",
+ "trainingGroups": "Training groups",
+ "reasonPlaceholder": "Reason (optional)",
+ "saving": "Saving...",
+ "submit": "Add",
+ "fallbackTitle": "Training cancelled",
+ "subtitle": "Training cancellation"
+ },
+ "customEvent": {
+ "title": "Own events",
+ "description": "District meetings, sessions, internal meetings, ...",
+ "titlePlaceholder": "Title",
+ "categoryPlaceholder": "Category (optional)",
+ "saving": "Saving...",
+ "submit": "Create",
+ "subtitleFallback": "Own event"
+ },
+ "quickCancellation": {
+ "title": "Training cancellation",
+ "message": "Mark “{title}” as training cancellation?",
+ "useWholeRange": "Apply to the full period ({start} to {end})",
+ "trainingGroups": "Affected training groups",
+ "confirm": "Add cancellation",
+ "noGroups": "No training groups with training times are available."
+ },
+ "sources": {
+ "trainingDays": "Training days",
+ "trainingTimes": "Training times",
+ "trainingCancellations": "Training cancellations",
+ "customEvents": "Own events",
+ "tournaments": "Tournaments",
+ "officialTournaments": "Tournament participations",
+ "matches": "League matches",
+ "holidays": "Holidays/school holidays"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Tournament participation",
+ "match": "League match"
+ },
+ "tournament": {
+ "open": "Open tournament",
+ "club": "Club tournament"
+ },
+ "match": {
+ "home": "Home",
+ "guest": "Away"
+ },
+ "holidayTypes": {
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays"
+ },
+ "weekdays": {
+ "monday": "Lun",
+ "tuesday": "Mar",
+ "wednesday": "Mié",
+ "thursday": "Jue",
+ "friday": "Vie",
+ "saturday": "Sáb",
+ "sunday": "Dom"
+ },
+ "cancelCancellation": {
+ "title": "Cancelar ausencia de entrenamiento",
+ "message": "¿Cancelar realmente la ausencia “{title}” el {date}?",
+ "confirm": "Cancelar ausencia"
+ }
+ },
"navigation": {
"home": "Inicio",
"members": "Miembros",
diff --git a/frontend/src/i18n/locales/fil.json b/frontend/src/i18n/locales/fil.json
index 5a33e101..6df2d35a 100644
--- a/frontend/src/i18n/locales/fil.json
+++ b/frontend/src/i18n/locales/fil.json
@@ -62,6 +62,106 @@
"ok": "OK",
"period": "Panahon"
},
+ "calendar": {
+ "eyebrow": "Kalendaryo ng club",
+ "title": "Kalendaryo",
+ "description": "Training days, club tournaments and league matches in a monthly view.",
+ "today": "Ngayon",
+ "loading": "Nilo-load ang datos ng kalendaryo...",
+ "noClub": "Pumili muna ng club.",
+ "loadError": "Calendar data could not be loaded.",
+ "sourceWarning": "{source} could not be loaded",
+ "agendaTitle": "Mga event ngayong buwan",
+ "agendaEmpty": "Walang event ngayong buwan.",
+ "recurringTrainingTime": "Regular training time",
+ "participants": "{count} participants",
+ "starts": "{count} starts",
+ "options": {
+ "title": "Options",
+ "subtitle": "Cancellations & own events"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Participation",
+ "match": "League match",
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays",
+ "trainingCancellation": "Cancelled",
+ "customEvent": "Event"
+ },
+ "cancellation": {
+ "title": "Training cancelled",
+ "description": "Hides regular training times.",
+ "date": "Date",
+ "untilOptional": "Until optional",
+ "trainingGroups": "Training groups",
+ "reasonPlaceholder": "Reason (optional)",
+ "saving": "Saving...",
+ "submit": "Add",
+ "fallbackTitle": "Training cancelled",
+ "subtitle": "Training cancellation"
+ },
+ "customEvent": {
+ "title": "Own events",
+ "description": "District meetings, sessions, internal meetings, ...",
+ "titlePlaceholder": "Title",
+ "categoryPlaceholder": "Category (optional)",
+ "saving": "Saving...",
+ "submit": "Create",
+ "subtitleFallback": "Own event"
+ },
+ "quickCancellation": {
+ "title": "Training cancellation",
+ "message": "Mark “{title}” as training cancellation?",
+ "useWholeRange": "Apply to the full period ({start} to {end})",
+ "trainingGroups": "Affected training groups",
+ "confirm": "Add cancellation",
+ "noGroups": "No training groups with training times are available."
+ },
+ "sources": {
+ "trainingDays": "Training days",
+ "trainingTimes": "Training times",
+ "trainingCancellations": "Training cancellations",
+ "customEvents": "Own events",
+ "tournaments": "Tournaments",
+ "officialTournaments": "Tournament participations",
+ "matches": "League matches",
+ "holidays": "Holidays/school holidays"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Tournament participation",
+ "match": "League match"
+ },
+ "tournament": {
+ "open": "Open tournament",
+ "club": "Club tournament"
+ },
+ "match": {
+ "home": "Home",
+ "guest": "Away"
+ },
+ "holidayTypes": {
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays"
+ },
+ "weekdays": {
+ "monday": "Lun",
+ "tuesday": "Mar",
+ "wednesday": "Miy",
+ "thursday": "Huw",
+ "friday": "Biy",
+ "saturday": "Sab",
+ "sunday": "Lin"
+ },
+ "cancelCancellation": {
+ "title": "Bawiin ang pagkansela ng training",
+ "message": "Bawiin talaga ang pagkansela ng training “{title}” sa {date}?",
+ "confirm": "Bawiin ang pagkansela"
+ }
+ },
"navigation": {
"home": "Home",
"members": "Mga miyembro",
diff --git a/frontend/src/i18n/locales/fr.json b/frontend/src/i18n/locales/fr.json
index 28e0913f..536a26bf 100644
--- a/frontend/src/i18n/locales/fr.json
+++ b/frontend/src/i18n/locales/fr.json
@@ -62,6 +62,106 @@
"ok": "OK",
"period": "Période"
},
+ "calendar": {
+ "eyebrow": "Calendrier du club",
+ "title": "Calendrier",
+ "description": "Training days, club tournaments and league matches in a monthly view.",
+ "today": "Aujourd’hui",
+ "loading": "Chargement des données du calendrier...",
+ "noClub": "Veuillez d’abord sélectionner un club.",
+ "loadError": "Calendar data could not be loaded.",
+ "sourceWarning": "{source} could not be loaded",
+ "agendaTitle": "Événements du mois",
+ "agendaEmpty": "Aucun événement ce mois-ci.",
+ "recurringTrainingTime": "Regular training time",
+ "participants": "{count} participants",
+ "starts": "{count} starts",
+ "options": {
+ "title": "Options",
+ "subtitle": "Cancellations & own events"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Participation",
+ "match": "League match",
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays",
+ "trainingCancellation": "Cancelled",
+ "customEvent": "Event"
+ },
+ "cancellation": {
+ "title": "Training cancelled",
+ "description": "Hides regular training times.",
+ "date": "Date",
+ "untilOptional": "Until optional",
+ "trainingGroups": "Training groups",
+ "reasonPlaceholder": "Reason (optional)",
+ "saving": "Saving...",
+ "submit": "Add",
+ "fallbackTitle": "Training cancelled",
+ "subtitle": "Training cancellation"
+ },
+ "customEvent": {
+ "title": "Own events",
+ "description": "District meetings, sessions, internal meetings, ...",
+ "titlePlaceholder": "Title",
+ "categoryPlaceholder": "Category (optional)",
+ "saving": "Saving...",
+ "submit": "Create",
+ "subtitleFallback": "Own event"
+ },
+ "quickCancellation": {
+ "title": "Training cancellation",
+ "message": "Mark “{title}” as training cancellation?",
+ "useWholeRange": "Apply to the full period ({start} to {end})",
+ "trainingGroups": "Affected training groups",
+ "confirm": "Add cancellation",
+ "noGroups": "No training groups with training times are available."
+ },
+ "sources": {
+ "trainingDays": "Training days",
+ "trainingTimes": "Training times",
+ "trainingCancellations": "Training cancellations",
+ "customEvents": "Own events",
+ "tournaments": "Tournaments",
+ "officialTournaments": "Tournament participations",
+ "matches": "League matches",
+ "holidays": "Holidays/school holidays"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Tournament participation",
+ "match": "League match"
+ },
+ "tournament": {
+ "open": "Open tournament",
+ "club": "Club tournament"
+ },
+ "match": {
+ "home": "Home",
+ "guest": "Away"
+ },
+ "holidayTypes": {
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays"
+ },
+ "weekdays": {
+ "monday": "Lun",
+ "tuesday": "Mar",
+ "wednesday": "Mer",
+ "thursday": "Jeu",
+ "friday": "Ven",
+ "saturday": "Sam",
+ "sunday": "Dim"
+ },
+ "cancelCancellation": {
+ "title": "Annuler l’annulation de l’entraînement",
+ "message": "Vraiment annuler l’annulation « {title} » le {date} ?",
+ "confirm": "Annuler l’annulation"
+ }
+ },
"navigation": {
"home": "Accueil",
"members": "Membres",
diff --git a/frontend/src/i18n/locales/it.json b/frontend/src/i18n/locales/it.json
index e135a736..8790e1fc 100644
--- a/frontend/src/i18n/locales/it.json
+++ b/frontend/src/i18n/locales/it.json
@@ -62,6 +62,106 @@
"ok": "OK",
"period": "Periodo"
},
+ "calendar": {
+ "eyebrow": "Calendario del club",
+ "title": "Calendario",
+ "description": "Training days, club tournaments and league matches in a monthly view.",
+ "today": "Oggi",
+ "loading": "Caricamento dati calendario...",
+ "noClub": "Seleziona prima un club.",
+ "loadError": "Calendar data could not be loaded.",
+ "sourceWarning": "{source} could not be loaded",
+ "agendaTitle": "Eventi del mese",
+ "agendaEmpty": "Nessun evento questo mese.",
+ "recurringTrainingTime": "Regular training time",
+ "participants": "{count} participants",
+ "starts": "{count} starts",
+ "options": {
+ "title": "Options",
+ "subtitle": "Cancellations & own events"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Participation",
+ "match": "League match",
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays",
+ "trainingCancellation": "Cancelled",
+ "customEvent": "Event"
+ },
+ "cancellation": {
+ "title": "Training cancelled",
+ "description": "Hides regular training times.",
+ "date": "Date",
+ "untilOptional": "Until optional",
+ "trainingGroups": "Training groups",
+ "reasonPlaceholder": "Reason (optional)",
+ "saving": "Saving...",
+ "submit": "Add",
+ "fallbackTitle": "Training cancelled",
+ "subtitle": "Training cancellation"
+ },
+ "customEvent": {
+ "title": "Own events",
+ "description": "District meetings, sessions, internal meetings, ...",
+ "titlePlaceholder": "Title",
+ "categoryPlaceholder": "Category (optional)",
+ "saving": "Saving...",
+ "submit": "Create",
+ "subtitleFallback": "Own event"
+ },
+ "quickCancellation": {
+ "title": "Training cancellation",
+ "message": "Mark “{title}” as training cancellation?",
+ "useWholeRange": "Apply to the full period ({start} to {end})",
+ "trainingGroups": "Affected training groups",
+ "confirm": "Add cancellation",
+ "noGroups": "No training groups with training times are available."
+ },
+ "sources": {
+ "trainingDays": "Training days",
+ "trainingTimes": "Training times",
+ "trainingCancellations": "Training cancellations",
+ "customEvents": "Own events",
+ "tournaments": "Tournaments",
+ "officialTournaments": "Tournament participations",
+ "matches": "League matches",
+ "holidays": "Holidays/school holidays"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Tournament participation",
+ "match": "League match"
+ },
+ "tournament": {
+ "open": "Open tournament",
+ "club": "Club tournament"
+ },
+ "match": {
+ "home": "Home",
+ "guest": "Away"
+ },
+ "holidayTypes": {
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays"
+ },
+ "weekdays": {
+ "monday": "Lun",
+ "tuesday": "Mar",
+ "wednesday": "Mer",
+ "thursday": "Gio",
+ "friday": "Ven",
+ "saturday": "Sab",
+ "sunday": "Dom"
+ },
+ "cancelCancellation": {
+ "title": "Annulla cancellazione allenamento",
+ "message": "Annullare davvero la cancellazione “{title}” del {date}?",
+ "confirm": "Annulla cancellazione"
+ }
+ },
"navigation": {
"home": "Home",
"members": "Membri",
diff --git a/frontend/src/i18n/locales/ja.json b/frontend/src/i18n/locales/ja.json
index 012dccc3..6ef0e18a 100644
--- a/frontend/src/i18n/locales/ja.json
+++ b/frontend/src/i18n/locales/ja.json
@@ -62,6 +62,106 @@
"ok": "OK",
"period": "期間"
},
+ "calendar": {
+ "eyebrow": "クラブカレンダー",
+ "title": "カレンダー",
+ "description": "Training days, club tournaments and league matches in a monthly view.",
+ "today": "今日",
+ "loading": "カレンダーデータを読み込んでいます...",
+ "noClub": "最初にクラブを選択してください。",
+ "loadError": "Calendar data could not be loaded.",
+ "sourceWarning": "{source} could not be loaded",
+ "agendaTitle": "今月の予定",
+ "agendaEmpty": "今月の予定はありません。",
+ "recurringTrainingTime": "Regular training time",
+ "participants": "{count} participants",
+ "starts": "{count} starts",
+ "options": {
+ "title": "Options",
+ "subtitle": "Cancellations & own events"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Participation",
+ "match": "League match",
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays",
+ "trainingCancellation": "Cancelled",
+ "customEvent": "Event"
+ },
+ "cancellation": {
+ "title": "Training cancelled",
+ "description": "Hides regular training times.",
+ "date": "Date",
+ "untilOptional": "Until optional",
+ "trainingGroups": "Training groups",
+ "reasonPlaceholder": "Reason (optional)",
+ "saving": "Saving...",
+ "submit": "Add",
+ "fallbackTitle": "Training cancelled",
+ "subtitle": "Training cancellation"
+ },
+ "customEvent": {
+ "title": "Own events",
+ "description": "District meetings, sessions, internal meetings, ...",
+ "titlePlaceholder": "Title",
+ "categoryPlaceholder": "Category (optional)",
+ "saving": "Saving...",
+ "submit": "Create",
+ "subtitleFallback": "Own event"
+ },
+ "quickCancellation": {
+ "title": "Training cancellation",
+ "message": "Mark “{title}” as training cancellation?",
+ "useWholeRange": "Apply to the full period ({start} to {end})",
+ "trainingGroups": "Affected training groups",
+ "confirm": "Add cancellation",
+ "noGroups": "No training groups with training times are available."
+ },
+ "sources": {
+ "trainingDays": "Training days",
+ "trainingTimes": "Training times",
+ "trainingCancellations": "Training cancellations",
+ "customEvents": "Own events",
+ "tournaments": "Tournaments",
+ "officialTournaments": "Tournament participations",
+ "matches": "League matches",
+ "holidays": "Holidays/school holidays"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Tournament participation",
+ "match": "League match"
+ },
+ "tournament": {
+ "open": "Open tournament",
+ "club": "Club tournament"
+ },
+ "match": {
+ "home": "Home",
+ "guest": "Away"
+ },
+ "holidayTypes": {
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays"
+ },
+ "weekdays": {
+ "monday": "月",
+ "tuesday": "火",
+ "wednesday": "水",
+ "thursday": "木",
+ "friday": "金",
+ "saturday": "土",
+ "sunday": "日"
+ },
+ "cancelCancellation": {
+ "title": "練習中止を取り消す",
+ "message": "{date} の「{title}」の練習中止を本当に取り消しますか?",
+ "confirm": "中止を取り消す"
+ }
+ },
"navigation": {
"home": "ホーム",
"members": "メンバー",
diff --git a/frontend/src/i18n/locales/pl.json b/frontend/src/i18n/locales/pl.json
index e14dc5f7..ba6b6582 100644
--- a/frontend/src/i18n/locales/pl.json
+++ b/frontend/src/i18n/locales/pl.json
@@ -62,6 +62,106 @@
"ok": "OK",
"period": "Okres"
},
+ "calendar": {
+ "eyebrow": "Kalendarz klubu",
+ "title": "Kalendarz",
+ "description": "Training days, club tournaments and league matches in a monthly view.",
+ "today": "Dzisiaj",
+ "loading": "Ładowanie danych kalendarza...",
+ "noClub": "Najpierw wybierz klub.",
+ "loadError": "Calendar data could not be loaded.",
+ "sourceWarning": "{source} could not be loaded",
+ "agendaTitle": "Wydarzenia w tym miesiącu",
+ "agendaEmpty": "Brak wydarzeń w tym miesiącu.",
+ "recurringTrainingTime": "Regular training time",
+ "participants": "{count} participants",
+ "starts": "{count} starts",
+ "options": {
+ "title": "Options",
+ "subtitle": "Cancellations & own events"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Participation",
+ "match": "League match",
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays",
+ "trainingCancellation": "Cancelled",
+ "customEvent": "Event"
+ },
+ "cancellation": {
+ "title": "Training cancelled",
+ "description": "Hides regular training times.",
+ "date": "Date",
+ "untilOptional": "Until optional",
+ "trainingGroups": "Training groups",
+ "reasonPlaceholder": "Reason (optional)",
+ "saving": "Saving...",
+ "submit": "Add",
+ "fallbackTitle": "Training cancelled",
+ "subtitle": "Training cancellation"
+ },
+ "customEvent": {
+ "title": "Own events",
+ "description": "District meetings, sessions, internal meetings, ...",
+ "titlePlaceholder": "Title",
+ "categoryPlaceholder": "Category (optional)",
+ "saving": "Saving...",
+ "submit": "Create",
+ "subtitleFallback": "Own event"
+ },
+ "quickCancellation": {
+ "title": "Training cancellation",
+ "message": "Mark “{title}” as training cancellation?",
+ "useWholeRange": "Apply to the full period ({start} to {end})",
+ "trainingGroups": "Affected training groups",
+ "confirm": "Add cancellation",
+ "noGroups": "No training groups with training times are available."
+ },
+ "sources": {
+ "trainingDays": "Training days",
+ "trainingTimes": "Training times",
+ "trainingCancellations": "Training cancellations",
+ "customEvents": "Own events",
+ "tournaments": "Tournaments",
+ "officialTournaments": "Tournament participations",
+ "matches": "League matches",
+ "holidays": "Holidays/school holidays"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Tournament participation",
+ "match": "League match"
+ },
+ "tournament": {
+ "open": "Open tournament",
+ "club": "Club tournament"
+ },
+ "match": {
+ "home": "Home",
+ "guest": "Away"
+ },
+ "holidayTypes": {
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays"
+ },
+ "weekdays": {
+ "monday": "Pon",
+ "tuesday": "Wt",
+ "wednesday": "Śr",
+ "thursday": "Czw",
+ "friday": "Pt",
+ "saturday": "Sob",
+ "sunday": "Nd"
+ },
+ "cancelCancellation": {
+ "title": "Cofnij odwołanie treningu",
+ "message": "Na pewno cofnąć odwołanie „{title}” w dniu {date}?",
+ "confirm": "Cofnij odwołanie"
+ }
+ },
"navigation": {
"home": "Strona główna",
"members": "Członkowie",
diff --git a/frontend/src/i18n/locales/th.json b/frontend/src/i18n/locales/th.json
index 8410d022..47615e4b 100644
--- a/frontend/src/i18n/locales/th.json
+++ b/frontend/src/i18n/locales/th.json
@@ -62,6 +62,106 @@
"ok": "ตกลง",
"period": "ช่วงเวลา"
},
+ "calendar": {
+ "eyebrow": "ปฏิทินสโมสร",
+ "title": "ปฏิทิน",
+ "description": "Training days, club tournaments and league matches in a monthly view.",
+ "today": "วันนี้",
+ "loading": "กำลังโหลดข้อมูลปฏิทิน...",
+ "noClub": "โปรดเลือกสโมสรก่อน",
+ "loadError": "Calendar data could not be loaded.",
+ "sourceWarning": "{source} could not be loaded",
+ "agendaTitle": "กิจกรรมในเดือนนี้",
+ "agendaEmpty": "ไม่มีกิจกรรมในเดือนนี้",
+ "recurringTrainingTime": "Regular training time",
+ "participants": "{count} participants",
+ "starts": "{count} starts",
+ "options": {
+ "title": "Options",
+ "subtitle": "Cancellations & own events"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Participation",
+ "match": "League match",
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays",
+ "trainingCancellation": "Cancelled",
+ "customEvent": "Event"
+ },
+ "cancellation": {
+ "title": "Training cancelled",
+ "description": "Hides regular training times.",
+ "date": "Date",
+ "untilOptional": "Until optional",
+ "trainingGroups": "Training groups",
+ "reasonPlaceholder": "Reason (optional)",
+ "saving": "Saving...",
+ "submit": "Add",
+ "fallbackTitle": "Training cancelled",
+ "subtitle": "Training cancellation"
+ },
+ "customEvent": {
+ "title": "Own events",
+ "description": "District meetings, sessions, internal meetings, ...",
+ "titlePlaceholder": "Title",
+ "categoryPlaceholder": "Category (optional)",
+ "saving": "Saving...",
+ "submit": "Create",
+ "subtitleFallback": "Own event"
+ },
+ "quickCancellation": {
+ "title": "Training cancellation",
+ "message": "Mark “{title}” as training cancellation?",
+ "useWholeRange": "Apply to the full period ({start} to {end})",
+ "trainingGroups": "Affected training groups",
+ "confirm": "Add cancellation",
+ "noGroups": "No training groups with training times are available."
+ },
+ "sources": {
+ "trainingDays": "Training days",
+ "trainingTimes": "Training times",
+ "trainingCancellations": "Training cancellations",
+ "customEvents": "Own events",
+ "tournaments": "Tournaments",
+ "officialTournaments": "Tournament participations",
+ "matches": "League matches",
+ "holidays": "Holidays/school holidays"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Tournament participation",
+ "match": "League match"
+ },
+ "tournament": {
+ "open": "Open tournament",
+ "club": "Club tournament"
+ },
+ "match": {
+ "home": "Home",
+ "guest": "Away"
+ },
+ "holidayTypes": {
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays"
+ },
+ "weekdays": {
+ "monday": "จ.",
+ "tuesday": "อ.",
+ "wednesday": "พ.",
+ "thursday": "พฤ.",
+ "friday": "ศ.",
+ "saturday": "ส.",
+ "sunday": "อา."
+ },
+ "cancelCancellation": {
+ "title": "ยกเลิกการงดซ้อม",
+ "message": "ต้องการยกเลิกการงดซ้อม “{title}” วันที่ {date} หรือไม่?",
+ "confirm": "ยกเลิกการงดซ้อม"
+ }
+ },
"navigation": {
"home": "หน้าแรก",
"members": "สมาชิก",
diff --git a/frontend/src/i18n/locales/tl.json b/frontend/src/i18n/locales/tl.json
index 586fac10..e8fd4ac5 100644
--- a/frontend/src/i18n/locales/tl.json
+++ b/frontend/src/i18n/locales/tl.json
@@ -62,6 +62,106 @@
"ok": "OK",
"period": "Panahon"
},
+ "calendar": {
+ "eyebrow": "Kalendaryo ng club",
+ "title": "Kalendaryo",
+ "description": "Training days, club tournaments and league matches in a monthly view.",
+ "today": "Ngayon",
+ "loading": "Nilo-load ang datos ng kalendaryo...",
+ "noClub": "Pumili muna ng club.",
+ "loadError": "Calendar data could not be loaded.",
+ "sourceWarning": "{source} could not be loaded",
+ "agendaTitle": "Mga event ngayong buwan",
+ "agendaEmpty": "Walang event ngayong buwan.",
+ "recurringTrainingTime": "Regular training time",
+ "participants": "{count} participants",
+ "starts": "{count} starts",
+ "options": {
+ "title": "Options",
+ "subtitle": "Cancellations & own events"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Participation",
+ "match": "League match",
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays",
+ "trainingCancellation": "Cancelled",
+ "customEvent": "Event"
+ },
+ "cancellation": {
+ "title": "Training cancelled",
+ "description": "Hides regular training times.",
+ "date": "Date",
+ "untilOptional": "Until optional",
+ "trainingGroups": "Training groups",
+ "reasonPlaceholder": "Reason (optional)",
+ "saving": "Saving...",
+ "submit": "Add",
+ "fallbackTitle": "Training cancelled",
+ "subtitle": "Training cancellation"
+ },
+ "customEvent": {
+ "title": "Own events",
+ "description": "District meetings, sessions, internal meetings, ...",
+ "titlePlaceholder": "Title",
+ "categoryPlaceholder": "Category (optional)",
+ "saving": "Saving...",
+ "submit": "Create",
+ "subtitleFallback": "Own event"
+ },
+ "quickCancellation": {
+ "title": "Training cancellation",
+ "message": "Mark “{title}” as training cancellation?",
+ "useWholeRange": "Apply to the full period ({start} to {end})",
+ "trainingGroups": "Affected training groups",
+ "confirm": "Add cancellation",
+ "noGroups": "No training groups with training times are available."
+ },
+ "sources": {
+ "trainingDays": "Training days",
+ "trainingTimes": "Training times",
+ "trainingCancellations": "Training cancellations",
+ "customEvents": "Own events",
+ "tournaments": "Tournaments",
+ "officialTournaments": "Tournament participations",
+ "matches": "League matches",
+ "holidays": "Holidays/school holidays"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Tournament participation",
+ "match": "League match"
+ },
+ "tournament": {
+ "open": "Open tournament",
+ "club": "Club tournament"
+ },
+ "match": {
+ "home": "Home",
+ "guest": "Away"
+ },
+ "holidayTypes": {
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays"
+ },
+ "weekdays": {
+ "monday": "Lun",
+ "tuesday": "Mar",
+ "wednesday": "Miy",
+ "thursday": "Huw",
+ "friday": "Biy",
+ "saturday": "Sab",
+ "sunday": "Lin"
+ },
+ "cancelCancellation": {
+ "title": "Bawiin ang pagkansela ng training",
+ "message": "Bawiin talaga ang pagkansela ng training “{title}” sa {date}?",
+ "confirm": "Bawiin ang pagkansela"
+ }
+ },
"navigation": {
"home": "Home",
"members": "Mga miyembro",
diff --git a/frontend/src/i18n/locales/zh.json b/frontend/src/i18n/locales/zh.json
index caf549d1..d08ed114 100644
--- a/frontend/src/i18n/locales/zh.json
+++ b/frontend/src/i18n/locales/zh.json
@@ -62,6 +62,106 @@
"ok": "确定",
"period": "期间"
},
+ "calendar": {
+ "eyebrow": "俱乐部日历",
+ "title": "日历",
+ "description": "Training days, club tournaments and league matches in a monthly view.",
+ "today": "今天",
+ "loading": "正在加载日历数据...",
+ "noClub": "请先选择俱乐部。",
+ "loadError": "Calendar data could not be loaded.",
+ "sourceWarning": "{source} could not be loaded",
+ "agendaTitle": "本月活动",
+ "agendaEmpty": "本月没有活动。",
+ "recurringTrainingTime": "Regular training time",
+ "participants": "{count} participants",
+ "starts": "{count} starts",
+ "options": {
+ "title": "Options",
+ "subtitle": "Cancellations & own events"
+ },
+ "legend": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Participation",
+ "match": "League match",
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays",
+ "trainingCancellation": "Cancelled",
+ "customEvent": "Event"
+ },
+ "cancellation": {
+ "title": "Training cancelled",
+ "description": "Hides regular training times.",
+ "date": "Date",
+ "untilOptional": "Until optional",
+ "trainingGroups": "Training groups",
+ "reasonPlaceholder": "Reason (optional)",
+ "saving": "Saving...",
+ "submit": "Add",
+ "fallbackTitle": "Training cancelled",
+ "subtitle": "Training cancellation"
+ },
+ "customEvent": {
+ "title": "Own events",
+ "description": "District meetings, sessions, internal meetings, ...",
+ "titlePlaceholder": "Title",
+ "categoryPlaceholder": "Category (optional)",
+ "saving": "Saving...",
+ "submit": "Create",
+ "subtitleFallback": "Own event"
+ },
+ "quickCancellation": {
+ "title": "Training cancellation",
+ "message": "Mark “{title}” as training cancellation?",
+ "useWholeRange": "Apply to the full period ({start} to {end})",
+ "trainingGroups": "Affected training groups",
+ "confirm": "Add cancellation",
+ "noGroups": "No training groups with training times are available."
+ },
+ "sources": {
+ "trainingDays": "Training days",
+ "trainingTimes": "Training times",
+ "trainingCancellations": "Training cancellations",
+ "customEvents": "Own events",
+ "tournaments": "Tournaments",
+ "officialTournaments": "Tournament participations",
+ "matches": "League matches",
+ "holidays": "Holidays/school holidays"
+ },
+ "eventTitles": {
+ "training": "Training",
+ "tournament": "Tournament",
+ "officialTournament": "Tournament participation",
+ "match": "League match"
+ },
+ "tournament": {
+ "open": "Open tournament",
+ "club": "Club tournament"
+ },
+ "match": {
+ "home": "Home",
+ "guest": "Away"
+ },
+ "holidayTypes": {
+ "holiday": "Holiday",
+ "schoolHoliday": "School holidays"
+ },
+ "weekdays": {
+ "monday": "周一",
+ "tuesday": "周二",
+ "wednesday": "周三",
+ "thursday": "周四",
+ "friday": "周五",
+ "saturday": "周六",
+ "sunday": "周日"
+ },
+ "cancelCancellation": {
+ "title": "取消训练停课",
+ "message": "确定要取消 {date} 的“{title}”训练停课吗?",
+ "confirm": "取消停课"
+ }
+ },
"navigation": {
"home": "首页",
"members": "成员",
diff --git a/frontend/src/views/CalendarView.vue b/frontend/src/views/CalendarView.vue
index 7f861609..38f0eba2 100644
--- a/frontend/src/views/CalendarView.vue
+++ b/frontend/src/views/CalendarView.vue
@@ -2,13 +2,13 @@
@@ -31,27 +31,39 @@
- Optionen
- Ausfälle & eigene Termine
+ {{ $t('calendar.options.title') }}
+ {{ $t('calendar.options.subtitle') }}
-
Training fällt aus
-
Blendet regelmäßige Trainingszeiten aus.
+
{{ $t('calendar.cancellation.title') }}
+
{{ $t('calendar.cancellation.description') }}
@@ -60,28 +72,28 @@
:key="`cancel-${cancellation.cancellationId}`"
type="button"
class="training-cancellation-item"
- @click="deleteTrainingCancellation(cancellation)"
- title="Löschen"
+ @click="openTrainingCancellationDeleteDialog(cancellation)"
+ :title="$t('common.delete')"
>
{{ formatShortDate(cancellation.date) }}
{{ cancellation.title }}
- Löschen
+ {{ $t('common.delete') }}
-
Eigene Termine
-
Kreistage, Sitzungen, interne Meetings, ...
+
{{ $t('calendar.customEvent.title') }}
+
{{ $t('calendar.customEvent.description') }}
@@ -91,11 +103,11 @@
type="button"
class="custom-event-item"
@click="deleteCustomEvent(event)"
- title="Löschen"
+ :title="$t('common.delete')"
>
{{ formatEventDate(event) }}
{{ event.title }}
- Löschen
+ {{ $t('common.delete') }}
@@ -105,12 +117,12 @@
{{ sourceWarnings.join(' · ') }}
-
Kalenderdaten werden geladen...
+
{{ $t('calendar.loading') }}
-
Bitte zuerst einen Verein auswählen.
+
{{ $t('calendar.noClub') }}
-
+
{{ day }}
- Termine im Monat
- Keine Termine in diesem Monat.
+ {{ $t('calendar.agendaTitle') }}
+ {{ $t('calendar.agendaEmpty') }}
-
+
+
+
+ {{ $t('calendar.quickCancellation.message', { title: quickCancellationDialog.eventTitle }) }}
+
+
+
+
+ {{ $t('calendar.quickCancellation.noGroups') }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('calendar.cancelCancellation.message', {
+ title: cancellationDeleteDialog.title,
+ date: cancellationDeleteDialog.dateLabel
+ }) }}
+
+
+ {{ cancellationDeleteDialog.subtitle }}
+
+
+
+
+
+
+