Bisher las Onyx nur den Schnappschuss aus dem gemeinsamen Ordner. Der ist so aktuell wie der letzte Start der Calendarr-App — wer sie eine Woche nicht öffnet, sieht wochenalte Termine, und Onyx kann nichts dafür und nichts dagegen. Der Live-Weg stand im Plan als „bewusst weggelassen, später ohne Umbau nachrüstbar". Das stimmte: das Quellenprotokoll hat gehalten. Ein einziger Aufruf genügt. /api/caldav/events fasst CalDAV-Konten, lokale Kalender, Geburtstage, iCal-Abos und Google bereits zusammen — nachgebaut wird nichts. Angemeldet wird mit Adresse, Benutzername und Passwort statt mit einem Token, und der Grund steht im Backend: auth.py:17 ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 7 # 7 days Ein eingetragenes Token wäre nach einer Woche tot. Onyx holt sich seines deshalb selbst und erneuert es, bevor es abläuft — die Gültigkeit liest es aus dem Token, statt sieben Tage anzunehmen; die stehen heute so im Server und morgen vielleicht nicht mehr. Kommt trotzdem ein 401, wird einmal neu angemeldet und der Abruf wiederholt. Adresse und Benutzername stehen in den Einstellungen, das Passwort im Schlüsselbund — `defaults read` ist keine Stelle, an der ein Passwort mitgelesen werden soll. Geprüft wird beim Verbinden, nicht erst beim nächsten Laden: ein Tippfehler, den man am Folgetag bemerkt, ist ein vermeidbarer. Der Schnappschuss bleibt das Netz darunter. Ohne Zugangsdaten ändert sich nichts, und ohne Netzwerk hält er, was Calendarr zuletzt geschrieben hat. Nachgesehen wird am Server alle fünf Minuten statt alle zwei: ein Dateizugriff kostet nichts, eine Anfrage über das Netz schon. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
469 lines
11 KiB
Plaintext
469 lines
11 KiB
Plaintext
{
|
||
"sourceLanguage": "en",
|
||
"strings": {
|
||
"": {},
|
||
"%lld": {
|
||
"comment": "A day of the month. The argument is the day of the month.",
|
||
"isCommentAutoGenerated": true,
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "%lld"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "%lld"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.apple": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Apple Kalender"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Apple Calendar"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.both": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Beide"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Both"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.calendarr": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendarr"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendarr"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.readOnly": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Onyx liest nur. Es meldet sich nie selbst an und schreibt nie nach Calendarr."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Onyx only reads. It never signs in and never writes to Calendarr."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.coverage": {
|
||
"extractionState": "stale",
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Bekannt bis %@"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Known through %@"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.coverage %@": {
|
||
"comment": "A footnote in the Calendarr settings, indicating the end of the coverage window.",
|
||
"isCommentAutoGenerated": true,
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Bekannt bis %@"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Known through %@"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.incompatible": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendarr schreibt ein neueres Format. Bitte Onyx aktualisieren."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendarr writes a newer format. Please update Onyx."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.loggedOut": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "In Calendarr nicht angemeldet. Alte Termine werden nicht gezeigt."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Not signed in to Calendarr. Old events are not shown."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.neverWritten": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendarr einmal öffnen, damit ein Schnappschuss geschrieben wird."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Open Calendarr once so it can write a snapshot."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.ready": {
|
||
"extractionState": "stale",
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "%@ Termine, Stand %@"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "%@ events, as of %@"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.ready %@ %@": {
|
||
"comment": "Die Anzahl der Termine in der The argument is the string “–”.",
|
||
"isCommentAutoGenerated": true,
|
||
"localizations": {
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "new",
|
||
"value": "calendar.source.status.ready %1$@ %2$@"
|
||
}
|
||
},
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "%@ Termine, Stand %@"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.unreadable": {
|
||
"extractionState": "stale",
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Schnappschuss unlesbar: %@"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Snapshot unreadable: %@"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.status.unreadable %@": {
|
||
"comment": "A warning message explaining that a Calendarr source is not readable. The argument is a human-readable description of the problem.",
|
||
"isCommentAutoGenerated": true,
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Schnappschuss unlesbar: %@"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Snapshot unreadable: %@"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendar.source.title": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Terminquelle"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendar source"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendarr.live.error.credentials": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Benutzername oder Passwort stimmen nicht."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Wrong username or password."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendarr.live.error.response": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Der Server hat geantwortet, aber nicht verständlich."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "The server replied, but not intelligibly."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendarr.live.error.server": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Diese Adresse ergibt keinen Server."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "That address doesn’t resolve to a server."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"calendarr.live.error.status %lld": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Der Server meldet Fehler %lld."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "The server reports error %lld."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.allDay": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Ganztägig"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "All day"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.day.unknown": {
|
||
"comment": "Erklärt einen ausgegrauten Tag: keine Information, nicht keine Termine",
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Für diesen Tag liegen keine Daten vor"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "No data available for this day"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.denied": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Kein Kalenderzugriff.\nIn den Systemeinstellungen erlauben."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "No calendar access.\nAllow it in System Settings."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.incompatible": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Onyx ist zu alt für diese\nCalendarr-Version. Bitte aktualisieren."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Onyx is too old for this\nCalendarr version. Please update."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.loggedOut": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "In Calendarr anmelden"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Sign in to Calendarr"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.name": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Kalender"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendar"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.neverWritten": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Calendarr einmal öffnen,\ndamit Termine bereitstehen."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Open Calendarr once\nso events become available."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.noUpcoming": {
|
||
"comment": "Nur zeigen, wenn der Zeitraum wirklich abgedeckt ist",
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Nichts mehr für heute"
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Nothing left today"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"widget.calendar.unreadable": {
|
||
"localizations": {
|
||
"de": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Termine nicht lesbar.\nKonfigurationsfehler."
|
||
}
|
||
},
|
||
"en": {
|
||
"stringUnit": {
|
||
"state": "translated",
|
||
"value": "Events unreadable.\nConfiguration error."
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"version": "1.1"
|
||
}
|