feat: data foundation (models, secure storage, Retrofit API, repository, L10n)
- java.time via core library desugaring (minSdk 24) - Domain models: CalEvent, AppSettings, account/calendar models - CredentialStore (EncryptedSharedPreferences) + SettingsStore - Retrofit CalendarrApi covering all server endpoints - CalendarRepository: auth, settings, accounts, events (org.json parsing for mixed-type payloads), writable calendars, visibility toggles - Hilt DI (Moshi), dynamic-baseUrl ApiProvider, AuthInterceptor - L10n (de/en) ported from iOS Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
220
app/src/main/java/com/scarriffle/calendarr/ui/L10n.kt
Normal file
220
app/src/main/java/com/scarriffle/calendarr/ui/L10n.kt
Normal file
@@ -0,0 +1,220 @@
|
||||
package com.scarriffle.calendarr.ui
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* In-app localization mirroring the iOS `L10n`. The stored language may be
|
||||
* "de", "en" or "system" (resolve to device language).
|
||||
*/
|
||||
object L10n {
|
||||
|
||||
fun resolved(stored: String): String {
|
||||
if (stored == "de" || stored == "en") return stored
|
||||
val pref = Locale.getDefault().language.lowercase()
|
||||
return if (pref.startsWith("de")) "de" else "en"
|
||||
}
|
||||
|
||||
fun locale(stored: String): Locale = Locale(resolved(stored))
|
||||
|
||||
fun t(key: String, stored: String): String {
|
||||
val lang = resolved(stored)
|
||||
return strings[lang]?.get(key) ?: strings["en"]?.get(key) ?: key
|
||||
}
|
||||
|
||||
fun t(key: String, stored: String, vararg args: Any): String {
|
||||
val template = t(key, stored)
|
||||
// Support both %@ (iOS) and %s / %d (Java) placeholders.
|
||||
val javaTemplate = template.replace("%@", "%s")
|
||||
return runCatching { String.format(locale(stored), javaTemplate, *args) }
|
||||
.getOrDefault(template)
|
||||
}
|
||||
|
||||
private val strings: Map<String, Map<String, String>> = mapOf(
|
||||
"de" to mapOf(
|
||||
"nav.today" to "Heute", "nav.menu" to "Menü", "nav.done" to "Fertig",
|
||||
"view.month" to "Monat", "view.week" to "Woche", "view.day" to "Tag",
|
||||
"view.quarter" to "Quartal", "view.agenda" to "Termine", "view.change" to "Ansicht",
|
||||
"cal.cw" to "KW", "cal.allday" to "Ganztägig",
|
||||
"cal.no_events_title" to "Keine Termine",
|
||||
"cal.no_events_body" to "In den nächsten 90 Tagen sind keine Termine vorhanden.",
|
||||
"cal.loading_more" to "Lade weitere Wochen…", "cal.new_event" to "Neues Ereignis",
|
||||
"menu.section.settings" to "Einstellungen", "menu.profile" to "Profil",
|
||||
"menu.appearance" to "Darstellung", "menu.accounts" to "Konten & Kalender",
|
||||
"menu.server" to "Server", "menu.logout" to "Abmelden", "menu.admin" to "Admin",
|
||||
"menu.sync" to "Mit Server synchronisieren", "menu.sync.section" to "Synchronisierung",
|
||||
"settings.title" to "Darstellung", "settings.loading" to "Lade Einstellungen…",
|
||||
"settings.save" to "Speichern", "settings.saved" to "Gespeichert",
|
||||
"settings.cache.title" to "Vorladen", "settings.cache.range" to "Zeitraum",
|
||||
"settings.cache.1m" to "±1 Monat", "settings.cache.3m" to "±3 Monate",
|
||||
"settings.cache.6m" to "±6 Monate", "settings.cache.1y" to "±1 Jahr",
|
||||
"settings.language" to "Sprache", "lang.system" to "Systemstandard",
|
||||
"lang.german" to "Deutsch", "lang.english" to "English",
|
||||
"settings.colors" to "Farben", "settings.color.primary" to "Primärfarbe",
|
||||
"settings.color.accent" to "Akzentfarbe", "settings.color.today" to "Heutige-Tag-Farbe",
|
||||
"settings.color.divider" to "Monatswechsel-Linie", "settings.color.label" to "Monatskürzel",
|
||||
"settings.textcontrast" to "Schriftkontrast", "settings.linecontrast" to "Linienkontrast",
|
||||
"settings.calview" to "Kalenderansicht", "settings.defaultview" to "Standardansicht",
|
||||
"settings.firstweekday" to "Erster Wochentag", "settings.monday" to "Montag",
|
||||
"settings.sunday" to "Sonntag", "settings.dimpast" to "Vergangene Termine ausgrauen",
|
||||
"settings.hourheight" to "Stundenhöhe",
|
||||
"common.cancel" to "Abbrechen", "common.close" to "Schliessen",
|
||||
"common.ok" to "OK", "common.error" to "Fehler", "common.delete" to "Löschen",
|
||||
"common.save" to "Sichern", "common.retry" to "Erneut versuchen",
|
||||
"server.title" to "Server", "server.connected" to "Verbundener Server",
|
||||
"server.switch" to "Server wechseln", "server.logout_title" to "Abmelden",
|
||||
"server.version" to "Version",
|
||||
"profile.title" to "Profil", "profile.loading" to "Lade Profil…",
|
||||
"profile.account" to "Konto", "profile.username" to "Benutzername",
|
||||
"profile.role" to "Rolle", "profile.role.admin" to "Administrator",
|
||||
"profile.role.user" to "Benutzer", "profile.email" to "E-Mail",
|
||||
"profile.no_email" to "Keine E-Mail", "profile.save_email" to "E-Mail speichern",
|
||||
"profile.email_saved" to "E-Mail gespeichert", "profile.change_password" to "Passwort ändern",
|
||||
"profile.current_password" to "Aktuelles Passwort", "profile.new_password" to "Neues Passwort",
|
||||
"profile.new_password_repeat" to "Neues Passwort wiederholen",
|
||||
"profile.password_mismatch" to "Passwörter stimmen nicht überein",
|
||||
"profile.password_changed" to "Passwort geändert",
|
||||
"profile.twofa" to "Zwei-Faktor-Authentifizierung",
|
||||
"profile.twofa.active" to "2FA ist aktiviert", "profile.twofa.inactive" to "2FA ist deaktiviert",
|
||||
"profile.twofa.enable" to "2FA einrichten", "profile.twofa.disable" to "2FA deaktivieren",
|
||||
"twofa.setup_title" to "2FA einrichten",
|
||||
"twofa.scan_hint" to "Scanne den QR-Code mit deiner Authenticator-App.",
|
||||
"twofa.code_placeholder" to "6-stelliger Code", "twofa.activate" to "Aktivieren",
|
||||
"twofa.disable_title" to "2FA deaktivieren", "twofa.password_placeholder" to "Passwort",
|
||||
"twofa.disable" to "Deaktivieren",
|
||||
"event.title_placeholder" to "Titel", "event.allday" to "Ganztägig",
|
||||
"event.start" to "Start", "event.end" to "Ende", "event.location" to "Ort",
|
||||
"event.description" to "Beschreibung", "event.calendar_section" to "Kalender",
|
||||
"event.no_writable" to "Keine beschreibbaren Kalender vorhanden",
|
||||
"event.calendar_picker" to "Kalender", "event.color_section" to "Farbe",
|
||||
"event.color" to "Terminfarbe", "event.reset_color" to "Zurücksetzen",
|
||||
"event.edit_title" to "Termin bearbeiten", "event.new_title" to "Neuer Termin",
|
||||
"event.save" to "Sichern", "event.add" to "Hinzufügen",
|
||||
"event.delete_confirm" to "Diesen Termin löschen?",
|
||||
"accounts.title" to "Konten", "accounts.loading" to "Lade Konten…",
|
||||
"accounts.caldav.header" to "CalDAV-Konten", "accounts.caldav.empty" to "Keine CalDAV-Konten",
|
||||
"accounts.caldav.add" to "CalDAV hinzufügen", "accounts.local.header" to "Lokale Kalender",
|
||||
"accounts.local.empty" to "Keine lokalen Kalender", "accounts.local.add" to "Lokalen Kalender erstellen",
|
||||
"accounts.ical.header" to "iCal-Abonnements", "accounts.ical.empty" to "Keine Abonnements",
|
||||
"accounts.ical.add" to "iCal-URL abonnieren", "accounts.google.header" to "Google-Konten",
|
||||
"accounts.google.empty" to "Keine Google-Konten",
|
||||
"accounts.google.hint" to "Google-Konten werden über den Browser verknüpft",
|
||||
"accounts.ha.header" to "Home Assistant", "accounts.ha.empty" to "Keine Home Assistant-Konten",
|
||||
"accounts.ha.add" to "Home Assistant hinzufügen",
|
||||
"filter.title" to "Kalender", "filter.empty" to "Keine Kalender vorhanden",
|
||||
"filter.show_all" to "Alle anzeigen", "filter.hide_all" to "Alle ausblenden",
|
||||
"filter.button" to "Kalender ein-/ausblenden",
|
||||
"caldav.display_name" to "Anzeigename", "caldav.url" to "CalDAV-URL",
|
||||
"caldav.username" to "Benutzername", "caldav.password" to "Passwort",
|
||||
"caldav.color" to "Farbe", "caldav.connect" to "Verbinden", "caldav.title" to "CalDAV-Konto",
|
||||
"local.title" to "Lokaler Kalender", "local.name" to "Name", "local.color" to "Farbe",
|
||||
"local.create" to "Erstellen",
|
||||
"ical.title" to "iCal abonnieren", "ical.name" to "Name", "ical.url" to "iCal-URL",
|
||||
"ical.color" to "Farbe", "ical.interval" to "Intervall", "ical.subscribe" to "Abonnieren",
|
||||
"ical.refresh.15m" to "Alle 15 Min.", "ical.refresh.30m" to "Alle 30 Min.",
|
||||
"ical.refresh.1h" to "Stündlich", "ical.refresh.6h" to "Alle 6 Std.", "ical.refresh.1d" to "Täglich",
|
||||
"ha.display_name" to "Anzeigename", "ha.url_placeholder" to "URL (z.B. http://homeassistant.local:8123)",
|
||||
"ha.token" to "Long-Lived Access Token", "ha.connect" to "Verbinden",
|
||||
// Auth screens
|
||||
"auth.server_title" to "Server verbinden", "auth.server_url" to "Server-URL",
|
||||
"auth.server_hint" to "Gib die Adresse deines Calendarr-Servers ein.",
|
||||
"auth.continue" to "Weiter", "auth.checking" to "Verbinde…",
|
||||
"auth.login_title" to "Anmelden", "auth.username" to "Benutzername",
|
||||
"auth.password" to "Passwort", "auth.login" to "Anmelden",
|
||||
"auth.totp" to "2FA-Code", "auth.remember" to "Angemeldet bleiben",
|
||||
"auth.back" to "Zurück",
|
||||
),
|
||||
"en" to mapOf(
|
||||
"nav.today" to "Today", "nav.menu" to "Menu", "nav.done" to "Done",
|
||||
"view.month" to "Month", "view.week" to "Week", "view.day" to "Day",
|
||||
"view.quarter" to "Quarter", "view.agenda" to "Agenda", "view.change" to "View",
|
||||
"cal.cw" to "W", "cal.allday" to "All-day",
|
||||
"cal.no_events_title" to "No events",
|
||||
"cal.no_events_body" to "No events in the next 90 days.",
|
||||
"cal.loading_more" to "Loading more weeks…", "cal.new_event" to "New event",
|
||||
"menu.section.settings" to "Settings", "menu.profile" to "Profile",
|
||||
"menu.appearance" to "Appearance", "menu.accounts" to "Accounts & Calendars",
|
||||
"menu.server" to "Server", "menu.logout" to "Sign out", "menu.admin" to "Admin",
|
||||
"menu.sync" to "Sync with server", "menu.sync.section" to "Synchronization",
|
||||
"settings.title" to "Appearance", "settings.loading" to "Loading settings…",
|
||||
"settings.save" to "Save", "settings.saved" to "Saved",
|
||||
"settings.cache.title" to "Preloading", "settings.cache.range" to "Range",
|
||||
"settings.cache.1m" to "±1 month", "settings.cache.3m" to "±3 months",
|
||||
"settings.cache.6m" to "±6 months", "settings.cache.1y" to "±1 year",
|
||||
"settings.language" to "Language", "lang.system" to "System default",
|
||||
"lang.german" to "Deutsch", "lang.english" to "English",
|
||||
"settings.colors" to "Colors", "settings.color.primary" to "Primary color",
|
||||
"settings.color.accent" to "Accent color", "settings.color.today" to "Today color",
|
||||
"settings.color.divider" to "Month divider line", "settings.color.label" to "Month abbreviation",
|
||||
"settings.textcontrast" to "Text contrast", "settings.linecontrast" to "Line contrast",
|
||||
"settings.calview" to "Calendar view", "settings.defaultview" to "Default view",
|
||||
"settings.firstweekday" to "First day of week", "settings.monday" to "Monday",
|
||||
"settings.sunday" to "Sunday", "settings.dimpast" to "Dim past events",
|
||||
"settings.hourheight" to "Hour height",
|
||||
"common.cancel" to "Cancel", "common.close" to "Close",
|
||||
"common.ok" to "OK", "common.error" to "Error", "common.delete" to "Delete",
|
||||
"common.save" to "Save", "common.retry" to "Retry",
|
||||
"server.title" to "Server", "server.connected" to "Connected server",
|
||||
"server.switch" to "Switch server", "server.logout_title" to "Sign out",
|
||||
"server.version" to "Version",
|
||||
"profile.title" to "Profile", "profile.loading" to "Loading profile…",
|
||||
"profile.account" to "Account", "profile.username" to "Username",
|
||||
"profile.role" to "Role", "profile.role.admin" to "Administrator",
|
||||
"profile.role.user" to "User", "profile.email" to "Email",
|
||||
"profile.no_email" to "No email", "profile.save_email" to "Save email",
|
||||
"profile.email_saved" to "Email saved", "profile.change_password" to "Change password",
|
||||
"profile.current_password" to "Current password", "profile.new_password" to "New password",
|
||||
"profile.new_password_repeat" to "Repeat new password",
|
||||
"profile.password_mismatch" to "Passwords don't match",
|
||||
"profile.password_changed" to "Password changed",
|
||||
"profile.twofa" to "Two-factor authentication",
|
||||
"profile.twofa.active" to "2FA is enabled", "profile.twofa.inactive" to "2FA is disabled",
|
||||
"profile.twofa.enable" to "Set up 2FA", "profile.twofa.disable" to "Disable 2FA",
|
||||
"twofa.setup_title" to "Set up 2FA",
|
||||
"twofa.scan_hint" to "Scan the QR code with your authenticator app.",
|
||||
"twofa.code_placeholder" to "6-digit code", "twofa.activate" to "Activate",
|
||||
"twofa.disable_title" to "Disable 2FA", "twofa.password_placeholder" to "Password",
|
||||
"twofa.disable" to "Disable",
|
||||
"event.title_placeholder" to "Title", "event.allday" to "All-day",
|
||||
"event.start" to "Start", "event.end" to "End", "event.location" to "Location",
|
||||
"event.description" to "Description", "event.calendar_section" to "Calendar",
|
||||
"event.no_writable" to "No writable calendars available",
|
||||
"event.calendar_picker" to "Calendar", "event.color_section" to "Color",
|
||||
"event.color" to "Event color", "event.reset_color" to "Reset",
|
||||
"event.edit_title" to "Edit event", "event.new_title" to "New event",
|
||||
"event.save" to "Save", "event.add" to "Add",
|
||||
"event.delete_confirm" to "Delete this event?",
|
||||
"accounts.title" to "Accounts", "accounts.loading" to "Loading accounts…",
|
||||
"accounts.caldav.header" to "CalDAV accounts", "accounts.caldav.empty" to "No CalDAV accounts",
|
||||
"accounts.caldav.add" to "Add CalDAV", "accounts.local.header" to "Local calendars",
|
||||
"accounts.local.empty" to "No local calendars", "accounts.local.add" to "Create local calendar",
|
||||
"accounts.ical.header" to "iCal subscriptions", "accounts.ical.empty" to "No subscriptions",
|
||||
"accounts.ical.add" to "Subscribe to iCal URL", "accounts.google.header" to "Google accounts",
|
||||
"accounts.google.empty" to "No Google accounts",
|
||||
"accounts.google.hint" to "Google accounts are linked via the browser",
|
||||
"accounts.ha.header" to "Home Assistant", "accounts.ha.empty" to "No Home Assistant accounts",
|
||||
"accounts.ha.add" to "Add Home Assistant",
|
||||
"filter.title" to "Calendars", "filter.empty" to "No calendars available",
|
||||
"filter.show_all" to "Show all", "filter.hide_all" to "Hide all",
|
||||
"filter.button" to "Show/hide calendars",
|
||||
"caldav.display_name" to "Display name", "caldav.url" to "CalDAV URL",
|
||||
"caldav.username" to "Username", "caldav.password" to "Password",
|
||||
"caldav.color" to "Color", "caldav.connect" to "Connect", "caldav.title" to "CalDAV account",
|
||||
"local.title" to "Local calendar", "local.name" to "Name", "local.color" to "Color",
|
||||
"local.create" to "Create",
|
||||
"ical.title" to "Subscribe to iCal", "ical.name" to "Name", "ical.url" to "iCal URL",
|
||||
"ical.color" to "Color", "ical.interval" to "Interval", "ical.subscribe" to "Subscribe",
|
||||
"ical.refresh.15m" to "Every 15 min", "ical.refresh.30m" to "Every 30 min",
|
||||
"ical.refresh.1h" to "Hourly", "ical.refresh.6h" to "Every 6 hours", "ical.refresh.1d" to "Daily",
|
||||
"ha.display_name" to "Display name", "ha.url_placeholder" to "URL (e.g. http://homeassistant.local:8123)",
|
||||
"ha.token" to "Long-Lived Access Token", "ha.connect" to "Connect",
|
||||
// Auth screens
|
||||
"auth.server_title" to "Connect server", "auth.server_url" to "Server URL",
|
||||
"auth.server_hint" to "Enter the address of your Calendarr server.",
|
||||
"auth.continue" to "Continue", "auth.checking" to "Connecting…",
|
||||
"auth.login_title" to "Sign in", "auth.username" to "Username",
|
||||
"auth.password" to "Password", "auth.login" to "Sign in",
|
||||
"auth.totp" to "2FA code", "auth.remember" to "Stay signed in",
|
||||
"auth.back" to "Back",
|
||||
),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user