diff --git a/public/locales/de.json b/public/locales/de.json
new file mode 100644
index 0000000..e517219
--- /dev/null
+++ b/public/locales/de.json
@@ -0,0 +1,525 @@
+{
+ "common": {
+ "save": "Speichern",
+ "cancel": "Abbrechen",
+ "delete": "Löschen",
+ "edit": "Bearbeiten",
+ "close": "Schließen",
+ "create": "Erstellen",
+ "add": "Hinzufügen",
+ "back": "Zurück",
+ "next": "Weiter",
+ "loading": "Lade…",
+ "saving": "Wird gespeichert…",
+ "required": "Dieses Feld ist erforderlich.",
+ "error": "Fehler",
+ "allFieldsRequired": "Bitte alle Felder ausfüllen.",
+ "today": "Heute",
+ "tomorrow": "Morgen",
+ "skipToContent": "Zum Inhalt springen",
+ "reload": "Neu laden",
+ "errorOccurred": "Etwas ist schiefgelaufen.",
+ "unexpectedError": "Ein unerwarteter Fehler ist aufgetreten.",
+ "errorGeneric": "Ein Fehler ist aufgetreten.",
+ "updateAvailable": "Update verfügbar — Seite neu laden für die neueste Version.",
+ "titleRequired": "Titel ist erforderlich",
+ "nameRequired": "Name ist erforderlich",
+ "contentRequired": "Inhalt ist erforderlich",
+ "all": "Alle"
+ },
+
+ "nav": {
+ "dashboard": "Übersicht",
+ "tasks": "Aufgaben",
+ "calendar": "Kalender",
+ "meals": "Essen",
+ "shopping": "Einkauf",
+ "notes": "Pinnwand",
+ "contacts": "Kontakte",
+ "budget": "Budget",
+ "settings": "Einstellungen",
+ "main": "Hauptnavigation",
+ "navigation": "Navigation",
+ "quickActions": "Schnellaktionen"
+ },
+
+ "dashboard": {
+ "title": "Übersicht",
+ "greetingMorning": "Guten Morgen, {{name}}",
+ "greetingDay": "Guten Tag, {{name}}",
+ "greetingEvening": "Guten Abend, {{name}}",
+ "allDone": "Alles erledigt",
+ "noEvents": "Keine Termine",
+ "noPinnedNotes": "Keine angepinnten Notizen",
+ "todayMeals": "Heute essen",
+ "allLink": "Alle",
+ "weekLink": "Woche",
+ "urgentTasksChip": "{{count}} dring. Aufgabe",
+ "urgentTasksChipPlural": "{{count}} dring. Aufgaben",
+ "eventsChip": "{{count}} Termin heute",
+ "eventsChipPlural": "{{count}} Termine heute",
+ "todayMealChip": "Heute: {{title}}",
+ "loadError": "Dashboard konnte nicht vollständig geladen werden.",
+ "weatherRefresh": "Wetter aktualisieren",
+ "weatherRefreshTitle": "Aktualisieren",
+ "weatherFeelsLike": "Gefühlt {{temp}}° · {{humidity}}% · Wind {{wind}} km/h",
+ "fabTaskLabel": "Aufgabe hinzufügen",
+ "fabCalendarLabel": "Termin hinzufügen",
+ "fabShoppingLabel": "Einkauf hinzufügen",
+ "fabNoteLabel": "Notiz hinzufügen",
+ "fabTask": "Aufgabe",
+ "fabCalendar": "Termin",
+ "fabShopping": "Einkauf",
+ "fabNote": "Notiz",
+ "overdue": "Überfällig",
+ "dueSoon": "Heute fällig",
+ "dueTomorrow": "Morgen fällig",
+ "allDay": "Ganztägig"
+ },
+
+ "tasks": {
+ "title": "Aufgaben",
+ "newTask": "Neue Aufgabe",
+ "editTask": "Aufgabe bearbeiten",
+ "emptyTitle": "Keine Aufgaben — alles erledigt?",
+ "emptyDescription": "Neue Aufgaben über den + Button erstellen.",
+ "titleLabel": "Titel *",
+ "titlePlaceholder": "Was muss erledigt werden?",
+ "descriptionLabel": "Notiz",
+ "descriptionPlaceholder": "Optionale Details…",
+ "priorityLabel": "Priorität",
+ "categoryLabel": "Kategorie",
+ "dueDateLabel": "Fälligkeit",
+ "dueTimeLabel": "Uhrzeit",
+ "assignedLabel": "Zugewiesen an",
+ "assignedNobody": "— Niemand —",
+ "statusLabel": "Status",
+ "priorityUrgent": "Dringend",
+ "priorityHigh": "Hoch",
+ "priorityMedium": "Mittel",
+ "priorityLow": "Niedrig",
+ "statusOpen": "Offen",
+ "statusInProgress": "In Bearbeitung",
+ "statusDone": "Erledigt",
+ "categoryHousehold": "Haushalt",
+ "categorySchool": "Schule",
+ "categoryShopping": "Einkauf",
+ "categoryRepair": "Reparatur",
+ "categoryHealth": "Gesundheit",
+ "categoryFinance": "Finanzen",
+ "categoryLeisure": "Freizeit",
+ "categoryMisc": "Sonstiges",
+ "overdue": "Überfällig",
+ "overdueDay": "{{count}}d überfällig",
+ "dueToday": "Heute fällig",
+ "dueTomorrow": "Morgen fällig",
+ "groupOverdue": "Überfällig",
+ "groupToday": "Heute",
+ "groupThisWeek": "Diese Woche",
+ "groupNextWeek": "Nächste Woche",
+ "groupLater": "Später",
+ "groupNoDate": "Kein Datum",
+ "markDone": "{{title}} als erledigt markieren",
+ "editButton": "Aufgabe bearbeiten",
+ "swipeOpen": "Öffnen",
+ "swipeDone": "Erledigt",
+ "swipeEdit": "Bearbeiten",
+ "subtaskAdd": "+ Teilaufgabe hinzufügen",
+ "subtaskToggle": "Teilaufgaben anzeigen",
+ "subtaskMarkDone": "{{title}} als erledigt markieren",
+ "deleteConfirm": "Aufgabe und alle Teilaufgaben löschen?",
+ "savedToast": "Aufgabe gespeichert.",
+ "createdToast": "Aufgabe erstellt.",
+ "deletedToast": "Aufgabe gelöscht.",
+ "loadError": "Aufgabe konnte nicht geladen werden.",
+ "subtaskPrompt": "Teilaufgabe:",
+ "kanbanOpen": "Offen",
+ "kanbanInProgress": "In Bearbeitung",
+ "kanbanDone": "Erledigt"
+ },
+
+ "shopping": {
+ "title": "Einkauf",
+ "noLists": "Keine Listen",
+ "noListsDescription": "Erstelle eine Liste mit dem + Button.",
+ "emptyList": "Die Liste ist leer",
+ "emptyListDescription": "Artikel über das Eingabefeld oben hinzufügen.",
+ "newListPrompt": "Name der neuen Liste:",
+ "newListButton": "Neue Liste erstellen",
+ "renameListPrompt": "Neuer Listen-Name:",
+ "deleteListConfirm": "Liste \"{{name}}\" und alle Artikel löschen?",
+ "deletedListToast": "Liste gelöscht.",
+ "itemsRemovedToast": "{{count}} Artikel entfernt.",
+ "clearChecked": "Abgehakt löschen ({{count}})",
+ "itemNamePlaceholder": "Artikel hinzufügen…",
+ "itemQtyPlaceholder": "Menge",
+ "itemNameLabel": "Artikelname",
+ "itemQtyLabel": "Menge",
+ "categoryLabel": "Kategorie",
+ "addItemLabel": "Artikel hinzufügen",
+ "renameListLabel": "Liste umbenennen",
+ "deleteListLabel": "Liste löschen",
+ "swipeBack": "Zurück",
+ "swipeCheck": "Abhaken",
+ "swipeDelete": "Löschen",
+ "markDoneLabel": "{{name}} abhaken",
+ "markUndoneLabel": "{{name}} als nicht erledigt markieren",
+ "deleteItemLabel": "{{name}} löschen",
+ "listsLoadError": "Listen konnten nicht geladen werden.",
+ "itemsLoadError": "Artikel konnten nicht geladen werden.",
+ "catFruitVeg": "Obst & Gemüse",
+ "catBakery": "Backwaren",
+ "catDairy": "Milchprodukte",
+ "catMeatFish": "Fleisch & Fisch",
+ "catFrozen": "Tiefkühl",
+ "catDrinks": "Getränke",
+ "catHousehold": "Haushalt",
+ "catDrugstore": "Drogerie",
+ "catMisc": "Sonstiges"
+ },
+
+ "meals": {
+ "title": "Essensplan",
+ "noMealPlanned": "Kein Essen geplant",
+ "addMeal": "{{type}} hinzufügen",
+ "editMeal": "Mahlzeit bearbeiten",
+ "addMealTitle": "Mahlzeit hinzufügen",
+ "deleteMeal": "Mahlzeit löschen",
+ "transferToShoppingList": "Zutaten auf Einkaufsliste",
+ "today": "Heute",
+ "prevWeek": "Vorherige Woche",
+ "nextWeek": "Nächste Woche",
+ "loadError": "Essensplan konnte nicht geladen werden.",
+ "typeBreakfast": "Frühstück",
+ "typeLunch": "Mittagessen",
+ "typeDinner": "Abendessen",
+ "typeSnack": "Snack",
+ "dayMo": "Mo",
+ "dayDi": "Di",
+ "dayMi": "Mi",
+ "dayDo": "Do",
+ "dayFr": "Fr",
+ "daySa": "Sa",
+ "daySo": "So",
+ "dateLabel": "Datum",
+ "mealTypeLabel": "Mahlzeit",
+ "titleLabel": "Titel *",
+ "titlePlaceholder": "z.B. Spaghetti Bolognese",
+ "notesLabel": "Notizen",
+ "notesPlaceholder": "Optional…",
+ "ingredientsLabel": "Zutaten",
+ "addIngredient": "Zutat hinzufügen",
+ "ingredientNamePlaceholder": "Zutat",
+ "ingredientQtyPlaceholder": "Menge",
+ "removeIngredient": "Zutat entfernen",
+ "transferLabel": "Zutaten auf Einkaufsliste übertragen",
+ "transferNow": "Jetzt übertragen",
+ "noShoppingLists": "Keine Einkaufslisten vorhanden",
+ "transferSuccess": "{{count}} Zutat übertragen",
+ "transferSuccessPlural": "{{count}} Zutaten übertragen",
+ "transferAlreadyDone": "Alle Zutaten bereits übertragen",
+ "ingredientCount": "{{count}} Zutat",
+ "ingredientCountPlural": "{{count}} Zutaten",
+ "titleRequired": "Titel ist erforderlich",
+ "loadingIndicator": "Lade…"
+ },
+
+ "calendar": {
+ "title": "Kalender",
+ "newEvent": "Neuer Termin",
+ "editEvent": "Termin bearbeiten",
+ "addEvent": "Termin hinzufügen",
+ "deleteEvent": "Termin löschen",
+ "noEvents": "Keine Termine im gewählten Zeitraum.",
+ "today": "Heute",
+ "back": "Zurück",
+ "forward": "Weiter",
+ "viewMonth": "Monat",
+ "viewWeek": "Woche",
+ "viewDay": "Tag",
+ "viewAgenda": "Agenda",
+ "allDay": "Ganztägig",
+ "allDayShort": "ganztg.",
+ "moreEvents": "+{{count}} weitere",
+ "weekNumberLabel": "KW {{week}} · {{month}} {{year}}",
+ "agendaFrom": "Ab {{date}}",
+ "titleLabel": "Titel *",
+ "titlePlaceholder": "z.B. Zahnarzt",
+ "allDayToggle": "Ganztägig",
+ "startDateLabel": "Startdatum",
+ "startTimeLabel": "Startzeit",
+ "endDateLabel": "Enddatum",
+ "endTimeLabel": "Endzeit",
+ "fromLabel": "Von",
+ "toLabel": "Bis",
+ "locationLabel": "Ort",
+ "locationPlaceholder": "Optional",
+ "assignedLabel": "Zugewiesen an",
+ "assignedNobody": "— Niemand —",
+ "colorLabel": "Farbe",
+ "descriptionLabel": "Beschreibung",
+ "descriptionPlaceholder": "Optional…",
+ "popupEdit": "Bearbeiten",
+ "deleteConfirm": "\"{{title}}\" wirklich löschen?",
+ "createdToast": "Termin erstellt",
+ "savedToast": "Termin gespeichert",
+ "deletedToast": "Termin gelöscht",
+ "loadError": "Termine konnten nicht geladen werden.",
+ "saveError": "Fehler beim Speichern",
+ "deleteError": "Fehler beim Löschen",
+ "titleRequired": "Titel ist erforderlich",
+ "monthJanuary": "Januar",
+ "monthFebruary": "Februar",
+ "monthMarch": "März",
+ "monthApril": "April",
+ "monthMay": "Mai",
+ "monthJune": "Juni",
+ "monthJuly": "Juli",
+ "monthAugust": "August",
+ "monthSeptember": "September",
+ "monthOctober": "Oktober",
+ "monthNovember": "November",
+ "monthDecember": "Dezember",
+ "dayShortSunday": "So",
+ "dayShortMonday": "Mo",
+ "dayShortTuesday": "Di",
+ "dayShortWednesday": "Mi",
+ "dayShortThursday": "Do",
+ "dayShortFriday": "Fr",
+ "dayShortSaturday": "Sa",
+ "dayLongSunday": "Sonntag",
+ "dayLongMonday": "Montag",
+ "dayLongTuesday": "Dienstag",
+ "dayLongWednesday": "Mittwoch",
+ "dayLongThursday": "Donnerstag",
+ "dayLongFriday": "Freitag",
+ "dayLongSaturday": "Samstag"
+ },
+
+ "notes": {
+ "title": "Pinnwand",
+ "newNote": "Neue Notiz",
+ "editNote": "Notiz bearbeiten",
+ "addNoteLabel": "Neue Notiz",
+ "searchPlaceholder": "Notizen durchsuchen…",
+ "emptyTitle": "Noch keine Notizen",
+ "emptyDescription": "Neue Notiz über den + Button erstellen.",
+ "noResultsTitle": "Keine Treffer",
+ "noResultsDescription": "Keine Notiz enthält \"{{query}}\".",
+ "titleLabel": "Titel (optional)",
+ "titlePlaceholder": "Kein Titel",
+ "contentLabel": "Inhalt",
+ "contentMarkdownHint": "(Markdown-Formatierung möglich)",
+ "contentPlaceholder": "Notiz eingeben…",
+ "colorLabel": "Farbe",
+ "pinnedLabel": "Anpinnen (erscheint auf Dashboard)",
+ "pinAction": "Anpinnen",
+ "unpinAction": "Anpinnen aufheben",
+ "deleteLabel": "Notiz löschen",
+ "deleteConfirm": "Notiz wirklich löschen?",
+ "createdToast": "Notiz erstellt",
+ "savedToast": "Notiz gespeichert",
+ "deletedToast": "Notiz gelöscht",
+ "loadError": "Notizen konnten nicht geladen werden.",
+ "formatBold": "Fett (Strg+B)",
+ "formatItalic": "Kursiv (Strg+I)",
+ "formatUnderline": "Unterstrichen (Strg+U)",
+ "formatStrikethrough": "Durchgestrichen",
+ "formatHeading": "Überschrift",
+ "formatList": "Aufzählung",
+ "formatOrderedList": "Nummerierte Liste",
+ "formatChecklist": "Checkliste",
+ "formatLink": "Link",
+ "formatCode": "Code",
+ "formatQuote": "Zitat",
+ "formatDivider": "Trennlinie"
+ },
+
+ "contacts": {
+ "title": "Kontakte",
+ "newContact": "Neuer Kontakt",
+ "editContact": "Kontakt bearbeiten",
+ "addButton": "Neu",
+ "newContactLabel": "Neuer Kontakt",
+ "searchPlaceholder": "Name, Telefon oder E-Mail suchen…",
+ "importButton": "Import",
+ "importLabel": "Kontakt aus vCard importieren",
+ "importTooltip": "vCard importieren",
+ "emptyTitle": "Noch keine Kontakte",
+ "emptyDescription": "Neue Kontakte über den + Button hinzufügen.",
+ "filterAll": "Alle",
+ "nameLabel": "Name *",
+ "namePlaceholder": "Vollständiger Name",
+ "categoryLabel": "Kategorie",
+ "phoneLabel": "Telefon",
+ "phonePlaceholder": "+49 …",
+ "emailLabel": "E-Mail",
+ "emailPlaceholder": "name@beispiel.de",
+ "addressLabel": "Adresse",
+ "addressPlaceholder": "Straße, PLZ Ort",
+ "notesLabel": "Notizen",
+ "notesPlaceholder": "Optional…",
+ "callLabel": "Anrufen",
+ "emailActionLabel": "E-Mail",
+ "mapsLabel": "In Maps öffnen",
+ "exportLabel": "Als vCard exportieren",
+ "exportTooltip": "vCard exportieren",
+ "deleteLabel": "Kontakt löschen",
+ "deleteConfirm": "Kontakt wirklich löschen?",
+ "deletePersonConfirm": "\"{{name}}\" wirklich löschen?",
+ "savedToast": "Kontakt gespeichert",
+ "updatedToast": "Kontakt aktualisiert",
+ "deletedToast": "Kontakt gelöscht",
+ "importedToast": "{{name}} importiert.",
+ "importError": "Import fehlgeschlagen: {{error}}",
+ "vcardNoName": "vCard enthält keinen Namen.",
+ "catDoctor": "Arzt",
+ "catSchool": "Schule/Kita",
+ "catAuthority": "Behörde",
+ "catInsurance": "Versicherung",
+ "catCraftsman": "Handwerker",
+ "catEmergency": "Notfall",
+ "catMisc": "Sonstiges"
+ },
+
+ "budget": {
+ "title": "Budget",
+ "newEntry": "Neuer Eintrag",
+ "editEntry": "Eintrag bearbeiten",
+ "addEntryLabel": "Eintrag hinzufügen",
+ "newEntryFabLabel": "Neuer Eintrag",
+ "currentMonth": "Aktuell",
+ "prevMonth": "Vorheriger Monat",
+ "nextMonth": "Nächster Monat",
+ "income": "Einnahmen",
+ "expenses": "Ausgaben",
+ "balance": "Saldo",
+ "byCategory": "Nach Kategorie",
+ "transactions": "Transaktionen",
+ "emptyTitle": "Keine Einträge diesen Monat",
+ "emptyDescription": "Budget-Einträge über den + Button hinzufügen.",
+ "csvExport": "CSV",
+ "typeExpense": "Ausgabe",
+ "typeIncome": "Einnahme",
+ "titleLabel": "Titel *",
+ "titlePlaceholder": "z.B. REWE Einkauf",
+ "amountLabel": "Betrag (€) *",
+ "amountPlaceholder": "0,00",
+ "categoryLabel": "Kategorie",
+ "dateLabel": "Datum *",
+ "recurringLabel": "Wiederkehrend",
+ "deleteLabel": "Eintrag löschen",
+ "deleteConfirm": "Eintrag wirklich löschen?",
+ "deletePersonConfirm": "\"{{title}}\" wirklich löschen?",
+ "addedToast": "Eintrag hinzugefügt",
+ "savedToast": "Eintrag gespeichert",
+ "deletedToast": "Eintrag gelöscht",
+ "loadError": "Budget konnte nicht geladen werden.",
+ "trendNeutral": "— wie {{month}}",
+ "validAmountRequired": "Gültigen Betrag eingeben",
+ "dateRequired": "Datum ist erforderlich",
+ "catFood": "Lebensmittel",
+ "catRent": "Miete",
+ "catInsurance": "Versicherung",
+ "catMobility": "Mobilität",
+ "catLeisure": "Freizeit",
+ "catClothing": "Kleidung",
+ "catHealth": "Gesundheit",
+ "catEducation": "Bildung",
+ "catMisc": "Sonstiges",
+ "loadingIndicator": "Lade…"
+ },
+
+ "settings": {
+ "title": "Einstellungen",
+ "sectionDesign": "Design",
+ "sectionAccount": "Mein Konto",
+ "sectionCalendarSync": "Kalender-Synchronisation",
+ "sectionFamily": "Familienmitglieder",
+ "cardAppearance": "Darstellung",
+ "themeSystem": "System",
+ "themeSysLabel": "System-Einstellung verwenden",
+ "themeLight": "Hell",
+ "themeLightLabel": "Helles Design",
+ "themeDark": "Dunkel",
+ "themeDarkLabel": "Dunkles Design",
+ "changePassword": "Passwort ändern",
+ "currentPasswordLabel": "Aktuelles Passwort",
+ "newPasswordLabel": "Neues Passwort",
+ "confirmPasswordLabel": "Neues Passwort bestätigen",
+ "savePassword": "Passwort speichern",
+ "passwordMismatch": "Passwörter stimmen nicht überein.",
+ "passwordSavedToast": "Passwort erfolgreich geändert.",
+ "googleCalendar": "Google Calendar",
+ "appleCalendar": "Apple Calendar (iCloud)",
+ "syncNow": "Jetzt synchronisieren",
+ "disconnect": "Verbindung trennen",
+ "connectGoogle": "Mit Google verbinden",
+ "connected": "Verbunden",
+ "connectedLastSync": "Verbunden · Zuletzt: {{date}}",
+ "notConnected": "Nicht verbunden",
+ "notConfigured": "Nicht konfiguriert (fehlende .env-Variablen)",
+ "configured": "Konfiguriert (via .env)",
+ "configuredLastSync": "Konfiguriert (via .env) · Zuletzt: {{date}}",
+ "syncSuccess": "{{provider}} synchronisiert.",
+ "disconnectedToast": "{{provider}} getrennt.",
+ "googleOnlyAdmin": "Nur Admin kann Google Calendar verbinden.",
+ "appleOnlyAdmin": "Nur Admin kann Apple Calendar verbinden.",
+ "caldavUrlLabel": "CalDAV-Server-URL",
+ "caldavUrlPlaceholder": "https://caldav.icloud.com",
+ "appleIdLabel": "Apple-ID (E-Mail)",
+ "applePasswordLabel": "App-spezifisches Passwort",
+ "applePasswordHint": "Passwort unter appleid.apple.com → Sicherheit erstellen.",
+ "appleConnectBtn": "Verbinden & testen",
+ "appleConnecting": "Verbinde…",
+ "appleConnectedToast": "Apple Calendar verbunden.",
+ "syncSuccessGoogle": "Kalender-Sync mit Google erfolgreich verbunden.",
+ "syncSuccessApple": "Kalender-Sync mit Apple erfolgreich verbunden.",
+ "syncErrorGoogle": "Verbindung mit Google fehlgeschlagen. Bitte erneut versuchen.",
+ "syncErrorApple": "Verbindung mit Apple fehlgeschlagen. Bitte erneut versuchen.",
+ "addMember": "+ Mitglied hinzufügen",
+ "newMemberTitle": "Neues Familienmitglied",
+ "usernameLabel": "Benutzername",
+ "displayNameLabel": "Anzeigename",
+ "memberPasswordLabel": "Passwort",
+ "colorLabel": "Farbe",
+ "roleLabel": "Rolle",
+ "roleMember": "Mitglied",
+ "roleAdmin": "Admin",
+ "createMember": "Erstellen",
+ "cancelAddMember": "Abbrechen",
+ "memberAddedToast": "{{name}} hinzugefügt.",
+ "deleteMemberConfirm": "{{name}} wirklich löschen?",
+ "memberDeletedToast": "{{name}} gelöscht.",
+ "deleteMemberLabel": "Löschen",
+ "logout": "Abmelden",
+ "synchronizing": "Synchronisiere…",
+ "googleDisconnectConfirm": "Google Calendar-Verbindung trennen?",
+ "appleDisconnectConfirm": "Apple Calendar-Verbindung trennen?"
+ },
+
+ "login": {
+ "tagline": "Familienplanung. Sicher. Datenschutzfreundlich. Open Source.",
+ "usernameLabel": "Benutzername",
+ "usernamePlaceholder": "benutzername",
+ "passwordLabel": "Passwort",
+ "passwordPlaceholder": "••••••••",
+ "loginButton": "Anmelden",
+ "loggingIn": "Wird angemeldet …",
+ "tooManyAttempts": "Zu viele Versuche. Bitte warte kurz.",
+ "invalidCredentials": "Ungültige Anmeldedaten."
+ },
+
+ "install": {
+ "title": "Oikos installieren",
+ "subtitle": "Zur App hinzufügen",
+ "iosTip1": "Tippe auf ",
+ "iosTip2": " \u2192 \"Zum Home-Bildschirm\"",
+ "installButton": "Installieren",
+ "dismissLabel": "Schließen"
+ },
+
+ "modal": {
+ "closeLabel": "Schließen"
+ }
+}
diff --git a/public/locales/en.json b/public/locales/en.json
new file mode 100644
index 0000000..c6c2819
--- /dev/null
+++ b/public/locales/en.json
@@ -0,0 +1,525 @@
+{
+ "common": {
+ "save": "Save",
+ "cancel": "Cancel",
+ "delete": "Delete",
+ "edit": "Edit",
+ "close": "Close",
+ "create": "Create",
+ "add": "Add",
+ "back": "Back",
+ "next": "Next",
+ "loading": "Loading…",
+ "saving": "Saving…",
+ "required": "This field is required.",
+ "error": "Error",
+ "allFieldsRequired": "Please fill in all fields.",
+ "today": "Today",
+ "tomorrow": "Tomorrow",
+ "skipToContent": "Skip to content",
+ "reload": "Reload",
+ "errorOccurred": "Something went wrong.",
+ "unexpectedError": "An unexpected error occurred.",
+ "errorGeneric": "An error occurred.",
+ "updateAvailable": "Update available — reload the page to get the latest version.",
+ "titleRequired": "Title is required",
+ "nameRequired": "Name is required",
+ "contentRequired": "Content is required",
+ "all": "All"
+ },
+
+ "nav": {
+ "dashboard": "Overview",
+ "tasks": "Tasks",
+ "calendar": "Calendar",
+ "meals": "Meals",
+ "shopping": "Shopping",
+ "notes": "Board",
+ "contacts": "Contacts",
+ "budget": "Budget",
+ "settings": "Settings",
+ "main": "Main navigation",
+ "navigation": "Navigation",
+ "quickActions": "Quick actions"
+ },
+
+ "dashboard": {
+ "title": "Overview",
+ "greetingMorning": "Good morning, {{name}}",
+ "greetingDay": "Good afternoon, {{name}}",
+ "greetingEvening": "Good evening, {{name}}",
+ "allDone": "All done",
+ "noEvents": "No events",
+ "noPinnedNotes": "No pinned notes",
+ "todayMeals": "Today's meals",
+ "allLink": "All",
+ "weekLink": "Week",
+ "urgentTasksChip": "{{count}} urgent task",
+ "urgentTasksChipPlural": "{{count}} urgent tasks",
+ "eventsChip": "{{count}} event today",
+ "eventsChipPlural": "{{count}} events today",
+ "todayMealChip": "Today: {{title}}",
+ "loadError": "Dashboard could not be fully loaded.",
+ "weatherRefresh": "Refresh weather",
+ "weatherRefreshTitle": "Refresh",
+ "weatherFeelsLike": "Feels like {{temp}}° · {{humidity}}% · Wind {{wind}} km/h",
+ "fabTaskLabel": "Add task",
+ "fabCalendarLabel": "Add event",
+ "fabShoppingLabel": "Add shopping",
+ "fabNoteLabel": "Add note",
+ "fabTask": "Task",
+ "fabCalendar": "Event",
+ "fabShopping": "Shopping",
+ "fabNote": "Note",
+ "overdue": "Overdue",
+ "dueSoon": "Due today",
+ "dueTomorrow": "Due tomorrow",
+ "allDay": "All day"
+ },
+
+ "tasks": {
+ "title": "Tasks",
+ "newTask": "New Task",
+ "editTask": "Edit Task",
+ "emptyTitle": "No tasks — all done?",
+ "emptyDescription": "Create new tasks with the + button.",
+ "titleLabel": "Title *",
+ "titlePlaceholder": "What needs to be done?",
+ "descriptionLabel": "Note",
+ "descriptionPlaceholder": "Optional details…",
+ "priorityLabel": "Priority",
+ "categoryLabel": "Category",
+ "dueDateLabel": "Due date",
+ "dueTimeLabel": "Time",
+ "assignedLabel": "Assigned to",
+ "assignedNobody": "— Nobody —",
+ "statusLabel": "Status",
+ "priorityUrgent": "Urgent",
+ "priorityHigh": "High",
+ "priorityMedium": "Medium",
+ "priorityLow": "Low",
+ "statusOpen": "Open",
+ "statusInProgress": "In Progress",
+ "statusDone": "Done",
+ "categoryHousehold": "Household",
+ "categorySchool": "School",
+ "categoryShopping": "Shopping",
+ "categoryRepair": "Repair",
+ "categoryHealth": "Health",
+ "categoryFinance": "Finance",
+ "categoryLeisure": "Leisure",
+ "categoryMisc": "Miscellaneous",
+ "overdue": "Overdue",
+ "overdueDay": "{{count}}d overdue",
+ "dueToday": "Due today",
+ "dueTomorrow": "Due tomorrow",
+ "groupOverdue": "Overdue",
+ "groupToday": "Today",
+ "groupThisWeek": "This week",
+ "groupNextWeek": "Next week",
+ "groupLater": "Later",
+ "groupNoDate": "No date",
+ "markDone": "Mark {{title}} as done",
+ "editButton": "Edit task",
+ "swipeOpen": "Reopen",
+ "swipeDone": "Done",
+ "swipeEdit": "Edit",
+ "subtaskAdd": "+ Add subtask",
+ "subtaskToggle": "Show subtasks",
+ "subtaskMarkDone": "Mark {{title}} as done",
+ "deleteConfirm": "Delete task and all subtasks?",
+ "savedToast": "Task saved.",
+ "createdToast": "Task created.",
+ "deletedToast": "Task deleted.",
+ "loadError": "Task could not be loaded.",
+ "subtaskPrompt": "Subtask:",
+ "kanbanOpen": "Open",
+ "kanbanInProgress": "In Progress",
+ "kanbanDone": "Done"
+ },
+
+ "shopping": {
+ "title": "Shopping",
+ "noLists": "No lists",
+ "noListsDescription": "Create a list with the + button.",
+ "emptyList": "The list is empty",
+ "emptyListDescription": "Add items using the input field above.",
+ "newListPrompt": "Name for the new list:",
+ "newListButton": "Create new list",
+ "renameListPrompt": "New list name:",
+ "deleteListConfirm": "Delete list \"{{name}}\" and all items?",
+ "deletedListToast": "List deleted.",
+ "itemsRemovedToast": "{{count}} items removed.",
+ "clearChecked": "Remove checked ({{count}})",
+ "itemNamePlaceholder": "Add item…",
+ "itemQtyPlaceholder": "Quantity",
+ "itemNameLabel": "Item name",
+ "itemQtyLabel": "Quantity",
+ "categoryLabel": "Category",
+ "addItemLabel": "Add item",
+ "renameListLabel": "Rename list",
+ "deleteListLabel": "Delete list",
+ "swipeBack": "Undo",
+ "swipeCheck": "Check off",
+ "swipeDelete": "Delete",
+ "markDoneLabel": "Check off {{name}}",
+ "markUndoneLabel": "Uncheck {{name}}",
+ "deleteItemLabel": "Delete {{name}}",
+ "listsLoadError": "Lists could not be loaded.",
+ "itemsLoadError": "Items could not be loaded.",
+ "catFruitVeg": "Fruit & Vegetables",
+ "catBakery": "Bakery",
+ "catDairy": "Dairy",
+ "catMeatFish": "Meat & Fish",
+ "catFrozen": "Frozen",
+ "catDrinks": "Drinks",
+ "catHousehold": "Household",
+ "catDrugstore": "Drugstore",
+ "catMisc": "Miscellaneous"
+ },
+
+ "meals": {
+ "title": "Meal Plan",
+ "noMealPlanned": "No meal planned",
+ "addMeal": "Add {{type}}",
+ "editMeal": "Edit meal",
+ "addMealTitle": "Add meal",
+ "deleteMeal": "Delete meal",
+ "transferToShoppingList": "Add ingredients to shopping list",
+ "today": "Today",
+ "prevWeek": "Previous week",
+ "nextWeek": "Next week",
+ "loadError": "Meal plan could not be loaded.",
+ "typeBreakfast": "Breakfast",
+ "typeLunch": "Lunch",
+ "typeDinner": "Dinner",
+ "typeSnack": "Snack",
+ "dayMo": "Mon",
+ "dayDi": "Tue",
+ "dayMi": "Wed",
+ "dayDo": "Thu",
+ "dayFr": "Fri",
+ "daySa": "Sat",
+ "daySo": "Sun",
+ "dateLabel": "Date",
+ "mealTypeLabel": "Meal",
+ "titleLabel": "Title *",
+ "titlePlaceholder": "e.g. Spaghetti Bolognese",
+ "notesLabel": "Notes",
+ "notesPlaceholder": "Optional…",
+ "ingredientsLabel": "Ingredients",
+ "addIngredient": "Add ingredient",
+ "ingredientNamePlaceholder": "Ingredient",
+ "ingredientQtyPlaceholder": "Quantity",
+ "removeIngredient": "Remove ingredient",
+ "transferLabel": "Transfer ingredients to shopping list",
+ "transferNow": "Transfer now",
+ "noShoppingLists": "No shopping lists available",
+ "transferSuccess": "{{count}} ingredient transferred",
+ "transferSuccessPlural": "{{count}} ingredients transferred",
+ "transferAlreadyDone": "All ingredients already transferred",
+ "ingredientCount": "{{count}} ingredient",
+ "ingredientCountPlural": "{{count}} ingredients",
+ "titleRequired": "Title is required",
+ "loadingIndicator": "Loading…"
+ },
+
+ "calendar": {
+ "title": "Calendar",
+ "newEvent": "New Event",
+ "editEvent": "Edit Event",
+ "addEvent": "Add event",
+ "deleteEvent": "Delete event",
+ "noEvents": "No events in the selected period.",
+ "today": "Today",
+ "back": "Back",
+ "forward": "Forward",
+ "viewMonth": "Month",
+ "viewWeek": "Week",
+ "viewDay": "Day",
+ "viewAgenda": "Agenda",
+ "allDay": "All day",
+ "allDayShort": "all day",
+ "moreEvents": "+{{count}} more",
+ "weekNumberLabel": "W{{week}} · {{month}} {{year}}",
+ "agendaFrom": "From {{date}}",
+ "titleLabel": "Title *",
+ "titlePlaceholder": "e.g. Dentist",
+ "allDayToggle": "All day",
+ "startDateLabel": "Start date",
+ "startTimeLabel": "Start time",
+ "endDateLabel": "End date",
+ "endTimeLabel": "End time",
+ "fromLabel": "From",
+ "toLabel": "To",
+ "locationLabel": "Location",
+ "locationPlaceholder": "Optional",
+ "assignedLabel": "Assigned to",
+ "assignedNobody": "— Nobody —",
+ "colorLabel": "Color",
+ "descriptionLabel": "Description",
+ "descriptionPlaceholder": "Optional…",
+ "popupEdit": "Edit",
+ "deleteConfirm": "Really delete \"{{title}}\"?",
+ "createdToast": "Event created",
+ "savedToast": "Event saved",
+ "deletedToast": "Event deleted",
+ "loadError": "Events could not be loaded.",
+ "saveError": "Error saving",
+ "deleteError": "Error deleting",
+ "titleRequired": "Title is required",
+ "monthJanuary": "January",
+ "monthFebruary": "February",
+ "monthMarch": "March",
+ "monthApril": "April",
+ "monthMay": "May",
+ "monthJune": "June",
+ "monthJuly": "July",
+ "monthAugust": "August",
+ "monthSeptember": "September",
+ "monthOctober": "October",
+ "monthNovember": "November",
+ "monthDecember": "December",
+ "dayShortSunday": "Sun",
+ "dayShortMonday": "Mon",
+ "dayShortTuesday": "Tue",
+ "dayShortWednesday": "Wed",
+ "dayShortThursday": "Thu",
+ "dayShortFriday": "Fri",
+ "dayShortSaturday": "Sat",
+ "dayLongSunday": "Sunday",
+ "dayLongMonday": "Monday",
+ "dayLongTuesday": "Tuesday",
+ "dayLongWednesday": "Wednesday",
+ "dayLongThursday": "Thursday",
+ "dayLongFriday": "Friday",
+ "dayLongSaturday": "Saturday"
+ },
+
+ "notes": {
+ "title": "Board",
+ "newNote": "New Note",
+ "editNote": "Edit Note",
+ "addNoteLabel": "New Note",
+ "searchPlaceholder": "Search notes…",
+ "emptyTitle": "No notes yet",
+ "emptyDescription": "Create a new note with the + button.",
+ "noResultsTitle": "No results",
+ "noResultsDescription": "No note contains \"{{query}}\".",
+ "titleLabel": "Title (optional)",
+ "titlePlaceholder": "No title",
+ "contentLabel": "Content",
+ "contentMarkdownHint": "(Markdown formatting supported)",
+ "contentPlaceholder": "Enter note…",
+ "colorLabel": "Color",
+ "pinnedLabel": "Pin (appears on dashboard)",
+ "pinAction": "Pin",
+ "unpinAction": "Unpin",
+ "deleteLabel": "Delete note",
+ "deleteConfirm": "Really delete this note?",
+ "createdToast": "Note created",
+ "savedToast": "Note saved",
+ "deletedToast": "Note deleted",
+ "loadError": "Notes could not be loaded.",
+ "formatBold": "Bold (Ctrl+B)",
+ "formatItalic": "Italic (Ctrl+I)",
+ "formatUnderline": "Underline (Ctrl+U)",
+ "formatStrikethrough": "Strikethrough",
+ "formatHeading": "Heading",
+ "formatList": "Bullet list",
+ "formatOrderedList": "Numbered list",
+ "formatChecklist": "Checklist",
+ "formatLink": "Link",
+ "formatCode": "Code",
+ "formatQuote": "Quote",
+ "formatDivider": "Divider"
+ },
+
+ "contacts": {
+ "title": "Contacts",
+ "newContact": "New Contact",
+ "editContact": "Edit Contact",
+ "addButton": "New",
+ "newContactLabel": "New Contact",
+ "searchPlaceholder": "Search by name, phone or email…",
+ "importButton": "Import",
+ "importLabel": "Import contact from vCard",
+ "importTooltip": "Import vCard",
+ "emptyTitle": "No contacts yet",
+ "emptyDescription": "Add new contacts with the + button.",
+ "filterAll": "All",
+ "nameLabel": "Name *",
+ "namePlaceholder": "Full name",
+ "categoryLabel": "Category",
+ "phoneLabel": "Phone",
+ "phonePlaceholder": "+1 …",
+ "emailLabel": "Email",
+ "emailPlaceholder": "name@example.com",
+ "addressLabel": "Address",
+ "addressPlaceholder": "Street, ZIP City",
+ "notesLabel": "Notes",
+ "notesPlaceholder": "Optional…",
+ "callLabel": "Call",
+ "emailActionLabel": "Email",
+ "mapsLabel": "Open in Maps",
+ "exportLabel": "Export as vCard",
+ "exportTooltip": "Export vCard",
+ "deleteLabel": "Delete contact",
+ "deleteConfirm": "Really delete this contact?",
+ "deletePersonConfirm": "Really delete \"{{name}}\"?",
+ "savedToast": "Contact saved",
+ "updatedToast": "Contact updated",
+ "deletedToast": "Contact deleted",
+ "importedToast": "{{name}} imported.",
+ "importError": "Import failed: {{error}}",
+ "vcardNoName": "vCard does not contain a name.",
+ "catDoctor": "Doctor",
+ "catSchool": "School/Childcare",
+ "catAuthority": "Authority",
+ "catInsurance": "Insurance",
+ "catCraftsman": "Tradesperson",
+ "catEmergency": "Emergency",
+ "catMisc": "Miscellaneous"
+ },
+
+ "budget": {
+ "title": "Budget",
+ "newEntry": "New Entry",
+ "editEntry": "Edit Entry",
+ "addEntryLabel": "Add entry",
+ "newEntryFabLabel": "New Entry",
+ "currentMonth": "Current",
+ "prevMonth": "Previous month",
+ "nextMonth": "Next month",
+ "income": "Income",
+ "expenses": "Expenses",
+ "balance": "Balance",
+ "byCategory": "By category",
+ "transactions": "Transactions",
+ "emptyTitle": "No entries this month",
+ "emptyDescription": "Add budget entries with the + button.",
+ "csvExport": "CSV",
+ "typeExpense": "Expense",
+ "typeIncome": "Income",
+ "titleLabel": "Title *",
+ "titlePlaceholder": "e.g. Supermarket",
+ "amountLabel": "Amount (€) *",
+ "amountPlaceholder": "0.00",
+ "categoryLabel": "Category",
+ "dateLabel": "Date *",
+ "recurringLabel": "Recurring",
+ "deleteLabel": "Delete entry",
+ "deleteConfirm": "Really delete this entry?",
+ "deletePersonConfirm": "Really delete \"{{title}}\"?",
+ "addedToast": "Entry added",
+ "savedToast": "Entry saved",
+ "deletedToast": "Entry deleted",
+ "loadError": "Budget could not be loaded.",
+ "trendNeutral": "— same as {{month}}",
+ "validAmountRequired": "Please enter a valid amount",
+ "dateRequired": "Date is required",
+ "catFood": "Groceries",
+ "catRent": "Rent",
+ "catInsurance": "Insurance",
+ "catMobility": "Transport",
+ "catLeisure": "Leisure",
+ "catClothing": "Clothing",
+ "catHealth": "Health",
+ "catEducation": "Education",
+ "catMisc": "Miscellaneous",
+ "loadingIndicator": "Loading…"
+ },
+
+ "settings": {
+ "title": "Settings",
+ "sectionDesign": "Appearance",
+ "sectionAccount": "My Account",
+ "sectionCalendarSync": "Calendar Sync",
+ "sectionFamily": "Family Members",
+ "cardAppearance": "Display",
+ "themeSystem": "System",
+ "themeSysLabel": "Use system setting",
+ "themeLight": "Light",
+ "themeLightLabel": "Light mode",
+ "themeDark": "Dark",
+ "themeDarkLabel": "Dark mode",
+ "changePassword": "Change password",
+ "currentPasswordLabel": "Current password",
+ "newPasswordLabel": "New password",
+ "confirmPasswordLabel": "Confirm new password",
+ "savePassword": "Save password",
+ "passwordMismatch": "Passwords do not match.",
+ "passwordSavedToast": "Password changed successfully.",
+ "googleCalendar": "Google Calendar",
+ "appleCalendar": "Apple Calendar (iCloud)",
+ "syncNow": "Sync now",
+ "disconnect": "Disconnect",
+ "connectGoogle": "Connect with Google",
+ "connected": "Connected",
+ "connectedLastSync": "Connected · Last: {{date}}",
+ "notConnected": "Not connected",
+ "notConfigured": "Not configured (missing .env variables)",
+ "configured": "Configured (via .env)",
+ "configuredLastSync": "Configured (via .env) · Last: {{date}}",
+ "syncSuccess": "{{provider}} synced.",
+ "disconnectedToast": "{{provider}} disconnected.",
+ "googleOnlyAdmin": "Only admin can connect Google Calendar.",
+ "appleOnlyAdmin": "Only admin can connect Apple Calendar.",
+ "caldavUrlLabel": "CalDAV Server URL",
+ "caldavUrlPlaceholder": "https://caldav.icloud.com",
+ "appleIdLabel": "Apple ID (email)",
+ "applePasswordLabel": "App-specific password",
+ "applePasswordHint": "Create password at appleid.apple.com → Security.",
+ "appleConnectBtn": "Connect & test",
+ "appleConnecting": "Connecting…",
+ "appleConnectedToast": "Apple Calendar connected.",
+ "syncSuccessGoogle": "Calendar sync with Google connected successfully.",
+ "syncSuccessApple": "Calendar sync with Apple connected successfully.",
+ "syncErrorGoogle": "Connection to Google failed. Please try again.",
+ "syncErrorApple": "Connection to Apple failed. Please try again.",
+ "addMember": "+ Add member",
+ "newMemberTitle": "New Family Member",
+ "usernameLabel": "Username",
+ "displayNameLabel": "Display name",
+ "memberPasswordLabel": "Password",
+ "colorLabel": "Color",
+ "roleLabel": "Role",
+ "roleMember": "Member",
+ "roleAdmin": "Admin",
+ "createMember": "Create",
+ "cancelAddMember": "Cancel",
+ "memberAddedToast": "{{name}} added.",
+ "deleteMemberConfirm": "Really delete {{name}}?",
+ "memberDeletedToast": "{{name}} deleted.",
+ "deleteMemberLabel": "Delete",
+ "logout": "Log out",
+ "synchronizing": "Syncing…",
+ "googleDisconnectConfirm": "Disconnect Google Calendar?",
+ "appleDisconnectConfirm": "Disconnect Apple Calendar?"
+ },
+
+ "login": {
+ "tagline": "Family planning. Secure. Privacy-friendly. Open source.",
+ "usernameLabel": "Username",
+ "usernamePlaceholder": "username",
+ "passwordLabel": "Password",
+ "passwordPlaceholder": "••••••••",
+ "loginButton": "Log in",
+ "loggingIn": "Logging in…",
+ "tooManyAttempts": "Too many attempts. Please wait a moment.",
+ "invalidCredentials": "Invalid credentials."
+ },
+
+ "install": {
+ "title": "Install Oikos",
+ "subtitle": "Add to home screen",
+ "iosTip1": "Tap ",
+ "iosTip2": " → \"Add to Home Screen\"",
+ "installButton": "Install",
+ "dismissLabel": "Close"
+ },
+
+ "modal": {
+ "closeLabel": "Close"
+ }
+}