From c726320c1e7bea2158fbea84caef13632842b4b8 Mon Sep 17 00:00:00 2001 From: Trey t Date: Tue, 2 Dec 2025 02:02:00 -0600 Subject: [PATCH] Add comprehensive i18n localization for KMM and iOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KMM (Android/Shared): - Add strings.xml with 200+ localized strings - Add translation files for es, fr, de, pt languages - Update all screens to use stringResource() for i18n - Add Accept-Language header to API client for all platforms iOS: - Add L10n.swift helper with type-safe string accessors - Add Localizable.xcstrings with translations for all 5 languages - Update all SwiftUI views to use L10n.* for localized strings - Localize Auth, Residence, Task, Contractor, Document, and Profile views Supported languages: English, Spanish, French, German, Portuguese 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../casera/network/ApiClient.android.kt | 10 + .../composeResources/values-de/strings.xml | 473 + .../composeResources/values-es/strings.xml | 473 + .../composeResources/values-fr/strings.xml | 473 + .../composeResources/values-pt/strings.xml | 473 + .../composeResources/values/strings.xml | 473 + .../com/example/casera/network/ApiClient.kt | 7 + .../ui/screens/ContractorDetailScreen.kt | 68 +- .../casera/ui/screens/ContractorsScreen.kt | 46 +- .../casera/ui/screens/DocumentDetailScreen.kt | 104 +- .../casera/ui/screens/DocumentsScreen.kt | 26 +- .../casera/ui/screens/EditTaskScreen.kt | 37 +- .../casera/ui/screens/ForgotPasswordScreen.kt | 14 +- .../example/casera/ui/screens/HomeScreen.kt | 30 +- .../example/casera/ui/screens/LoginScreen.kt | 20 +- .../example/casera/ui/screens/MainScreen.kt | 18 +- .../screens/NotificationPreferencesScreen.kt | 40 +- .../casera/ui/screens/ProfileScreen.kt | 59 +- .../casera/ui/screens/RegisterScreen.kt | 25 +- .../casera/ui/screens/ResetPasswordScreen.kt | 12 +- .../ui/screens/ResidenceDetailScreen.kt | 76 +- .../casera/ui/screens/ResidenceFormScreen.kt | 50 +- .../casera/ui/screens/ResidencesScreen.kt | 32 +- .../example/casera/ui/screens/TasksScreen.kt | 15 +- .../casera/ui/screens/VerifyEmailScreen.kt | 14 +- .../ui/screens/VerifyResetCodeScreen.kt | 12 +- .../example/casera/network/ApiClient.ios.kt | 14 + .../example/casera/network/ApiClient.js.kt | 12 +- .../example/casera/network/ApiClient.jvm.kt | 12 +- .../casera/network/ApiClient.wasmJs.kt | 12 +- .../Contractor/ContractorDetailView.swift | 54 +- .../Contractor/ContractorFormSheet.swift | 62 +- .../Contractor/ContractorsListView.swift | 12 +- .../Components/DocumentsTabContent.swift | 4 +- .../Components/WarrantiesTabContent.swift | 4 +- .../Documents/Components/WarrantyCard.swift | 18 +- .../iosApp/Documents/DocumentDetailView.swift | 100 +- .../iosApp/Documents/DocumentFormView.swift | 104 +- .../Documents/DocumentsWarrantiesView.swift | 14 +- iosApp/iosApp/Helpers/L10n.swift | 577 + iosApp/iosApp/Localizable.xcstrings | 16033 ++++++++++++++++ iosApp/iosApp/Login/LoginView.swift | 26 +- .../Profile/NotificationPreferencesView.swift | 38 +- iosApp/iosApp/Profile/ProfileTabView.swift | 50 +- iosApp/iosApp/Profile/ProfileView.swift | 22 +- .../iosApp/Profile/ThemeSelectionView.swift | 4 +- iosApp/iosApp/Register/RegisterView.swift | 24 +- .../iosApp/Residence/JoinResidenceView.swift | 14 +- iosApp/iosApp/Residence/ManageUsersView.swift | 6 +- .../Residence/ResidenceDetailView.swift | 42 +- .../iosApp/Residence/ResidencesListView.swift | 6 +- iosApp/iosApp/ResidenceFormView.swift | 50 +- .../Subviews/Task/DynamicTaskColumnView.swift | 2 +- iosApp/iosApp/Subviews/Task/TaskCard.swift | 16 +- iosApp/iosApp/Task/AllTasksView.swift | 32 +- iosApp/iosApp/Task/CompleteTaskView.swift | 54 +- .../iosApp/Task/CompletionHistorySheet.swift | 22 +- iosApp/iosApp/Task/TaskFormView.swift | 60 +- .../iosApp/VerifyEmail/VerifyEmailView.swift | 16 +- 59 files changed, 19839 insertions(+), 757 deletions(-) create mode 100644 composeApp/src/commonMain/composeResources/values-de/strings.xml create mode 100644 composeApp/src/commonMain/composeResources/values-es/strings.xml create mode 100644 composeApp/src/commonMain/composeResources/values-fr/strings.xml create mode 100644 composeApp/src/commonMain/composeResources/values-pt/strings.xml create mode 100644 composeApp/src/commonMain/composeResources/values/strings.xml create mode 100644 iosApp/iosApp/Helpers/L10n.swift create mode 100644 iosApp/iosApp/Localizable.xcstrings diff --git a/composeApp/src/androidMain/kotlin/com/example/casera/network/ApiClient.android.kt b/composeApp/src/androidMain/kotlin/com/example/casera/network/ApiClient.android.kt index 0decd32..b09b039 100644 --- a/composeApp/src/androidMain/kotlin/com/example/casera/network/ApiClient.android.kt +++ b/composeApp/src/androidMain/kotlin/com/example/casera/network/ApiClient.android.kt @@ -2,13 +2,19 @@ package com.example.casera.network import io.ktor.client.* import io.ktor.client.engine.okhttp.* +import io.ktor.client.plugins.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.logging.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.json.Json +import java.util.Locale actual fun getLocalhostAddress(): String = "10.0.2.2" +actual fun getDeviceLanguage(): String { + return Locale.getDefault().language +} + actual fun createHttpClient(): HttpClient { return HttpClient(OkHttp) { install(ContentNegotiation) { @@ -23,5 +29,9 @@ actual fun createHttpClient(): HttpClient { logger = Logger.DEFAULT level = LogLevel.ALL } + + install(DefaultRequest) { + headers.append("Accept-Language", getDeviceLanguage()) + } } } diff --git a/composeApp/src/commonMain/composeResources/values-de/strings.xml b/composeApp/src/commonMain/composeResources/values-de/strings.xml new file mode 100644 index 0000000..97c67c8 --- /dev/null +++ b/composeApp/src/commonMain/composeResources/values-de/strings.xml @@ -0,0 +1,473 @@ + + + + Casera + Verwalten Sie Ihre Immobilien einfach + + + Casera + Verwalten Sie Ihre Immobilien einfach + Benutzername oder E-Mail + Passwort + Anmelden + Passwort vergessen? + Kein Konto? Registrieren + Anmeldung fehlgeschlagen + Passwort anzeigen + Passwort verbergen + + + Konto erstellen + Registrieren Sie sich, um zu beginnen + Vorname + Nachname + E-Mail + Benutzername + Passwort + Passwort bestatigen + Konto erstellen + Bereits ein Konto? Anmelden + Passworter stimmen nicht uberein + + + E-Mail bestatigen + Geben Sie den 6-stelligen Code ein + Bestatigungscode + Bestatigen + Code erneut senden + E-Mail erfolgreich bestatigt + + + Passwort vergessen + Geben Sie Ihre E-Mail ein, um einen Code zu erhalten + E-Mail + Code senden + Wenn ein Konto existiert, wurde ein Code gesendet + + + Passwort zurucksetzen + Geben Sie Ihr neues Passwort ein + Code + Neues Passwort + Neues Passwort bestatigen + Passwort zurucksetzen + Passwort erfolgreich zuruckgesetzt + + + Meine Immobilien + Keine Immobilien + Fugen Sie Ihre erste Immobilie hinzu! + Immobilie hinzufugen + Immobilie hinzufugen + Immobilie bearbeiten + Name der Immobilie + Adresse + Immobilientyp + Notizen + Mochten Sie diese Immobilie wirklich loschen? + Immobilie geloscht + Immobilie teilen + Freigabecode + Lauft ab in %1$s + Immobilie beitreten + Freigabecode eingeben + Beitreten + Immobilienmitglieder + Eigentumer + Mitglied + Benutzer entfernen + Immobiliendetails + Immobilienname * + Name ist erforderlich + Erforderlich + Straßenadresse + Wohnung/Einheit # + Stadt + Bundesland/Kanton + Postleitzahl + Land + Optionale Details + Quadratmeter + Grundstücksgröße (Hektar) + Beschreibung + Hauptwohnsitz + Immobilie Erstellen + Immobilie Aktualisieren + Lade Immobilie... + Fehler beim Laden der Immobilie + Fehler beim Löschen der Immobilie + Fehler beim Generieren des Berichts + Bericht Generieren + Dies wird einen Wartungsbericht für diese Immobilie generieren und per E-Mail senden. Möchten Sie fortfahren? + Generieren + Benutzer Verwalten + Immobilie Bearbeiten + Immobilie Löschen + Sind Sie sicher, dass Sie %1$s löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden. + Adresse + Einheit: %1$s + Immobiliendetails + Schlafzimmer + Badezimmer + Quadratmeter + Grundstücksgröße + Baujahr + %1$s m² + %1$s Hektar + Beschreibung + Kaufinformationen + Kaufdatum + Kaufpreis + Aufgabe Hinzufügen + Noch keine Aufgaben + Fügen Sie eine Aufgabe hinzu, um zu beginnen + Fehler beim Laden der Aufgaben: %1$s + Noch keine Dienstleister + Fügen Sie Dienstleister über den Dienstleister-Tab hinzu + Fehler beim Laden der Dienstleister: %1$s + Aufgabe Abbrechen + Sind Sie sicher, dass Sie \"%1$s\" abbrechen möchten? Diese Aktion kann nicht rückgängig gemacht werden. + Aufgabe Archivieren + Sind Sie sicher, dass Sie \"%1$s\" archivieren möchten? Sie können sie später aus dem Archiv wiederherstellen. + Ablehnen + + + Aufgaben + Keine Aufgaben + Fugen Sie Ihre erste Wartungsaufgabe hinzu + Aufgabe hinzufugen + Aufgabe hinzufugen + Aufgabe bearbeiten + Aufgabentitel + Beschreibung + Kategorie + Prioritat + Haufigkeit + Falligkeitsdatum + Geschatzte Kosten + Dienstleister + Notizen + Mochten Sie diese Aufgabe wirklich loschen? + Aufgabe geloscht + Aufgabendetails + Titel * + Titel ist erforderlich + Kategorie * + Häufigkeit * + Priorität * + Status * + Fälligkeitsdatum (JJJJ-MM-TT) * + Fälligkeitsdatum ist erforderlich + 2025-01-31 + Aufgabe Aktualisieren + Fehler beim Aktualisieren der Aufgabe + + + Uberfallig + Bald fallig + Bevorstehend + In Bearbeitung + Abgeschlossen + Storniert + + + Abschliessen + Starten + Stornieren + Wiederherstellen + Archivieren + Dearchivieren + Aufgabe als abgeschlossen markiert + Aufgabe als in Bearbeitung markiert + Aufgabe storniert + + + Aufgabenabschlusse + Aufgabe abschliessen + Notizen + Tatsachliche Kosten + Abschlussdatum + Fotos + Foto hinzufugen + Diesen Eintrag loschen? + + + Dienstleister + Keine Dienstleister + Fugen Sie vertrauenswurdige Dienstleister hinzu + Fugen Sie Ihren ersten Dienstleister hinzu + Keine Dienstleister gefunden + Dienstleister hinzufugen + Dienstleister hinzufugen + Dienstleister bearbeiten + Name + Firma + Telefon + E-Mail + Fachgebiet + Notizen + Favorit + Favoriten + Favoriten filtern + Nach Fachgebiet filtern + Alle Fachgebiete + Dienstleister suchen... + Suche loschen + Zu Favoriten hinzufugen + Aus Favoriten entfernen + Details anzeigen + %1$d Aufgaben + Mochten Sie diesen Dienstleister wirklich loschen? + Dienstleister geloscht + Anrufen + E-Mail senden + Fehler beim Laden der Dienstleister + Fehler beim Loschen des Dienstleisters + Fehler beim Aktualisieren des Favoriten + Upgrade erforderlich + Sie haben die maximale Anzahl von Dienstleistern fur Ihren aktuellen Plan erreicht. Upgraden Sie auf Pro fur unbegrenzte Dienstleister. + Dienstleisterdetails + Favorit umschalten + Webseite + Wegbeschreibung + Kontaktinformationen + Keine Kontaktinformationen verfügbar + Adresse + Standort + Zugehörige Immobilie + Immobilie + Notizen + Statistiken + Aufgaben\nAbgeschlossen + Durchschnittliche\nBewertung + Informationen + Hinzugefügt Von + Mitglied Seit + Dienstleister Löschen + Sind Sie sicher, dass Sie diesen Dienstleister löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden. + %1$d abgeschlossene Aufgaben + + + Dokumente + Dokumente und Garantien + Keine Dokumente + Speichern Sie wichtige Dokumente und Garantien + Dokument hinzufugen + Dokument hinzufugen + Dokument bearbeiten + Titel + Beschreibung + Dokumenttyp + Anbieter + Seriennummer + Modellnummer + Kaufdatum + Kaufpreis + Ablaufdatum + Mochten Sie dieses Dokument wirklich loschen? + Dokument geloscht + Garantien + Garantien + Dokumente + Datei hochladen + Dokument anzeigen + Alle Kategorien + Alle Typen + Aktive filtern + Filter + Upgrade erforderlich + Sie haben die maximale Anzahl von Dokumenten fur Ihren aktuellen Plan erreicht. Upgraden Sie auf Pro fur unbegrenzte Dokumente. + Dokumentdetails + Status + Inaktiv + Abgelaufen + Läuft bald ab + Aktiv + Verbleibende Tage + Grundinformationen + Artikeldetails + Artikelname + Modellnummer + Seriennummer + Anbieter + Anbieterkontakt + Anspruchsinformationen + Anspruchstelefon + Anspruchs-E-Mail + Anspruchs-Webseite + Wichtige Daten + Kaufdatum + Startdatum + Enddatum + Zuordnungen + Immobilie + Dienstleister + Dienstleistertelefon + Zusätzliche Informationen + Tags + Notizen + Bilder (%1$d) + Angehängte Datei + Dateityp + Dateigröße + Datei Herunterladen + Metadaten + Hochgeladen Von + Erstellt + Aktualisiert + Dokument Löschen + Sind Sie sicher, dass Sie dieses Dokument löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden. + Fehler beim Laden des Dokuments + Fehler beim Löschen des Dokuments + Dokumentbilder + Bild %1$d von %2$d + Fehler beim Laden des Bildes + Fehler beim Laden des Bildes + Zurück + Weiter + + + Profil + Profil bearbeiten + Profil aktualisieren + Vorname + Nachname + E-Mail + Telefon + Anderungen speichern + Abmelden + Mochten Sie sich wirklich abmelden? + Einstellungen + Benachrichtigungen + Benachrichtigungseinstellungen verwalten + Design + Erscheinungsbild + Design andern + Profilinformationen + Profil-Aktualisierung fehlgeschlagen + Fehler beim Laden der Benutzerdaten + Nicht authentifiziert + Profilaktualisierung demnachst verfugbar + E-Mail ist erforderlich + Profil erfolgreich aktualisiert + Abonnement + Pro-Plan + Kostenloser Plan + Aktiv bis %1$s + Eingeschrankte Funktionen + Auf Pro upgraden + Verwalten Sie Ihr Abonnement im Google Play Store + + + Einstellungen + Benachrichtigungseinstellungen + App-Design + Sprache + Uber + Datenschutzrichtlinie + Nutzungsbedingungen + + + Benachrichtigungen + Keine Benachrichtigungen + Aufgabenerinnerungen + Aufgabe abgeschlossen + Immobilie geteilt + Aktiviert + Deaktiviert + Benachrichtigungseinstellungen + Wählen Sie, welche Benachrichtigungen Sie erhalten möchten + Aufgabenbenachrichtigungen + Andere Benachrichtigungen + Aufgabe Bald Fällig + Erinnerungen für anstehende Aufgaben + Aufgabe Überfällig + Warnungen für überfällige Aufgaben + Wenn jemand eine Aufgabe abschließt + Aufgabe Zugewiesen + Wenn Ihnen eine Aufgabe zugewiesen wird + Wenn jemand eine Immobilie mit Ihnen teilt + Garantie Läuft Ab + Erinnerungen für ablaufende Garantien + + + Speichern + Abbrechen + Loschen + Bearbeiten + Fertig + Schliessen + Zuruck + Weiter + Absenden + Bestatigen + Wird geladen... + Fehler + Erneut versuchen + Erfolg + Suchen + Filtern + Sortieren + Aktualisieren + Auswahlen + Keine + Alle + Ja + Nein + OK + + + Etwas ist schiefgelaufen. Bitte versuchen Sie es erneut. + Netzwerkfehler. Uberprufen Sie Ihre Verbindung. + Zeituberschreitung. Bitte versuchen Sie es erneut. + Serverfehler. Bitte versuchen Sie es spater erneut. + Sitzung abgelaufen. Bitte melden Sie sich erneut an. + Nicht gefunden + Bitte uberprufen Sie Ihre Eingabe + Dieses Feld ist erforderlich + + + Zuruck + Schliessen + Menu offnen + Neues Element hinzufugen + Element bearbeiten + Element loschen + Inhalt aktualisieren + Suchen + Filteroptionen + Inhalt wird geladen + + + Heute + Gestern + Morgen + vor %1$d Tagen + in %1$d Tagen + + + Willkommen zuruck + Verwalten Sie Ihre Immobilien + Laden fehlgeschlagen + Abmelden + Immobilien + Aufgaben + Alle Immobilien Anzeigen + Alle Aufgaben Anzeigen + Ubersicht + Ihre Immobilienstatistiken + Aufgaben Gesamt + Ausstehend + Verwalten Sie Ihre Wohnungen + Aufgaben anzeigen und verwalten + + + Abonnement + Kostenlos + Premium + Upgrade + Kaufe wiederherstellen + Premium-Funktionen + Sie haben das Immobilienlimit Ihres Plans erreicht + Sie haben das Aufgabenlimit Ihres Plans erreicht + diff --git a/composeApp/src/commonMain/composeResources/values-es/strings.xml b/composeApp/src/commonMain/composeResources/values-es/strings.xml new file mode 100644 index 0000000..101c556 --- /dev/null +++ b/composeApp/src/commonMain/composeResources/values-es/strings.xml @@ -0,0 +1,473 @@ + + + + Casera + Administra tus propiedades con facilidad + + + Casera + Administra tus propiedades con facilidad + Usuario o Correo + Contrasena + Iniciar Sesion + Olvidaste tu Contrasena? + No tienes cuenta? Registrate + Error de Inicio de Sesion + Mostrar contrasena + Ocultar contrasena + + + Crear Cuenta + Registrate para comenzar + Nombre + Apellido + Correo Electronico + Usuario + Contrasena + Confirmar Contrasena + Crear Cuenta + Ya tienes cuenta? Inicia Sesion + Las contrasenas no coinciden + + + Verificar Correo + Ingresa el codigo de 6 digitos enviado a tu correo + Codigo de Verificacion + Verificar + Reenviar Codigo + Correo verificado correctamente + + + Olvidaste tu Contrasena + Ingresa tu correo para recibir un codigo + Correo Electronico + Enviar Codigo + Si existe una cuenta, se envio un codigo + + + Restablecer Contrasena + Ingresa tu nueva contrasena + Codigo + Nueva Contrasena + Confirmar Nueva Contrasena + Restablecer Contrasena + Contrasena restablecida correctamente + + + Mis Propiedades + Sin propiedades + Agrega tu primera propiedad para comenzar! + Agregar Propiedad + Agregar Propiedad + Editar Propiedad + Nombre de la Propiedad + Direccion + Tipo de Propiedad + Notas + Seguro que quieres eliminar esta propiedad? + Propiedad eliminada + Compartir Propiedad + Codigo para Compartir + Expira en %1$s + Unirse a Propiedad + Ingresa el Codigo + Unirse + Miembros de la Propiedad + Propietario + Miembro + Eliminar Usuario + Detalles de la Propiedad + Nombre de la Propiedad * + El nombre es requerido + Requerido + Direccion + Apartamento/Unidad # + Ciudad + Estado/Provincia + Codigo Postal + Pais + Detalles Opcionales + Metros Cuadrados + Tamano del Lote (acres) + Descripcion + Residencia Principal + Crear Residencia + Actualizar Residencia + Cargando residencia... + Error al Cargar Propiedad + Error al Eliminar Propiedad + Error al Generar Reporte + Generar Reporte + Esto generara y enviara por correo un reporte de mantenimiento para esta propiedad. Deseas continuar? + Generar + Administrar Usuarios + Editar Residencia + Eliminar Residencia + Seguro que deseas eliminar %1$s? Esta accion no se puede deshacer. + Direccion + Unidad: %1$s + Detalles de la Propiedad + Habitaciones + Banos + Metros Cuadrados + Tamano del Lote + Ano de Construccion + %1$s m2 + %1$s acres + Descripcion + Informacion de Compra + Fecha de Compra + Precio de Compra + Agregar Tarea + Sin tareas aun + Agrega una tarea para comenzar + Error al cargar tareas: %1$s + Sin contratistas aun + Agrega contratistas desde la pestana de Contratistas + Error al cargar contratistas: %1$s + Cancelar Tarea + Seguro que deseas cancelar \"%1$s\"? Esta accion no se puede deshacer. + Archivar Tarea + Seguro que deseas archivar \"%1$s\"? Puedes desarchivarla despues desde tareas archivadas. + Descartar + + + Tareas + Sin tareas + Agrega tu primera tarea de mantenimiento + Agregar Tarea + Agregar Tarea + Editar Tarea + Titulo de la Tarea + Descripcion + Categoria + Prioridad + Frecuencia + Fecha de Vencimiento + Costo Estimado + Contratista + Notas + Seguro que quieres eliminar esta tarea? + Tarea eliminada + Detalles de la Tarea + Titulo * + El titulo es requerido + Categoria * + Frecuencia * + Prioridad * + Estado * + Fecha de Vencimiento (AAAA-MM-DD) * + La fecha de vencimiento es requerida + 2025-01-31 + Actualizar Tarea + Error al Actualizar Tarea + + + Vencidas + Por Vencer + Proximas + En Progreso + Completadas + Canceladas + + + Completar + Iniciar + Cancelar + Restaurar + Archivar + Desarchivar + Tarea marcada como completada + Tarea marcada como en progreso + Tarea cancelada + + + Registros de Tareas + Completar Tarea + Notas + Costo Real + Fecha de Finalizacion + Fotos + Agregar Foto + Eliminar este registro? + + + Contratistas + Sin contratistas + Agrega contratistas de confianza + Agrega tu primer contratista para empezar + No se encontraron contratistas + Agregar Contratista + Agregar Contratista + Editar Contratista + Nombre + Empresa + Telefono + Correo + Especialidad + Notas + Favorito + Favoritos + Filtrar favoritos + Filtrar por especialidad + Todas las Especialidades + Buscar contratistas... + Limpiar busqueda + Agregar a favoritos + Quitar de favoritos + Ver detalles + %1$d tareas + Seguro que quieres eliminar este contratista? + Contratista eliminado + Llamar + Enviar Correo + Error al Cargar Contratistas + Error al Eliminar Contratista + Error al Actualizar Favorito + Actualizacion Requerida + Has alcanzado el maximo de contratistas para tu plan actual. Actualiza a Pro para contratistas ilimitados. + Detalles del Contratista + Cambiar favorito + Sitio Web + Direcciones + Informacion de Contacto + No hay informacion de contacto disponible + Direccion + Ubicacion + Propiedad Asociada + Propiedad + Notas + Estadisticas + Tareas\nCompletadas + Calificacion\nPromedio + Informacion + Agregado Por + Miembro Desde + Eliminar Contratista + Seguro que deseas eliminar este contratista? Esta accion no se puede deshacer. + %1$d tareas completadas + + + Documentos + Documentos y Garantias + Sin documentos + Guarda documentos importantes y garantias + Agregar Documento + Agregar Documento + Editar Documento + Titulo + Descripcion + Tipo de Documento + Proveedor + Numero de Serie + Numero de Modelo + Fecha de Compra + Precio de Compra + Fecha de Vencimiento + Seguro que quieres eliminar este documento? + Documento eliminado + Garantias + Garantias + Documentos + Subir Archivo + Ver Documento + Todas las Categorias + Todos los Tipos + Filtrar activos + Filtros + Actualizacion Requerida + Has alcanzado el maximo de documentos para tu plan actual. Actualiza a Pro para documentos ilimitados. + Detalles del Documento + Estado + Inactivo + Expirado + Expira pronto + Activo + Dias Restantes + Informacion Basica + Detalles del Articulo + Nombre del Articulo + Numero de Modelo + Numero de Serie + Proveedor + Contacto del Proveedor + Informacion de Reclamo + Telefono de Reclamo + Correo de Reclamo + Sitio Web de Reclamo + Fechas Importantes + Fecha de Compra + Fecha de Inicio + Fecha de Fin + Asociaciones + Residencia + Contratista + Telefono del Contratista + Informacion Adicional + Etiquetas + Notas + Imagenes (%1$d) + Archivo Adjunto + Tipo de Archivo + Tamano del Archivo + Descargar Archivo + Metadatos + Subido Por + Creado + Actualizado + Eliminar Documento + Seguro que deseas eliminar este documento? Esta accion no se puede deshacer. + Error al Cargar Documento + Error al Eliminar Documento + Imagenes del Documento + Imagen %1$d de %2$d + Error al cargar imagen + Error al cargar imagen + Anterior + Siguiente + + + Perfil + Editar Perfil + Actualiza Tu Perfil + Nombre + Apellido + Correo Electronico + Telefono + Guardar Cambios + Cerrar Sesion + Seguro que quieres cerrar sesion? + Configuracion + Notificaciones + Administrar preferencias de notificaciones + Tema + Apariencia + Cambiar tema + Informacion del Perfil + Error al Actualizar Perfil + Error al cargar datos del usuario + No autenticado + Actualizacion de perfil proximamente + El correo es requerido + Perfil actualizado exitosamente + Suscripcion + Plan Pro + Plan Gratis + Activo hasta %1$s + Funciones limitadas + Actualizar a Pro + Administra tu suscripcion en Google Play Store + + + Configuracion + Preferencias de Notificaciones + Tema de la App + Idioma + Acerca de + Politica de Privacidad + Terminos de Servicio + + + Notificaciones + Sin notificaciones + Recordatorios de Tareas + Tarea Completada + Propiedad Compartida + Activado + Desactivado + Preferencias de Notificaciones + Elige que notificaciones deseas recibir + Notificaciones de Tareas + Otras Notificaciones + Tarea Por Vencer + Recordatorios de tareas proximas + Tarea Vencida + Alertas de tareas vencidas + Cuando alguien completa una tarea + Tarea Asignada + Cuando te asignan una tarea + Cuando alguien comparte una propiedad contigo + Garantia Por Vencer + Recordatorios de garantias por vencer + + + Guardar + Cancelar + Eliminar + Editar + Listo + Cerrar + Atras + Siguiente + Enviar + Confirmar + Cargando... + Error + Reintentar + Exito + Buscar + Filtrar + Ordenar + Actualizar + Seleccionar + Ninguno + Todo + Si + No + OK + + + Algo salio mal. Por favor intenta de nuevo. + Error de red. Verifica tu conexion. + Tiempo de espera agotado. Intenta de nuevo. + Error del servidor. Intenta mas tarde. + Sesion expirada. Inicia sesion de nuevo. + No encontrado + Verifica los datos ingresados + Este campo es requerido + + + Volver + Cerrar + Abrir menu + Agregar nuevo + Editar + Eliminar + Actualizar contenido + Buscar + Opciones de filtro + Cargando contenido + + + Hoy + Ayer + Manana + hace %1$d dias + en %1$d dias + + + Bienvenido + Administra tus propiedades + Error al Cargar Resumen + Cerrar Sesion + Propiedades + Tareas + Ver Todas las Propiedades + Ver Todas las Tareas + Resumen + Estadisticas de propiedades + Total de Tareas + Pendientes + Administra tus residencias + Ver y administrar tareas + + + Suscripcion + Gratis + Premium + Mejorar + Restaurar Compras + Funciones Premium + Has alcanzado el limite de propiedades de tu plan + Has alcanzado el limite de tareas de tu plan + diff --git a/composeApp/src/commonMain/composeResources/values-fr/strings.xml b/composeApp/src/commonMain/composeResources/values-fr/strings.xml new file mode 100644 index 0000000..16c998a --- /dev/null +++ b/composeApp/src/commonMain/composeResources/values-fr/strings.xml @@ -0,0 +1,473 @@ + + + + Casera + Gerez vos proprietes facilement + + + Casera + Gerez vos proprietes facilement + Nom d\'utilisateur ou Email + Mot de passe + Se connecter + Mot de passe oublie ? + Pas de compte ? S\'inscrire + Echec de connexion + Afficher le mot de passe + Masquer le mot de passe + + + Creer un compte + Inscrivez-vous pour commencer + Prenom + Nom + Email + Nom d\'utilisateur + Mot de passe + Confirmer le mot de passe + Creer un compte + Deja un compte ? Se connecter + Les mots de passe ne correspondent pas + + + Verifier l\'email + Entrez le code a 6 chiffres envoye a votre email + Code de verification + Verifier + Renvoyer le code + Email verifie avec succes + + + Mot de passe oublie + Entrez votre email pour recevoir un code + Email + Envoyer le code + Si un compte existe, un code a ete envoye + + + Reinitialiser le mot de passe + Entrez votre nouveau mot de passe + Code + Nouveau mot de passe + Confirmer le nouveau mot de passe + Reinitialiser + Mot de passe reinitialise avec succes + + + Mes Proprietes + Aucune propriete + Ajoutez votre premiere propriete pour commencer ! + Ajouter une propriete + Ajouter une propriete + Modifier la propriete + Nom de la propriete + Adresse + Type de propriete + Notes + Etes-vous sur de vouloir supprimer cette propriete ? + Propriete supprimee + Partager la propriete + Code de partage + Expire dans %1$s + Rejoindre une propriete + Entrez le code de partage + Rejoindre + Membres de la propriete + Proprietaire + Membre + Supprimer l\'utilisateur + Détails de la Propriété + Nom de la Propriété * + Le nom est requis + Requis + Adresse + Appartement/Unité # + Ville + État/Province + Code Postal + Pays + Détails Optionnels + Mètres Carrés + Taille du Terrain (acres) + Description + Résidence Principale + Créer la Résidence + Mettre à Jour la Résidence + Chargement de la résidence... + Échec du Chargement de la Propriété + Échec de la Suppression de la Propriété + Échec de la Génération du Rapport + Générer le Rapport + Ceci va générer et envoyer par email un rapport de maintenance pour cette propriété. Voulez-vous continuer? + Générer + Gérer les Utilisateurs + Modifier la Résidence + Supprimer la Résidence + Êtes-vous sûr de vouloir supprimer %1$s? Cette action est irréversible. + Adresse + Unité: %1$s + Détails de la Propriété + Chambres + Salles de Bain + Mètres Carrés + Taille du Terrain + Année de Construction + %1$s m² + %1$s acres + Description + Informations d\'Achat + Date d\'Achat + Prix d\'Achat + Ajouter une Tâche + Pas encore de tâches + Ajoutez une tâche pour commencer + Erreur de chargement des tâches: %1$s + Pas encore de prestataires + Ajoutez des prestataires depuis l\'onglet Prestataires + Erreur de chargement des prestataires: %1$s + Annuler la Tâche + Êtes-vous sûr de vouloir annuler \"%1$s\"? Cette action est irréversible. + Archiver la Tâche + Êtes-vous sûr de vouloir archiver \"%1$s\"? Vous pourrez la désarchiver plus tard. + Ignorer + + + Taches + Aucune tache + Ajoutez votre premiere tache de maintenance + Ajouter une tache + Ajouter une tache + Modifier la tache + Titre de la tache + Description + Categorie + Priorite + Frequence + Date d\'echeance + Cout estime + Prestataire + Notes + Etes-vous sur de vouloir supprimer cette tache ? + Tache supprimee + Détails de la Tâche + Titre * + Le titre est requis + Catégorie * + Fréquence * + Priorité * + Statut * + Date d\'Échéance (AAAA-MM-JJ) * + La date d\'échéance est requise + 2025-01-31 + Mettre à Jour la Tâche + Échec de la Mise à Jour de la Tâche + + + En retard + Bientot dues + A venir + En cours + Terminees + Annulees + + + Terminer + Demarrer + Annuler + Restaurer + Archiver + Desarchiver + Tache marquee comme terminee + Tache marquee comme en cours + Tache annulee + + + Historique des taches + Terminer la tache + Notes + Cout reel + Date de completion + Photos + Ajouter une photo + Supprimer cet enregistrement ? + + + Prestataires + Aucun prestataire + Ajoutez des prestataires de confiance + Ajoutez votre premier prestataire pour commencer + Aucun prestataire trouve + Ajouter un prestataire + Ajouter un prestataire + Modifier le prestataire + Nom + Entreprise + Telephone + Email + Specialite + Notes + Favori + Favoris + Filtrer les favoris + Filtrer par specialite + Toutes les specialites + Rechercher des prestataires... + Effacer la recherche + Ajouter aux favoris + Retirer des favoris + Voir les details + %1$d taches + Etes-vous sur de vouloir supprimer ce prestataire ? + Prestataire supprime + Appeler + Envoyer un email + Echec du chargement des prestataires + Echec de la suppression du prestataire + Echec de la mise a jour du favori + Mise a niveau requise + Vous avez atteint le nombre maximum de prestataires pour votre forfait actuel. Passez a Pro pour des prestataires illimites. + Détails du Prestataire + Basculer favori + Site Web + Itinéraire + Informations de Contact + Aucune information de contact disponible + Adresse + Emplacement + Propriété Associée + Propriété + Notes + Statistiques + Tâches\nTerminées + Note\nMoyenne + Informations + Ajouté Par + Membre Depuis + Supprimer le Prestataire + Êtes-vous sûr de vouloir supprimer ce prestataire? Cette action est irréversible. + %1$d tâches terminées + + + Documents + Documents et Garanties + Aucun document + Stockez vos documents importants et garanties + Ajouter un document + Ajouter un document + Modifier le document + Titre + Description + Type de document + Fournisseur + Numero de serie + Numero de modele + Date d\'achat + Prix d\'achat + Date d\'expiration + Etes-vous sur de vouloir supprimer ce document ? + Document supprime + Garanties + Garanties + Documents + Telecharger un fichier + Voir le document + Toutes les categories + Tous les types + Filtrer les actifs + Filtres + Mise a niveau requise + Vous avez atteint le nombre maximum de documents pour votre forfait actuel. Passez a Pro pour des documents illimites. + Détails du Document + Statut + Inactif + Expiré + Expire bientôt + Actif + Jours Restants + Informations de Base + Détails de l\'Article + Nom de l\'Article + Numéro de Modèle + Numéro de Série + Fournisseur + Contact du Fournisseur + Informations de Réclamation + Téléphone de Réclamation + Email de Réclamation + Site Web de Réclamation + Dates Importantes + Date d\'Achat + Date de Début + Date de Fin + Associations + Résidence + Prestataire + Téléphone du Prestataire + Informations Supplémentaires + Tags + Notes + Images (%1$d) + Fichier Joint + Type de Fichier + Taille du Fichier + Télécharger le Fichier + Métadonnées + Téléchargé Par + Créé + Mis à Jour + Supprimer le Document + Êtes-vous sûr de vouloir supprimer ce document? Cette action est irréversible. + Échec du Chargement du Document + Échec de la Suppression du Document + Images du Document + Image %1$d sur %2$d + Erreur de chargement de l\'image + Échec du chargement de l\'image + Précédent + Suivant + + + Profil + Modifier le profil + Mettre a jour votre profil + Prenom + Nom + Email + Telephone + Enregistrer + Se deconnecter + Etes-vous sur de vouloir vous deconnecter ? + Parametres + Notifications + Gerer les preferences de notifications + Theme + Apparence + Changer le theme + Informations du profil + Echec de la mise a jour du profil + Echec du chargement des donnees utilisateur + Non authentifie + Mise a jour du profil bientot disponible + L\'email est requis + Profil mis a jour avec succes + Abonnement + Forfait Pro + Forfait Gratuit + Actif jusqu\'au %1$s + Fonctionnalites limitees + Passer a Pro + Gerez votre abonnement dans Google Play Store + + + Parametres + Preferences de notifications + Theme de l\'application + Langue + A propos + Politique de confidentialite + Conditions d\'utilisation + + + Notifications + Aucune notification + Rappels de taches + Tache terminee + Propriete partagee + Active + Desactive + Préférences de Notifications + Choisissez les notifications que vous souhaitez recevoir + Notifications de Tâches + Autres Notifications + Tâche Bientôt Due + Rappels pour les tâches à venir + Tâche en Retard + Alertes pour les tâches en retard + Quand quelqu\'un termine une tâche + Tâche Assignée + Quand une tâche vous est assignée + Quand quelqu\'un partage une propriété avec vous + Garantie Expirante + Rappels pour les garanties qui expirent + + + Enregistrer + Annuler + Supprimer + Modifier + Termine + Fermer + Retour + Suivant + Soumettre + Confirmer + Chargement... + Erreur + Reessayer + Succes + Rechercher + Filtrer + Trier + Actualiser + Selectionner + Aucun + Tous + Oui + Non + OK + + + Une erreur s\'est produite. Veuillez reessayer. + Erreur reseau. Verifiez votre connexion. + Delai d\'attente depasse. Veuillez reessayer. + Erreur serveur. Veuillez reessayer plus tard. + Session expiree. Veuillez vous reconnecter. + Non trouve + Veuillez verifier vos donnees + Ce champ est requis + + + Retour + Fermer + Ouvrir le menu + Ajouter un nouvel element + Modifier l\'element + Supprimer l\'element + Actualiser le contenu + Rechercher + Options de filtre + Chargement du contenu + + + Aujourd\'hui + Hier + Demain + il y a %1$d jours + dans %1$d jours + + + Bon retour + Gerez vos proprietes + Echec du Chargement + Deconnexion + Proprietes + Taches + Voir Toutes les Proprietes + Voir Toutes les Taches + Apercu + Statistiques de vos proprietes + Total des Taches + En Attente + Gerez vos residences + Voir et gerer les taches + + + Abonnement + Gratuit + Premium + Ameliorer + Restaurer les achats + Fonctionnalites Premium + Vous avez atteint la limite de proprietes de votre forfait + Vous avez atteint la limite de taches de votre forfait + diff --git a/composeApp/src/commonMain/composeResources/values-pt/strings.xml b/composeApp/src/commonMain/composeResources/values-pt/strings.xml new file mode 100644 index 0000000..63d7899 --- /dev/null +++ b/composeApp/src/commonMain/composeResources/values-pt/strings.xml @@ -0,0 +1,473 @@ + + + + Casera + Gerencie suas propriedades com facilidade + + + Casera + Gerencie suas propriedades com facilidade + Usuario ou Email + Senha + Entrar + Esqueceu a Senha? + Nao tem conta? Cadastre-se + Falha no Login + Mostrar senha + Ocultar senha + + + Criar Conta + Cadastre-se para comecar + Nome + Sobrenome + Email + Usuario + Senha + Confirmar Senha + Criar Conta + Ja tem conta? Entrar + As senhas nao coincidem + + + Verificar Email + Digite o codigo de 6 digitos enviado para seu email + Codigo de Verificacao + Verificar + Reenviar Codigo + Email verificado com sucesso + + + Esqueceu a Senha + Digite seu email para receber um codigo + Email + Enviar Codigo + Se uma conta existir, um codigo foi enviado + + + Redefinir Senha + Digite sua nova senha + Codigo + Nova Senha + Confirmar Nova Senha + Redefinir Senha + Senha redefinida com sucesso + + + Minhas Propriedades + Sem propriedades + Adicione sua primeira propriedade para comecar! + Adicionar Propriedade + Adicionar Propriedade + Editar Propriedade + Nome da Propriedade + Endereco + Tipo de Propriedade + Notas + Tem certeza que deseja excluir esta propriedade? + Propriedade excluida + Compartilhar Propriedade + Codigo de Compartilhamento + Expira em %1$s + Entrar em Propriedade + Digite o Codigo + Entrar + Membros da Propriedade + Proprietario + Membro + Remover Usuario + Detalhes da Propriedade + Nome da Propriedade * + Nome é obrigatório + Obrigatório + Endereço + Apartamento/Unidade # + Cidade + Estado/Província + Código Postal + País + Detalhes Opcionais + Metros Quadrados + Tamanho do Lote (acres) + Descrição + Residência Principal + Criar Residência + Atualizar Residência + Carregando residência... + Falha ao Carregar Propriedade + Falha ao Excluir Propriedade + Falha ao Gerar Relatório + Gerar Relatório + Isso irá gerar e enviar por e-mail um relatório de manutenção para esta propriedade. Deseja continuar? + Gerar + Gerenciar Usuários + Editar Residência + Excluir Residência + Tem certeza que deseja excluir %1$s? Esta ação não pode ser desfeita. + Endereço + Unidade: %1$s + Detalhes da Propriedade + Quartos + Banheiros + Metros Quadrados + Tamanho do Lote + Ano de Construção + %1$s m² + %1$s acres + Descrição + Informações de Compra + Data de Compra + Preço de Compra + Adicionar Tarefa + Sem tarefas ainda + Adicione uma tarefa para começar + Erro ao carregar tarefas: %1$s + Sem prestadores ainda + Adicione prestadores na aba Prestadores + Erro ao carregar prestadores: %1$s + Cancelar Tarefa + Tem certeza que deseja cancelar \"%1$s\"? Esta ação não pode ser desfeita. + Arquivar Tarefa + Tem certeza que deseja arquivar \"%1$s\"? Você pode desarquivar depois. + Dispensar + + + Tarefas + Sem tarefas + Adicione sua primeira tarefa de manutencao + Adicionar Tarefa + Adicionar Tarefa + Editar Tarefa + Titulo da Tarefa + Descricao + Categoria + Prioridade + Frequencia + Data de Vencimento + Custo Estimado + Prestador + Notas + Tem certeza que deseja excluir esta tarefa? + Tarefa excluida + Detalhes da Tarefa + Título * + Título é obrigatório + Categoria * + Frequência * + Prioridade * + Status * + Data de Vencimento (AAAA-MM-DD) * + Data de vencimento é obrigatória + 2025-01-31 + Atualizar Tarefa + Falha ao Atualizar Tarefa + + + Atrasadas + Vencendo + Proximas + Em Progresso + Concluidas + Canceladas + + + Concluir + Iniciar + Cancelar + Restaurar + Arquivar + Desarquivar + Tarefa marcada como concluida + Tarefa marcada como em progresso + Tarefa cancelada + + + Registros de Tarefas + Concluir Tarefa + Notas + Custo Real + Data de Conclusao + Fotos + Adicionar Foto + Excluir este registro? + + + Prestadores + Sem prestadores + Adicione prestadores de confianca + Adicione seu primeiro prestador para comecar + Nenhum prestador encontrado + Adicionar Prestador + Adicionar Prestador + Editar Prestador + Nome + Empresa + Telefone + Email + Especialidade + Notas + Favorito + Favoritos + Filtrar favoritos + Filtrar por especialidade + Todas as Especialidades + Buscar prestadores... + Limpar busca + Adicionar aos favoritos + Remover dos favoritos + Ver detalhes + %1$d tarefas + Tem certeza que deseja excluir este prestador? + Prestador excluido + Ligar + Enviar Email + Falha ao Carregar Prestadores + Falha ao Excluir Prestador + Falha ao Atualizar Favorito + Atualizacao Necessaria + Voce atingiu o numero maximo de prestadores para seu plano atual. Atualize para Pro para prestadores ilimitados. + Detalhes do Prestador + Alternar favorito + Site + Direções + Informações de Contato + Nenhuma informação de contato disponível + Endereço + Localização + Propriedade Associada + Propriedade + Notas + Estatísticas + Tarefas\nConcluídas + Avaliação\nMédia + Informações + Adicionado Por + Membro Desde + Excluir Prestador + Tem certeza que deseja excluir este prestador? Esta ação não pode ser desfeita. + %1$d tarefas concluídas + + + Documentos + Documentos e Garantias + Sem documentos + Guarde documentos importantes e garantias + Adicionar Documento + Adicionar Documento + Editar Documento + Titulo + Descricao + Tipo de Documento + Fornecedor + Numero de Serie + Numero do Modelo + Data da Compra + Preco de Compra + Data de Validade + Tem certeza que deseja excluir este documento? + Documento excluido + Garantias + Garantias + Documentos + Enviar Arquivo + Ver Documento + Todas as Categorias + Todos os Tipos + Filtrar ativos + Filtros + Atualizacao Necessaria + Voce atingiu o numero maximo de documentos para seu plano atual. Atualize para Pro para documentos ilimitados. + Detalhes do Documento + Status + Inativo + Expirado + Expirando em breve + Ativo + Dias Restantes + Informações Básicas + Detalhes do Item + Nome do Item + Número do Modelo + Número de Série + Fornecedor + Contato do Fornecedor + Informações de Reclamação + Telefone de Reclamação + E-mail de Reclamação + Site de Reclamação + Datas Importantes + Data de Compra + Data de Início + Data de Término + Associações + Residência + Prestador + Telefone do Prestador + Informações Adicionais + Tags + Notas + Imagens (%1$d) + Arquivo Anexado + Tipo de Arquivo + Tamanho do Arquivo + Baixar Arquivo + Metadados + Enviado Por + Criado + Atualizado + Excluir Documento + Tem certeza que deseja excluir este documento? Esta ação não pode ser desfeita. + Falha ao Carregar Documento + Falha ao Excluir Documento + Imagens do Documento + Imagem %1$d de %2$d + Erro ao carregar imagem + Falha ao carregar imagem + Anterior + Próximo + + + Perfil + Editar Perfil + Atualizar Seu Perfil + Nome + Sobrenome + Email + Telefone + Salvar Alteracoes + Sair + Tem certeza que deseja sair? + Configuracoes + Notificacoes + Gerenciar preferencias de notificacoes + Tema + Aparencia + Alterar tema + Informacoes do Perfil + Falha ao Atualizar Perfil + Falha ao carregar dados do usuario + Nao autenticado + Atualizacao de perfil em breve + Email e obrigatorio + Perfil atualizado com sucesso + Assinatura + Plano Pro + Plano Gratuito + Ativo ate %1$s + Recursos limitados + Atualizar para Pro + Gerencie sua assinatura na Google Play Store + + + Configuracoes + Preferencias de Notificacoes + Tema do App + Idioma + Sobre + Politica de Privacidade + Termos de Servico + + + Notificacoes + Sem notificacoes + Lembretes de Tarefas + Tarefa Concluida + Propriedade Compartilhada + Ativado + Desativado + Preferências de Notificações + Escolha quais notificações você deseja receber + Notificações de Tarefas + Outras Notificações + Tarefa Próxima ao Vencimento + Lembretes para tarefas próximas + Tarefa Vencida + Alertas para tarefas vencidas + Quando alguém conclui uma tarefa + Tarefa Atribuída + Quando uma tarefa é atribuída a você + Quando alguém compartilha uma propriedade com você + Garantia Expirando + Lembretes para garantias que estão expirando + + + Salvar + Cancelar + Excluir + Editar + Pronto + Fechar + Voltar + Proximo + Enviar + Confirmar + Carregando... + Erro + Tentar Novamente + Sucesso + Buscar + Filtrar + Ordenar + Atualizar + Selecionar + Nenhum + Todos + Sim + Nao + OK + + + Algo deu errado. Por favor, tente novamente. + Erro de rede. Verifique sua conexao. + Tempo esgotado. Tente novamente. + Erro do servidor. Tente mais tarde. + Sessao expirada. Entre novamente. + Nao encontrado + Verifique os dados informados + Este campo e obrigatorio + + + Voltar + Fechar + Abrir menu + Adicionar novo + Editar + Excluir + Atualizar conteudo + Buscar + Opcoes de filtro + Carregando conteudo + + + Hoje + Ontem + Amanha + ha %1$d dias + em %1$d dias + + + Bem-vindo de volta + Gerencie suas propriedades + Falha ao Carregar Resumo + Sair + Propriedades + Tarefas + Ver Todas as Propriedades + Ver Todas as Tarefas + Resumo + Estatisticas das suas propriedades + Total de Tarefas + Pendentes + Gerencie suas residencias + Ver e gerenciar tarefas + + + Assinatura + Gratis + Premium + Melhorar + Restaurar Compras + Recursos Premium + Voce atingiu o limite de propriedades do seu plano + Voce atingiu o limite de tarefas do seu plano + diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml new file mode 100644 index 0000000..4f80a90 --- /dev/null +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -0,0 +1,473 @@ + + + + Casera + Manage your properties with ease + + + Casera + Manage your properties with ease + Username or Email + Password + Sign In + Forgot Password? + Don\'t have an account? Register + Login Failed + Show password + Hide password + + + Create Account + Sign up to get started + First Name + Last Name + Email + Username + Password + Confirm Password + Create Account + Already have an account? Sign In + Passwords don\'t match + + + Verify Email + Enter the 6-digit code sent to your email + Verification Code + Verify + Resend Code + Email verified successfully + + + Forgot Password + Enter your email to receive a reset code + Email + Send Reset Code + If an account exists, a reset code has been sent + + + Reset Password + Enter your new password + Reset Code + New Password + Confirm New Password + Reset Password + Password reset successfully + + + My Properties + No properties yet + Add your first property to get started! + Add Property + Add Property + Edit Property + Property Name + Address + Property Type + Notes + Are you sure you want to delete this property? + Property deleted + Share Property + Share Code + Expires in %1$s + Join Property + Enter Share Code + Join + Property Members + Owner + Member + Remove User + Property Details + Property Name * + Name is required + Required + Street Address + Apartment/Unit # + City + State/Province + Postal Code + Country + Optional Details + Square Footage + Lot Size (acres) + Description + Primary Residence + Create Residence + Update Residence + Loading residence... + Failed to Load Property + Failed to Delete Property + Failed to Generate Report + Generate Report + This will generate and email a maintenance report for this property. Do you want to continue? + Generate + Manage Users + Edit Residence + Delete Residence + Are you sure you want to delete %1$s? This action cannot be undone. + Address + Unit: %1$s + Property Details + Bedrooms + Bathrooms + Square Footage + Lot Size + Year Built + %1$s sq ft + %1$s acres + Description + Purchase Information + Purchase Date + Purchase Price + Add Task + No tasks yet + Add a task to get started + Error loading tasks: %1$s + No contractors yet + Add contractors from the Contractors tab + Error loading contractors: %1$s + Cancel Task + Are you sure you want to cancel \"%1$s\"? This action cannot be undone. + Archive Task + Are you sure you want to archive \"%1$s\"? You can unarchive it later from archived tasks. + Dismiss + + + Tasks + No tasks yet + Add your first maintenance task + Add Task + Add Task + Edit Task + Task Title + Description + Category + Priority + Frequency + Due Date + Estimated Cost + Contractor + Notes + Are you sure you want to delete this task? + Task deleted + Task Details + Title * + Title is required + Category * + Frequency * + Priority * + Status * + Due Date (YYYY-MM-DD) * + Due date is required + 2025-01-31 + Update Task + Failed to Update Task + + + Overdue + Due Soon + Upcoming + In Progress + Completed + Cancelled + + + Complete + Start + Cancel + Restore + Archive + Unarchive + Task marked as completed + Task marked as in progress + Task cancelled + + + Task Completions + Complete Task + Notes + Actual Cost + Completion Date + Photos + Add Photo + Delete this completion record? + + + Contractors + No contractors yet + Add trusted contractors for your property + Add your first contractor to get started + No contractors found + Add Contractor + Add Contractor + Edit Contractor + Name + Company + Phone + Email + Specialty + Notes + Favorite + Favorites + Filter favorites + Filter by specialty + All Specialties + Search contractors... + Clear search + Add to favorites + Remove from favorites + View details + %1$d tasks + Are you sure you want to delete this contractor? + Contractor deleted + Call + Email + Failed to Load Contractors + Failed to Delete Contractor + Failed to Update Favorite + Upgrade Required + You\'ve reached the maximum number of contractors for your current plan. Upgrade to Pro for unlimited contractors. + Contractor Details + Toggle favorite + Website + Directions + Contact Information + No contact information available + Address + Location + Associated Property + Property + Notes + Statistics + Tasks\nCompleted + Average\nRating + Info + Added By + Member Since + Delete Contractor + Are you sure you want to delete this contractor? This action cannot be undone. + %1$d completed tasks + + + Documents + Documents & Warranties + No documents yet + Store important documents and warranties + Add Document + Add Document + Edit Document + Title + Description + Document Type + Vendor + Serial Number + Model Number + Purchase Date + Purchase Price + Expiry Date + Are you sure you want to delete this document? + Document deleted + Warranties + Warranties + Documents + Upload File + View Document + All Categories + All Types + Filter active + Filters + Upgrade Required + You\'ve reached the maximum number of documents for your current plan. Upgrade to Pro for unlimited documents. + Document Details + Status + Inactive + Expired + Expiring soon + Active + Days Remaining + Basic Information + Item Details + Item Name + Model Number + Serial Number + Provider + Provider Contact + Claim Information + Claim Phone + Claim Email + Claim Website + Important Dates + Purchase Date + Start Date + End Date + Associations + Residence + Contractor + Contractor Phone + Additional Information + Tags + Notes + Images (%1$d) + Attached File + File Type + File Size + Download File + Metadata + Uploaded By + Created + Updated + Delete Document + Are you sure you want to delete this document? This action cannot be undone. + Failed to Load Document + Failed to Delete Document + Document Images + Image %1$d of %2$d + Error loading image + Failed to load image + Previous + Next + + + Profile + Edit Profile + Update Your Profile + First Name + Last Name + Email + Phone + Save Changes + Log Out + Are you sure you want to log out? + Settings + Notifications + Manage notification preferences + Theme + Appearance + Change theme + Profile Information + Failed to Update Profile + Failed to load user data + Not authenticated + Profile update coming soon + Email is required + Profile updated successfully + Subscription + Pro Plan + Free Plan + Active until %1$s + Limited features + Upgrade to Pro + Manage your subscription in the Google Play Store + + + Settings + Notification Preferences + App Theme + Language + About + Privacy Policy + Terms of Service + + + Notifications + No notifications + Task Reminders + Task Completed + Property Shared + Enabled + Disabled + Notification Preferences + Choose which notifications you\'d like to receive + Task Notifications + Other Notifications + Task Due Soon + Reminders for upcoming tasks + Task Overdue + Alerts for overdue tasks + When someone completes a task + Task Assigned + When a task is assigned to you + When someone shares a property with you + Warranty Expiring + Reminders for expiring warranties + + + Save + Cancel + Delete + Edit + Done + Close + Back + Next + Submit + Confirm + Loading... + Error + Retry + Success + Search + Filter + Sort + Refresh + Select + None + All + Yes + No + OK + + + Something went wrong. Please try again. + Network error. Please check your connection. + Request timed out. Please try again. + Server error. Please try again later. + Session expired. Please log in again. + Not found + Please check your input + This field is required + + + Go back + Close + Open menu + Add new item + Edit item + Delete item + Refresh content + Search + Filter options + Loading content + + + Today + Yesterday + Tomorrow + %1$d days ago + in %1$d days + + + Welcome back + Manage your properties + Failed to Load Summary + Logout + Properties + Tasks + View All Properties + View All Tasks + Overview + Your property stats + Total Tasks + Pending + Manage your residences + View and manage tasks + + + Subscription + Free + Premium + Upgrade + Restore Purchases + Premium Features + You\'ve reached the property limit for your plan + You\'ve reached the task limit for your plan + diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/network/ApiClient.kt b/composeApp/src/commonMain/kotlin/com/example/casera/network/ApiClient.kt index 888cbd1..71282a1 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/network/ApiClient.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/network/ApiClient.kt @@ -9,6 +9,13 @@ import kotlinx.serialization.json.Json expect fun getLocalhostAddress(): String expect fun createHttpClient(): HttpClient +/** + * Get the device's preferred language code (e.g., "en", "es", "fr"). + * This is used to set the Accept-Language header for API requests + * so the server can return localized error messages and content. + */ +expect fun getDeviceLanguage(): String + object ApiClient { val httpClient = createHttpClient() diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ContractorDetailScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ContractorDetailScreen.kt index c276225..f2e4b7d 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ContractorDetailScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ContractorDetailScreen.kt @@ -28,6 +28,8 @@ import com.example.casera.ui.components.HandleErrors import com.example.casera.util.DateUtils import com.example.casera.viewmodel.ContractorViewModel import com.example.casera.network.ApiResult +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -50,13 +52,13 @@ fun ContractorDetailScreen( // Handle errors for delete contractor deleteState.HandleErrors( onRetry = { viewModel.deleteContractor(contractorId) }, - errorTitle = "Failed to Delete Contractor" + errorTitle = stringResource(Res.string.contractors_failed_to_delete) ) // Handle errors for toggle favorite toggleFavoriteState.HandleErrors( onRetry = { viewModel.toggleFavorite(contractorId) }, - errorTitle = "Failed to Update Favorite" + errorTitle = stringResource(Res.string.contractors_failed_to_update_favorite) ) LaunchedEffect(deleteState) { @@ -76,10 +78,10 @@ fun ContractorDetailScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Contractor Details", fontWeight = FontWeight.Bold) }, + title = { Text(stringResource(Res.string.contractors_details), fontWeight = FontWeight.Bold) }, navigationIcon = { IconButton(onClick = onNavigateBack) { - Icon(Icons.Default.ArrowBack, "Back") + Icon(Icons.Default.ArrowBack, stringResource(Res.string.common_back)) } }, actions = { @@ -88,15 +90,15 @@ fun ContractorDetailScreen( IconButton(onClick = { viewModel.toggleFavorite(contractorId) }) { Icon( if (state.data.isFavorite) Icons.Default.Star else Icons.Default.StarOutline, - "Toggle favorite", + stringResource(Res.string.contractors_toggle_favorite), tint = if (state.data.isFavorite) Color(0xFFF59E0B) else LocalContentColor.current ) } IconButton(onClick = { showEditDialog = true }) { - Icon(Icons.Default.Edit, "Edit") + Icon(Icons.Default.Edit, stringResource(Res.string.common_edit)) } IconButton(onClick = { showDeleteConfirmation = true }) { - Icon(Icons.Default.Delete, "Delete", tint = Color(0xFFEF4444)) + Icon(Icons.Default.Delete, stringResource(Res.string.common_delete), tint = Color(0xFFEF4444)) } } else -> {} @@ -120,7 +122,7 @@ fun ContractorDetailScreen( ApiResultHandler( state = contractorState, onRetry = { viewModel.loadContractorDetail(contractorId) }, - errorTitle = "Failed to Load Contractor", + errorTitle = stringResource(Res.string.contractors_failed_to_load), loadingContent = { CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) } @@ -235,7 +237,7 @@ fun ContractorDetailScreen( if (contractor.taskCount > 0) { Spacer(modifier = Modifier.height(4.dp)) Text( - text = "${contractor.taskCount} completed tasks", + text = stringResource(Res.string.contractors_completed_tasks, contractor.taskCount), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -254,7 +256,7 @@ fun ContractorDetailScreen( contractor.phone?.let { phone -> QuickActionButton( icon = Icons.Default.Phone, - label = "Call", + label = stringResource(Res.string.contractors_call), color = MaterialTheme.colorScheme.primary, modifier = Modifier.weight(1f), onClick = { @@ -268,7 +270,7 @@ fun ContractorDetailScreen( contractor.email?.let { email -> QuickActionButton( icon = Icons.Default.Email, - label = "Email", + label = stringResource(Res.string.contractors_send_email), color = MaterialTheme.colorScheme.secondary, modifier = Modifier.weight(1f), onClick = { @@ -282,7 +284,7 @@ fun ContractorDetailScreen( contractor.website?.let { website -> QuickActionButton( icon = Icons.Default.Language, - label = "Website", + label = stringResource(Res.string.contractors_website), color = Color(0xFFF59E0B), modifier = Modifier.weight(1f), onClick = { @@ -297,7 +299,7 @@ fun ContractorDetailScreen( if (contractor.streetAddress != null || contractor.city != null) { QuickActionButton( icon = Icons.Default.Map, - label = "Directions", + label = stringResource(Res.string.contractors_directions), color = Color(0xFFEF4444), modifier = Modifier.weight(1f), onClick = { @@ -319,11 +321,11 @@ fun ContractorDetailScreen( // Contact Information item { - DetailSection(title = "Contact Information") { + DetailSection(title = stringResource(Res.string.contractors_contact_info)) { contractor.phone?.let { phone -> ClickableDetailRow( icon = Icons.Default.Phone, - label = "Phone", + label = stringResource(Res.string.contractors_phone_label), value = phone, iconTint = MaterialTheme.colorScheme.primary, onClick = { @@ -337,7 +339,7 @@ fun ContractorDetailScreen( contractor.email?.let { email -> ClickableDetailRow( icon = Icons.Default.Email, - label = "Email", + label = stringResource(Res.string.contractors_email_label), value = email, iconTint = MaterialTheme.colorScheme.secondary, onClick = { @@ -351,7 +353,7 @@ fun ContractorDetailScreen( contractor.website?.let { website -> ClickableDetailRow( icon = Icons.Default.Language, - label = "Website", + label = stringResource(Res.string.contractors_website), value = website, iconTint = Color(0xFFF59E0B), onClick = { @@ -365,7 +367,7 @@ fun ContractorDetailScreen( if (contractor.phone == null && contractor.email == null && contractor.website == null) { Text( - text = "No contact information available", + text = stringResource(Res.string.contractors_no_contact_info), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(16.dp) @@ -377,7 +379,7 @@ fun ContractorDetailScreen( // Address if (contractor.streetAddress != null || contractor.city != null) { item { - DetailSection(title = "Address") { + DetailSection(title = stringResource(Res.string.contractors_address)) { val fullAddress = buildString { contractor.streetAddress?.let { append(it) } if (contractor.city != null || contractor.stateProvince != null || contractor.postalCode != null) { @@ -397,7 +399,7 @@ fun ContractorDetailScreen( if (fullAddress.isNotBlank()) { ClickableDetailRow( icon = Icons.Default.LocationOn, - label = "Location", + label = stringResource(Res.string.contractors_location), value = fullAddress, iconTint = Color(0xFFEF4444), onClick = { @@ -423,10 +425,10 @@ fun ContractorDetailScreen( ?: "Property #$resId" item { - DetailSection(title = "Associated Property") { + DetailSection(title = stringResource(Res.string.contractors_associated_property)) { DetailRow( icon = Icons.Default.Home, - label = "Property", + label = stringResource(Res.string.contractors_property), value = residenceName, iconTint = MaterialTheme.colorScheme.primary ) @@ -437,7 +439,7 @@ fun ContractorDetailScreen( // Notes if (!contractor.notes.isNullOrBlank()) { item { - DetailSection(title = "Notes") { + DetailSection(title = stringResource(Res.string.contractors_notes)) { Row( modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp), horizontalArrangement = Arrangement.spacedBy(12.dp) @@ -460,7 +462,7 @@ fun ContractorDetailScreen( // Statistics item { - DetailSection(title = "Statistics") { + DetailSection(title = stringResource(Res.string.contractors_statistics)) { Row( modifier = Modifier .fillMaxWidth() @@ -470,7 +472,7 @@ fun ContractorDetailScreen( StatCard( icon = Icons.Default.CheckCircle, value = contractor.taskCount.toString(), - label = "Tasks\nCompleted", + label = stringResource(Res.string.contractors_tasks_completed), color = MaterialTheme.colorScheme.primary ) @@ -478,7 +480,7 @@ fun ContractorDetailScreen( StatCard( icon = Icons.Default.Star, value = ((contractor.rating * 10).toInt() / 10.0).toString(), - label = "Average\nRating", + label = stringResource(Res.string.contractors_average_rating), color = Color(0xFFF59E0B) ) } @@ -488,11 +490,11 @@ fun ContractorDetailScreen( // Metadata item { - DetailSection(title = "Info") { + DetailSection(title = stringResource(Res.string.contractors_info)) { contractor.createdBy?.let { createdBy -> DetailRow( icon = Icons.Default.PersonAdd, - label = "Added By", + label = stringResource(Res.string.contractors_added_by), value = createdBy.username, iconTint = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -501,7 +503,7 @@ fun ContractorDetailScreen( DetailRow( icon = Icons.Default.CalendarMonth, - label = "Member Since", + label = stringResource(Res.string.contractors_member_since), value = DateUtils.formatDateMedium(contractor.createdAt), iconTint = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -527,8 +529,8 @@ fun ContractorDetailScreen( AlertDialog( onDismissRequest = { showDeleteConfirmation = false }, icon = { Icon(Icons.Default.Warning, null, tint = Color(0xFFEF4444)) }, - title = { Text("Delete Contractor") }, - text = { Text("Are you sure you want to delete this contractor? This action cannot be undone.") }, + title = { Text(stringResource(Res.string.contractors_delete)) }, + text = { Text(stringResource(Res.string.contractors_delete_warning)) }, confirmButton = { Button( onClick = { @@ -537,12 +539,12 @@ fun ContractorDetailScreen( }, colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFEF4444)) ) { - Text("Delete") + Text(stringResource(Res.string.common_delete)) } }, dismissButton = { TextButton(onClick = { showDeleteConfirmation = false }) { - Text("Cancel") + Text(stringResource(Res.string.common_cancel)) } }, containerColor = Color.White, diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ContractorsScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ContractorsScreen.kt index 21d8e3f..ca7e152 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ContractorsScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ContractorsScreen.kt @@ -29,6 +29,8 @@ import com.example.casera.network.ApiResult import com.example.casera.repository.LookupsRepository import com.example.casera.ui.subscription.UpgradeFeatureScreen import com.example.casera.utils.SubscriptionHelper +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -83,13 +85,13 @@ fun ContractorsScreen( // Handle errors for delete contractor deleteState.HandleErrors( onRetry = { /* Handled in UI */ }, - errorTitle = "Failed to Delete Contractor" + errorTitle = stringResource(Res.string.contractors_failed_to_delete) ) // Handle errors for toggle favorite toggleFavoriteState.HandleErrors( onRetry = { /* Handled in UI */ }, - errorTitle = "Failed to Update Favorite" + errorTitle = stringResource(Res.string.contractors_failed_to_update_favorite) ) LaunchedEffect(deleteState) { @@ -109,13 +111,13 @@ fun ContractorsScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Contractors", fontWeight = FontWeight.Bold) }, + title = { Text(stringResource(Res.string.contractors_title), fontWeight = FontWeight.Bold) }, actions = { // Favorites filter toggle IconButton(onClick = { showFavoritesOnly = !showFavoritesOnly }) { Icon( if (showFavoritesOnly) Icons.Default.Star else Icons.Default.StarOutline, - "Filter favorites", + stringResource(Res.string.contractors_filter_favorites), tint = if (showFavoritesOnly) MaterialTheme.colorScheme.tertiary else LocalContentColor.current ) } @@ -125,7 +127,7 @@ fun ContractorsScreen( IconButton(onClick = { showFiltersMenu = true }) { Icon( Icons.Default.FilterList, - "Filter by specialty", + stringResource(Res.string.contractors_filter_specialty), tint = if (selectedFilter != null) MaterialTheme.colorScheme.primary else LocalContentColor.current ) } @@ -135,7 +137,7 @@ fun ContractorsScreen( onDismissRequest = { showFiltersMenu = false } ) { DropdownMenuItem( - text = { Text("All Specialties") }, + text = { Text(stringResource(Res.string.contractors_all_specialties)) }, onClick = { selectedFilter = null showFiltersMenu = false @@ -186,7 +188,7 @@ fun ContractorsScreen( containerColor = MaterialTheme.colorScheme.primary, contentColor = MaterialTheme.colorScheme.onPrimary ) { - Icon(Icons.Default.Add, "Add contractor") + Icon(Icons.Default.Add, stringResource(Res.string.contractors_add_button)) } } } @@ -219,12 +221,12 @@ fun ContractorsScreen( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 8.dp), - placeholder = { Text("Search contractors...") }, - leadingIcon = { Icon(Icons.Default.Search, "Search") }, + placeholder = { Text(stringResource(Res.string.contractors_search)) }, + leadingIcon = { Icon(Icons.Default.Search, stringResource(Res.string.common_search)) }, trailingIcon = { if (searchQuery.isNotEmpty()) { IconButton(onClick = { searchQuery = "" }) { - Icon(Icons.Default.Close, "Clear search") + Icon(Icons.Default.Close, stringResource(Res.string.contractors_clear_search)) } } }, @@ -250,7 +252,7 @@ fun ContractorsScreen( FilterChip( selected = true, onClick = { showFavoritesOnly = false }, - label = { Text("Favorites") }, + label = { Text(stringResource(Res.string.contractors_favorites)) }, leadingIcon = { Icon(Icons.Default.Star, null, modifier = Modifier.size(16.dp)) } ) } @@ -270,7 +272,7 @@ fun ContractorsScreen( onRetry = { viewModel.loadContractors() }, - errorTitle = "Failed to Load Contractors", + errorTitle = stringResource(Res.string.contractors_failed_to_load), loadingContent = { if (!isRefreshing) { CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) @@ -296,14 +298,14 @@ fun ContractorsScreen( ) Text( if (searchQuery.isNotEmpty() || selectedFilter != null || showFavoritesOnly) - "No contractors found" + stringResource(Res.string.contractors_no_results) else - "No contractors yet", + stringResource(Res.string.contractors_empty_title), color = MaterialTheme.colorScheme.onSurfaceVariant ) if (searchQuery.isEmpty() && selectedFilter == null && !showFavoritesOnly) { Text( - "Add your first contractor to get started", + stringResource(Res.string.contractors_empty_subtitle_first), color = MaterialTheme.colorScheme.onSurfaceVariant, style = MaterialTheme.typography.bodySmall ) @@ -353,13 +355,13 @@ fun ContractorsScreen( if (showUpgradeDialog) { AlertDialog( onDismissRequest = { showUpgradeDialog = false }, - title = { Text("Upgrade Required") }, + title = { Text(stringResource(Res.string.contractors_upgrade_required)) }, text = { - Text("You've reached the maximum number of contractors for your current plan. Upgrade to Pro for unlimited contractors.") + Text(stringResource(Res.string.contractors_upgrade_message)) }, confirmButton = { TextButton(onClick = { showUpgradeDialog = false }) { - Text("OK") + Text(stringResource(Res.string.common_ok)) } } ) @@ -422,7 +424,7 @@ fun ContractorCard( Spacer(modifier = Modifier.width(4.dp)) Icon( Icons.Default.Star, - contentDescription = "Favorite", + contentDescription = stringResource(Res.string.contractors_favorite), modifier = Modifier.size(16.dp), tint = MaterialTheme.colorScheme.tertiary ) @@ -490,7 +492,7 @@ fun ContractorCard( ) Spacer(modifier = Modifier.width(4.dp)) Text( - text = "${contractor.taskCount} tasks", + text = stringResource(Res.string.contractors_tasks_count, contractor.taskCount), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -505,7 +507,7 @@ fun ContractorCard( ) { Icon( if (contractor.isFavorite) Icons.Default.Star else Icons.Default.StarOutline, - contentDescription = if (contractor.isFavorite) "Remove from favorites" else "Add to favorites", + contentDescription = if (contractor.isFavorite) stringResource(Res.string.contractors_remove_from_favorites) else stringResource(Res.string.contractors_add_to_favorites), tint = if (contractor.isFavorite) MaterialTheme.colorScheme.tertiary else MaterialTheme.colorScheme.onSurfaceVariant ) } @@ -513,7 +515,7 @@ fun ContractorCard( // Arrow icon Icon( Icons.Default.ChevronRight, - contentDescription = "View details", + contentDescription = stringResource(Res.string.contractors_view_details), tint = MaterialTheme.colorScheme.onSurfaceVariant ) } diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/DocumentDetailScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/DocumentDetailScreen.kt index b07ea54..1933e42 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/DocumentDetailScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/DocumentDetailScreen.kt @@ -35,6 +35,8 @@ import coil3.compose.SubcomposeAsyncImage import coil3.compose.SubcomposeAsyncImageContent import coil3.compose.AsyncImagePainter import com.example.casera.util.DateUtils +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -57,7 +59,7 @@ fun DocumentDetailScreen( // Handle errors for document deletion deleteState.HandleErrors( onRetry = { documentViewModel.deleteDocument(documentId) }, - errorTitle = "Failed to Delete Document" + errorTitle = stringResource(Res.string.documents_failed_to_delete) ) // Handle successful deletion @@ -71,20 +73,20 @@ fun DocumentDetailScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Document Details", fontWeight = FontWeight.Bold) }, + title = { Text(stringResource(Res.string.documents_details), fontWeight = FontWeight.Bold) }, navigationIcon = { IconButton(onClick = onNavigateBack) { - Icon(Icons.Default.ArrowBack, "Back") + Icon(Icons.Default.ArrowBack, stringResource(Res.string.common_back)) } }, actions = { when (documentState) { is ApiResult.Success -> { IconButton(onClick = { onNavigateToEdit(documentId) }) { - Icon(Icons.Default.Edit, "Edit") + Icon(Icons.Default.Edit, stringResource(Res.string.common_edit)) } IconButton(onClick = { showDeleteDialog = true }) { - Icon(Icons.Default.Delete, "Delete", tint = Color.Red) + Icon(Icons.Default.Delete, stringResource(Res.string.common_delete), tint = Color.Red) } } else -> {} @@ -101,7 +103,7 @@ fun DocumentDetailScreen( ApiResultHandler( state = documentState, onRetry = { documentViewModel.loadDocumentDetail(documentId) }, - errorTitle = "Failed to Load Document" + errorTitle = stringResource(Res.string.documents_failed_to_load) ) { document -> Column( modifier = Modifier @@ -136,16 +138,16 @@ fun DocumentDetailScreen( ) { Column { Text( - "Status", + stringResource(Res.string.documents_status), style = MaterialTheme.typography.labelMedium, color = Color.Gray ) Text( when { - !document.isActive -> "Inactive" - daysUntilExpiration < 0 -> "Expired" - daysUntilExpiration < 30 -> "Expiring soon" - else -> "Active" + !document.isActive -> stringResource(Res.string.documents_inactive) + daysUntilExpiration < 0 -> stringResource(Res.string.documents_expired) + daysUntilExpiration < 30 -> stringResource(Res.string.documents_expiring_soon) + else -> stringResource(Res.string.documents_active) }, style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold, @@ -155,7 +157,7 @@ fun DocumentDetailScreen( if (document.isActive && daysUntilExpiration >= 0) { Column(horizontalAlignment = Alignment.End) { Text( - "Days Remaining", + stringResource(Res.string.documents_days_remaining), style = MaterialTheme.typography.labelMedium, color = Color.Gray ) @@ -178,19 +180,19 @@ fun DocumentDetailScreen( verticalArrangement = Arrangement.spacedBy(12.dp) ) { Text( - "Basic Information", + stringResource(Res.string.documents_basic_info), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold ) Divider() - DetailRow("Title", document.title) - DetailRow("Type", DocumentType.fromValue(document.documentType).displayName) + DetailRow(stringResource(Res.string.documents_title_label), document.title) + DetailRow(stringResource(Res.string.documents_type_label), DocumentType.fromValue(document.documentType).displayName) document.category?.let { - DetailRow("Category", DocumentCategory.fromValue(it).displayName) + DetailRow(stringResource(Res.string.documents_all_categories), DocumentCategory.fromValue(it).displayName) } document.description?.let { - DetailRow("Description", it) + DetailRow(stringResource(Res.string.documents_description_label), it) } } } @@ -205,17 +207,17 @@ fun DocumentDetailScreen( verticalArrangement = Arrangement.spacedBy(12.dp) ) { Text( - "Item Details", + stringResource(Res.string.documents_item_details), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold ) Divider() - document.itemName?.let { DetailRow("Item Name", it) } - document.modelNumber?.let { DetailRow("Model Number", it) } - document.serialNumber?.let { DetailRow("Serial Number", it) } - document.provider?.let { DetailRow("Provider", it) } - document.providerContact?.let { DetailRow("Provider Contact", it) } + document.itemName?.let { DetailRow(stringResource(Res.string.documents_item_name), it) } + document.modelNumber?.let { DetailRow(stringResource(Res.string.documents_model_number), it) } + document.serialNumber?.let { DetailRow(stringResource(Res.string.documents_serial_number), it) } + document.provider?.let { DetailRow(stringResource(Res.string.documents_provider), it) } + document.providerContact?.let { DetailRow(stringResource(Res.string.documents_provider_contact), it) } } } } @@ -230,15 +232,15 @@ fun DocumentDetailScreen( verticalArrangement = Arrangement.spacedBy(12.dp) ) { Text( - "Claim Information", + stringResource(Res.string.documents_claim_info), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold ) Divider() - document.claimPhone?.let { DetailRow("Claim Phone", it) } - document.claimEmail?.let { DetailRow("Claim Email", it) } - document.claimWebsite?.let { DetailRow("Claim Website", it) } + document.claimPhone?.let { DetailRow(stringResource(Res.string.documents_claim_phone), it) } + document.claimEmail?.let { DetailRow(stringResource(Res.string.documents_claim_email), it) } + document.claimWebsite?.let { DetailRow(stringResource(Res.string.documents_claim_website), it) } } } } @@ -252,15 +254,15 @@ fun DocumentDetailScreen( verticalArrangement = Arrangement.spacedBy(12.dp) ) { Text( - "Important Dates", + stringResource(Res.string.documents_important_dates), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold ) Divider() - document.purchaseDate?.let { DetailRow("Purchase Date", DateUtils.formatDateMedium(it)) } - document.startDate?.let { DetailRow("Start Date", DateUtils.formatDateMedium(it)) } - document.endDate?.let { DetailRow("End Date", DateUtils.formatDateMedium(it)) } + document.purchaseDate?.let { DetailRow(stringResource(Res.string.documents_purchase_date), DateUtils.formatDateMedium(it)) } + document.startDate?.let { DetailRow(stringResource(Res.string.documents_start_date), DateUtils.formatDateMedium(it)) } + document.endDate?.let { DetailRow(stringResource(Res.string.documents_end_date), DateUtils.formatDateMedium(it)) } } } } @@ -272,15 +274,15 @@ fun DocumentDetailScreen( verticalArrangement = Arrangement.spacedBy(12.dp) ) { Text( - "Associations", + stringResource(Res.string.documents_associations), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold ) Divider() - document.residenceAddress?.let { DetailRow("Residence", it) } - document.contractorName?.let { DetailRow("Contractor", it) } - document.contractorPhone?.let { DetailRow("Contractor Phone", it) } + document.residenceAddress?.let { DetailRow(stringResource(Res.string.documents_residence), it) } + document.contractorName?.let { DetailRow(stringResource(Res.string.documents_contractor), it) } + document.contractorPhone?.let { DetailRow(stringResource(Res.string.documents_contractor_phone), it) } } } @@ -292,14 +294,14 @@ fun DocumentDetailScreen( verticalArrangement = Arrangement.spacedBy(12.dp) ) { Text( - "Additional Information", + stringResource(Res.string.documents_additional_info), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold ) Divider() - document.tags?.let { DetailRow("Tags", it) } - document.notes?.let { DetailRow("Notes", it) } + document.tags?.let { DetailRow(stringResource(Res.string.documents_tags), it) } + document.notes?.let { DetailRow(stringResource(Res.string.documents_notes), it) } } } } @@ -312,7 +314,7 @@ fun DocumentDetailScreen( verticalArrangement = Arrangement.spacedBy(12.dp) ) { Text( - "Images (${document.images.size})", + stringResource(Res.string.documents_images, document.images.size), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold ) @@ -369,15 +371,15 @@ fun DocumentDetailScreen( verticalArrangement = Arrangement.spacedBy(12.dp) ) { Text( - "Attached File", + stringResource(Res.string.documents_attached_file), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold ) Divider() - document.fileType?.let { DetailRow("File Type", it) } + document.fileType?.let { DetailRow(stringResource(Res.string.documents_file_type), it) } document.fileSize?.let { - DetailRow("File Size", formatFileSize(it)) + DetailRow(stringResource(Res.string.documents_file_size), formatFileSize(it)) } Button( @@ -386,7 +388,7 @@ fun DocumentDetailScreen( ) { Icon(Icons.Default.Download, null) Spacer(modifier = Modifier.width(8.dp)) - Text("Download File") + Text(stringResource(Res.string.documents_download_file)) } } } @@ -399,15 +401,15 @@ fun DocumentDetailScreen( verticalArrangement = Arrangement.spacedBy(12.dp) ) { Text( - "Metadata", + stringResource(Res.string.documents_metadata), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold ) Divider() - document.uploadedByUsername?.let { DetailRow("Uploaded By", it) } - document.createdAt?.let { DetailRow("Created", DateUtils.formatDateMedium(it)) } - document.updatedAt?.let { DetailRow("Updated", DateUtils.formatDateMedium(it)) } + document.uploadedByUsername?.let { DetailRow(stringResource(Res.string.documents_uploaded_by), it) } + document.createdAt?.let { DetailRow(stringResource(Res.string.documents_created), DateUtils.formatDateMedium(it)) } + document.updatedAt?.let { DetailRow(stringResource(Res.string.documents_updated), DateUtils.formatDateMedium(it)) } } } } @@ -419,8 +421,8 @@ fun DocumentDetailScreen( if (showDeleteDialog) { AlertDialog( onDismissRequest = { showDeleteDialog = false }, - title = { Text("Delete Document") }, - text = { Text("Are you sure you want to delete this document? This action cannot be undone.") }, + title = { Text(stringResource(Res.string.documents_delete)) }, + text = { Text(stringResource(Res.string.documents_delete_warning)) }, confirmButton = { TextButton( onClick = { @@ -428,12 +430,12 @@ fun DocumentDetailScreen( showDeleteDialog = false } ) { - Text("Delete", color = Color.Red) + Text(stringResource(Res.string.common_delete), color = Color.Red) } }, dismissButton = { TextButton(onClick = { showDeleteDialog = false }) { - Text("Cancel") + Text(stringResource(Res.string.common_cancel)) } } ) diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/DocumentsScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/DocumentsScreen.kt index 9a29d63..dea8945 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/DocumentsScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/DocumentsScreen.kt @@ -16,6 +16,8 @@ import com.example.casera.ui.subscription.UpgradeFeatureScreen import com.example.casera.utils.SubscriptionHelper import com.example.casera.viewmodel.DocumentViewModel import com.example.casera.models.* +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource enum class DocumentTab { WARRANTIES, DOCUMENTS @@ -73,10 +75,10 @@ fun DocumentsScreen( topBar = { Column { TopAppBar( - title = { Text("Documents & Warranties", fontWeight = FontWeight.Bold) }, + title = { Text(stringResource(Res.string.documents_and_warranties), fontWeight = FontWeight.Bold) }, navigationIcon = { IconButton(onClick = onNavigateBack) { - Icon(Icons.Default.ArrowBack, "Back") + Icon(Icons.Default.ArrowBack, stringResource(Res.string.common_back)) } }, actions = { @@ -85,7 +87,7 @@ fun DocumentsScreen( IconButton(onClick = { showActiveOnly = !showActiveOnly }) { Icon( if (showActiveOnly) Icons.Default.CheckCircle else Icons.Default.CheckCircleOutline, - "Filter active", + stringResource(Res.string.documents_filter_active), tint = if (showActiveOnly) MaterialTheme.colorScheme.secondary else LocalContentColor.current ) } @@ -96,7 +98,7 @@ fun DocumentsScreen( IconButton(onClick = { showFiltersMenu = true }) { Icon( Icons.Default.FilterList, - "Filters", + stringResource(Res.string.documents_filters), tint = if (selectedCategory != null || selectedDocType != null) MaterialTheme.colorScheme.primary else LocalContentColor.current ) @@ -108,7 +110,7 @@ fun DocumentsScreen( ) { if (selectedTab == DocumentTab.WARRANTIES) { DropdownMenuItem( - text = { Text("All Categories") }, + text = { Text(stringResource(Res.string.documents_all_categories)) }, onClick = { selectedCategory = null showFiltersMenu = false @@ -126,7 +128,7 @@ fun DocumentsScreen( } } else { DropdownMenuItem( - text = { Text("All Types") }, + text = { Text(stringResource(Res.string.documents_all_types)) }, onClick = { selectedDocType = null showFiltersMenu = false @@ -153,13 +155,13 @@ fun DocumentsScreen( Tab( selected = selectedTab == DocumentTab.WARRANTIES, onClick = { selectedTab = DocumentTab.WARRANTIES }, - text = { Text("Warranties") }, + text = { Text(stringResource(Res.string.documents_warranties_tab)) }, icon = { Icon(Icons.Default.VerifiedUser, null) } ) Tab( selected = selectedTab == DocumentTab.DOCUMENTS, onClick = { selectedTab = DocumentTab.DOCUMENTS }, - text = { Text("Documents") }, + text = { Text(stringResource(Res.string.documents_documents_tab)) }, icon = { Icon(Icons.Default.Description, null) } ) } @@ -183,7 +185,7 @@ fun DocumentsScreen( }, containerColor = MaterialTheme.colorScheme.primary ) { - Icon(Icons.Default.Add, "Add") + Icon(Icons.Default.Add, stringResource(Res.string.documents_add_button)) } } } @@ -243,13 +245,13 @@ fun DocumentsScreen( if (showUpgradeDialog) { AlertDialog( onDismissRequest = { showUpgradeDialog = false }, - title = { Text("Upgrade Required") }, + title = { Text(stringResource(Res.string.documents_upgrade_required)) }, text = { - Text("You've reached the maximum number of documents for your current plan. Upgrade to Pro for unlimited documents.") + Text(stringResource(Res.string.documents_upgrade_message)) }, confirmButton = { TextButton(onClick = { showUpgradeDialog = false }) { - Text("OK") + Text(stringResource(Res.string.common_ok)) } } ) diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/EditTaskScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/EditTaskScreen.kt index 22b452f..3bc2338 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/EditTaskScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/EditTaskScreen.kt @@ -17,6 +17,8 @@ import com.example.casera.viewmodel.ResidenceViewModel import com.example.casera.repository.LookupsRepository import com.example.casera.models.* import com.example.casera.network.ApiResult +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -53,7 +55,7 @@ fun EditTaskScreen( // Handle errors for task update updateTaskState.HandleErrors( onRetry = { /* Retry handled in UI */ }, - errorTitle = "Failed to Update Task" + errorTitle = stringResource(Res.string.tasks_failed_to_update) ) // Handle update state changes @@ -67,18 +69,21 @@ fun EditTaskScreen( } } + val titleRequiredError = stringResource(Res.string.tasks_title_error) + val dueDateRequiredError = stringResource(Res.string.tasks_due_date_error) + fun validateForm(): Boolean { var isValid = true if (title.isBlank()) { - titleError = "Title is required" + titleError = titleRequiredError isValid = false } else { titleError = "" } if (dueDate.isNullOrBlank()) { - dueDateError = "Due date is required" + dueDateError = dueDateRequiredError isValid = false } else { dueDateError = "" @@ -90,10 +95,10 @@ fun EditTaskScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Edit Task") }, + title = { Text(stringResource(Res.string.tasks_edit_title)) }, navigationIcon = { IconButton(onClick = onNavigateBack) { - Icon(Icons.Default.ArrowBack, contentDescription = "Back") + Icon(Icons.Default.ArrowBack, contentDescription = stringResource(Res.string.common_back)) } } ) @@ -109,7 +114,7 @@ fun EditTaskScreen( ) { // Required fields section Text( - text = "Task Details", + text = stringResource(Res.string.tasks_details), style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.primary ) @@ -117,7 +122,7 @@ fun EditTaskScreen( OutlinedTextField( value = title, onValueChange = { title = it }, - label = { Text("Title *") }, + label = { Text(stringResource(Res.string.tasks_title_required)) }, modifier = Modifier.fillMaxWidth(), isError = titleError.isNotEmpty(), supportingText = if (titleError.isNotEmpty()) { @@ -128,7 +133,7 @@ fun EditTaskScreen( OutlinedTextField( value = description, onValueChange = { description = it }, - label = { Text("Description") }, + label = { Text(stringResource(Res.string.tasks_description_label)) }, modifier = Modifier.fillMaxWidth(), minLines = 3, maxLines = 5 @@ -143,7 +148,7 @@ fun EditTaskScreen( value = selectedCategory?.name?.replaceFirstChar { it.uppercase() } ?: "", onValueChange = {}, readOnly = true, - label = { Text("Category *") }, + label = { Text(stringResource(Res.string.tasks_category_required)) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = categoryExpanded) }, modifier = Modifier .fillMaxWidth() @@ -175,7 +180,7 @@ fun EditTaskScreen( value = selectedFrequency?.name?.replaceFirstChar { it.uppercase() } ?: "", onValueChange = {}, readOnly = true, - label = { Text("Frequency *") }, + label = { Text(stringResource(Res.string.tasks_frequency_required)) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = frequencyExpanded) }, modifier = Modifier .fillMaxWidth() @@ -207,7 +212,7 @@ fun EditTaskScreen( value = selectedPriority?.name?.replaceFirstChar { it.uppercase() } ?: "", onValueChange = {}, readOnly = true, - label = { Text("Priority *") }, + label = { Text(stringResource(Res.string.tasks_priority_required)) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = priorityExpanded) }, modifier = Modifier .fillMaxWidth() @@ -239,7 +244,7 @@ fun EditTaskScreen( value = selectedStatus?.name?.replaceFirstChar { it.uppercase() } ?: "", onValueChange = {}, readOnly = true, - label = { Text("Status *") }, + label = { Text(stringResource(Res.string.tasks_status_label)) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = statusExpanded) }, modifier = Modifier .fillMaxWidth() @@ -265,19 +270,19 @@ fun EditTaskScreen( OutlinedTextField( value = dueDate, onValueChange = { dueDate = it }, - label = { Text("Due Date (YYYY-MM-DD) *") }, + label = { Text(stringResource(Res.string.tasks_due_date_required)) }, modifier = Modifier.fillMaxWidth(), isError = dueDateError.isNotEmpty(), supportingText = if (dueDateError.isNotEmpty()) { { Text(dueDateError) } } else null, - placeholder = { Text("2025-01-31") } + placeholder = { Text(stringResource(Res.string.tasks_due_date_placeholder)) } ) OutlinedTextField( value = estimatedCost, onValueChange = { estimatedCost = it }, - label = { Text("Estimated Cost") }, + label = { Text(stringResource(Res.string.tasks_estimated_cost_label)) }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal), modifier = Modifier.fillMaxWidth(), prefix = { Text("$") } @@ -325,7 +330,7 @@ fun EditTaskScreen( color = MaterialTheme.colorScheme.onPrimary ) } else { - Text("Update Task") + Text(stringResource(Res.string.tasks_update)) } } diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ForgotPasswordScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ForgotPasswordScreen.kt index 20b2a76..d3a7d1a 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ForgotPasswordScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ForgotPasswordScreen.kt @@ -18,6 +18,8 @@ import com.example.casera.ui.components.auth.AuthHeader import com.example.casera.ui.components.common.ErrorCard import com.example.casera.viewmodel.PasswordResetViewModel import com.example.casera.network.ApiResult +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -60,10 +62,10 @@ fun ForgotPasswordScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Forgot Password") }, + title = { Text(stringResource(Res.string.auth_forgot_title)) }, navigationIcon = { IconButton(onClick = onNavigateBack) { - Icon(Icons.Default.ArrowBack, contentDescription = "Back") + Icon(Icons.Default.ArrowBack, contentDescription = stringResource(Res.string.common_back)) } }, colors = TopAppBarDefaults.topAppBarColors( @@ -98,8 +100,8 @@ fun ForgotPasswordScreen( ) { AuthHeader( icon = Icons.Default.Key, - title = "Forgot Password?", - subtitle = "Enter your email address and we'll send you a code to reset your password" + title = stringResource(Res.string.auth_forgot_title), + subtitle = stringResource(Res.string.auth_forgot_subtitle) ) Spacer(modifier = Modifier.height(8.dp)) @@ -110,7 +112,7 @@ fun ForgotPasswordScreen( email = it viewModel.resetForgotPasswordState() }, - label = { Text("Email Address") }, + label = { Text(stringResource(Res.string.auth_forgot_email_label)) }, leadingIcon = { Icon(Icons.Default.Email, contentDescription = null) }, @@ -178,7 +180,7 @@ fun ForgotPasswordScreen( Icon(Icons.Default.Send, contentDescription = null) Spacer(modifier = Modifier.width(8.dp)) Text( - "Send Reset Code", + stringResource(Res.string.auth_forgot_button), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/HomeScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/HomeScreen.kt index 729d0c0..25dc3f3 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/HomeScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/HomeScreen.kt @@ -19,6 +19,8 @@ import com.example.casera.ui.components.HandleErrors import com.example.casera.ui.theme.AppRadius import com.example.casera.viewmodel.ResidenceViewModel import com.example.casera.network.ApiResult +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -37,13 +39,13 @@ fun HomeScreen( // Handle errors for loading summary summaryState.HandleErrors( onRetry = { viewModel.loadMyResidences() }, - errorTitle = "Failed to Load Summary" + errorTitle = stringResource(Res.string.home_failed_to_load) ) Scaffold( topBar = { TopAppBar( - title = { Text("myCrib", style = MaterialTheme.typography.headlineSmall) }, + title = { Text(stringResource(Res.string.app_name), style = MaterialTheme.typography.headlineSmall) }, colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.background ), @@ -51,7 +53,7 @@ fun HomeScreen( IconButton(onClick = onLogout) { Icon( Icons.Default.ExitToApp, - contentDescription = "Logout", + contentDescription = stringResource(Res.string.home_logout), tint = MaterialTheme.colorScheme.primary ) } @@ -72,12 +74,12 @@ fun HomeScreen( modifier = Modifier.padding(vertical = 8.dp) ) { Text( - text = "Welcome back", + text = stringResource(Res.string.home_welcome), style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.onSurfaceVariant ) Text( - text = "Manage your properties", + text = stringResource(Res.string.home_manage_properties), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -127,12 +129,12 @@ fun HomeScreen( } Column { Text( - text = "Overview", + text = stringResource(Res.string.home_overview), style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurface ) Text( - text = "Your property stats", + text = stringResource(Res.string.home_property_stats), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -147,7 +149,7 @@ fun HomeScreen( ) { StatItem( value = "${summary.residences.size}", - label = "Properties", + label = stringResource(Res.string.home_properties), color = Color(0xFF3B82F6) ) Divider( @@ -158,7 +160,7 @@ fun HomeScreen( ) StatItem( value = "${summary.summary.totalTasks}", - label = "Total Tasks", + label = stringResource(Res.string.home_total_tasks), color = Color(0xFF8B5CF6) ) Divider( @@ -169,7 +171,7 @@ fun HomeScreen( ) StatItem( value = "${summary.summary.totalPending}", - label = "Pending", + label = stringResource(Res.string.home_pending), color = Color(0xFFF59E0B) ) } @@ -197,8 +199,8 @@ fun HomeScreen( // Residences Card NavigationCard( - title = "Properties", - subtitle = "Manage your residences", + title = stringResource(Res.string.home_properties), + subtitle = stringResource(Res.string.home_manage_residences), icon = Icons.Default.Home, iconColor = Color(0xFF3B82F6), onClick = onNavigateToResidences @@ -206,8 +208,8 @@ fun HomeScreen( // Tasks Card NavigationCard( - title = "Tasks", - subtitle = "View and manage tasks", + title = stringResource(Res.string.home_tasks), + subtitle = stringResource(Res.string.home_view_manage_tasks), icon = Icons.Default.CheckCircle, iconColor = Color(0xFF10B981), onClick = onNavigateToTasks diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/LoginScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/LoginScreen.kt index d95f760..991756b 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/LoginScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/LoginScreen.kt @@ -26,6 +26,8 @@ import com.example.casera.ui.components.auth.AuthHeader import com.example.casera.ui.components.common.ErrorCard import com.example.casera.viewmodel.AuthViewModel import com.example.casera.network.ApiResult +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @Composable fun LoginScreen( @@ -42,7 +44,7 @@ fun LoginScreen( // Handle errors for login loginState.HandleErrors( onRetry = { viewModel.login(username, password) }, - errorTitle = "Login Failed" + errorTitle = stringResource(Res.string.auth_login_failed) ) // Handle login state changes @@ -88,8 +90,8 @@ fun LoginScreen( ) { AuthHeader( icon = Icons.Default.Home, - title = "myCrib", - subtitle = "Manage your properties with ease" + title = stringResource(Res.string.app_name), + subtitle = stringResource(Res.string.app_tagline) ) Spacer(modifier = Modifier.height(8.dp)) @@ -97,7 +99,7 @@ fun LoginScreen( OutlinedTextField( value = username, onValueChange = { username = it }, - label = { Text("Username or Email") }, + label = { Text(stringResource(Res.string.auth_login_username_label)) }, leadingIcon = { Icon(Icons.Default.Person, contentDescription = null) }, @@ -113,7 +115,7 @@ fun LoginScreen( OutlinedTextField( value = password, onValueChange = { password = it }, - label = { Text("Password") }, + label = { Text(stringResource(Res.string.auth_login_password_label)) }, leadingIcon = { Icon(Icons.Default.Lock, contentDescription = null) }, @@ -121,7 +123,7 @@ fun LoginScreen( IconButton(onClick = { passwordVisible = !passwordVisible }) { Icon( imageVector = if (passwordVisible) Icons.Default.Visibility else Icons.Default.VisibilityOff, - contentDescription = if (passwordVisible) "Hide password" else "Show password" + contentDescription = if (passwordVisible) stringResource(Res.string.auth_hide_password) else stringResource(Res.string.auth_show_password) ) } }, @@ -175,7 +177,7 @@ fun LoginScreen( ) } else { Text( - "Sign In", + stringResource(Res.string.auth_login_button), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold, color = Color.White @@ -189,7 +191,7 @@ fun LoginScreen( modifier = Modifier.fillMaxWidth() ) { Text( - "Forgot Password?", + stringResource(Res.string.auth_forgot_password), style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.SemiBold ) @@ -200,7 +202,7 @@ fun LoginScreen( modifier = Modifier.fillMaxWidth() ) { Text( - "Don't have an account? Register", + stringResource(Res.string.auth_no_account), style = MaterialTheme.typography.bodyMedium ) } diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/MainScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/MainScreen.kt index 036cd46..5d23e36 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/MainScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/MainScreen.kt @@ -15,6 +15,8 @@ import com.example.casera.navigation.* import com.example.casera.repository.LookupsRepository import com.example.casera.models.Residence import com.example.casera.storage.TokenStorage +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @Composable fun MainScreen( @@ -35,8 +37,8 @@ fun MainScreen( tonalElevation = 3.dp ) { NavigationBarItem( - icon = { Icon(Icons.Default.Home, contentDescription = "Residences") }, - label = { Text("Residences") }, + icon = { Icon(Icons.Default.Home, contentDescription = stringResource(Res.string.properties_title)) }, + label = { Text(stringResource(Res.string.properties_title)) }, selected = selectedTab == 0, onClick = { selectedTab = 0 @@ -53,8 +55,8 @@ fun MainScreen( ) ) NavigationBarItem( - icon = { Icon(Icons.Default.CheckCircle, contentDescription = "Tasks") }, - label = { Text("Tasks") }, + icon = { Icon(Icons.Default.CheckCircle, contentDescription = stringResource(Res.string.tasks_title)) }, + label = { Text(stringResource(Res.string.tasks_title)) }, selected = selectedTab == 1, onClick = { selectedTab = 1 @@ -71,8 +73,8 @@ fun MainScreen( ) ) NavigationBarItem( - icon = { Icon(Icons.Default.Build, contentDescription = "Contractors") }, - label = { Text("Contractors") }, + icon = { Icon(Icons.Default.Build, contentDescription = stringResource(Res.string.contractors_title)) }, + label = { Text(stringResource(Res.string.contractors_title)) }, selected = selectedTab == 2, onClick = { selectedTab = 2 @@ -89,8 +91,8 @@ fun MainScreen( ) ) NavigationBarItem( - icon = { Icon(Icons.Default.Description, contentDescription = "Documents") }, - label = { Text("Documents") }, + icon = { Icon(Icons.Default.Description, contentDescription = stringResource(Res.string.documents_title)) }, + label = { Text(stringResource(Res.string.documents_title)) }, selected = selectedTab == 3, onClick = { selectedTab = 3 diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/NotificationPreferencesScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/NotificationPreferencesScreen.kt index 4b8cec7..88580d8 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/NotificationPreferencesScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/NotificationPreferencesScreen.kt @@ -17,6 +17,8 @@ import com.example.casera.network.ApiResult import com.example.casera.ui.theme.AppRadius import com.example.casera.ui.theme.AppSpacing import com.example.casera.viewmodel.NotificationPreferencesViewModel +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -55,10 +57,10 @@ fun NotificationPreferencesScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Notifications", fontWeight = FontWeight.SemiBold) }, + title = { Text(stringResource(Res.string.notifications_title), fontWeight = FontWeight.SemiBold) }, navigationIcon = { IconButton(onClick = onNavigateBack) { - Icon(Icons.Default.ArrowBack, contentDescription = "Back") + Icon(Icons.Default.ArrowBack, contentDescription = stringResource(Res.string.common_back)) } }, colors = TopAppBarDefaults.topAppBarColors( @@ -98,13 +100,13 @@ fun NotificationPreferencesScreen( ) Text( - "Notification Preferences", + stringResource(Res.string.notifications_preferences), style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold ) Text( - "Choose which notifications you'd like to receive", + stringResource(Res.string.notifications_choose), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -157,7 +159,7 @@ fun NotificationPreferencesScreen( onClick = { viewModel.loadPreferences() }, modifier = Modifier.fillMaxWidth() ) { - Text("Retry") + Text(stringResource(Res.string.common_retry)) } } } @@ -166,7 +168,7 @@ fun NotificationPreferencesScreen( is ApiResult.Success, is ApiResult.Idle -> { // Task Notifications Section Text( - "Task Notifications", + stringResource(Res.string.notifications_task_section), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold, modifier = Modifier.padding(top = AppSpacing.md) @@ -181,8 +183,8 @@ fun NotificationPreferencesScreen( ) { Column { NotificationToggle( - title = "Task Due Soon", - description = "Reminders for upcoming tasks", + title = stringResource(Res.string.notifications_task_due_soon), + description = stringResource(Res.string.notifications_task_due_soon_desc), icon = Icons.Default.Schedule, iconTint = MaterialTheme.colorScheme.tertiary, checked = taskDueSoon, @@ -198,8 +200,8 @@ fun NotificationPreferencesScreen( ) NotificationToggle( - title = "Task Overdue", - description = "Alerts for overdue tasks", + title = stringResource(Res.string.notifications_task_overdue), + description = stringResource(Res.string.notifications_task_overdue_desc), icon = Icons.Default.Warning, iconTint = MaterialTheme.colorScheme.error, checked = taskOverdue, @@ -215,8 +217,8 @@ fun NotificationPreferencesScreen( ) NotificationToggle( - title = "Task Completed", - description = "When someone completes a task", + title = stringResource(Res.string.notifications_task_completed), + description = stringResource(Res.string.notifications_task_completed_desc), icon = Icons.Default.CheckCircle, iconTint = MaterialTheme.colorScheme.primary, checked = taskCompleted, @@ -232,8 +234,8 @@ fun NotificationPreferencesScreen( ) NotificationToggle( - title = "Task Assigned", - description = "When a task is assigned to you", + title = stringResource(Res.string.notifications_task_assigned), + description = stringResource(Res.string.notifications_task_assigned_desc), icon = Icons.Default.PersonAdd, iconTint = MaterialTheme.colorScheme.secondary, checked = taskAssigned, @@ -247,7 +249,7 @@ fun NotificationPreferencesScreen( // Other Notifications Section Text( - "Other Notifications", + stringResource(Res.string.notifications_other_section), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold, modifier = Modifier.padding(top = AppSpacing.md) @@ -262,8 +264,8 @@ fun NotificationPreferencesScreen( ) { Column { NotificationToggle( - title = "Property Shared", - description = "When someone shares a property with you", + title = stringResource(Res.string.notifications_property_shared), + description = stringResource(Res.string.notifications_property_shared_desc), icon = Icons.Default.Home, iconTint = MaterialTheme.colorScheme.primary, checked = residenceShared, @@ -279,8 +281,8 @@ fun NotificationPreferencesScreen( ) NotificationToggle( - title = "Warranty Expiring", - description = "Reminders for expiring warranties", + title = stringResource(Res.string.notifications_warranty_expiring), + description = stringResource(Res.string.notifications_warranty_expiring_desc), icon = Icons.Default.Description, iconTint = MaterialTheme.colorScheme.tertiary, checked = warrantyExpiring, diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ProfileScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ProfileScreen.kt index ec40007..58cfb06 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ProfileScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ProfileScreen.kt @@ -28,6 +28,8 @@ import com.example.casera.storage.TokenStorage import com.example.casera.cache.SubscriptionCache import com.example.casera.ui.subscription.UpgradePromptDialog import androidx.compose.runtime.getValue +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -60,7 +62,7 @@ fun ProfileScreen( email = email ) }, - errorTitle = "Failed to Update Profile" + errorTitle = stringResource(Res.string.profile_update_failed) ) // Load current user data @@ -76,12 +78,12 @@ fun ProfileScreen( isLoadingUser = false } else -> { - errorMessage = "Failed to load user data" + errorMessage = "profile_load_failed" isLoadingUser = false } } } else { - errorMessage = "Not authenticated" + errorMessage = "profile_not_authenticated" isLoadingUser = false } } @@ -116,15 +118,15 @@ fun ProfileScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Profile", fontWeight = FontWeight.SemiBold) }, + title = { Text(stringResource(Res.string.profile_title), fontWeight = FontWeight.SemiBold) }, navigationIcon = { IconButton(onClick = onNavigateBack) { - Icon(Icons.Default.ArrowBack, contentDescription = "Back") + Icon(Icons.Default.ArrowBack, contentDescription = stringResource(Res.string.common_back)) } }, actions = { IconButton(onClick = onLogout) { - Icon(Icons.Default.Logout, contentDescription = "Logout") + Icon(Icons.Default.Logout, contentDescription = stringResource(Res.string.profile_logout)) } }, colors = TopAppBarDefaults.topAppBarColors( @@ -163,7 +165,7 @@ fun ProfileScreen( ) Text( - "Update Your Profile", + stringResource(Res.string.profile_update_title), style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold ) @@ -191,7 +193,7 @@ fun ProfileScreen( verticalArrangement = Arrangement.spacedBy(AppSpacing.xs) ) { Text( - text = "Appearance", + text = stringResource(Res.string.profile_appearance), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) @@ -203,7 +205,7 @@ fun ProfileScreen( } Icon( imageVector = Icons.Default.Palette, - contentDescription = "Change theme", + contentDescription = stringResource(Res.string.profile_change_theme), tint = MaterialTheme.colorScheme.primary ) } @@ -230,19 +232,19 @@ fun ProfileScreen( verticalArrangement = Arrangement.spacedBy(AppSpacing.xs) ) { Text( - text = "Notifications", + text = stringResource(Res.string.profile_notifications), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) Text( - text = "Manage notification preferences", + text = stringResource(Res.string.profile_notifications_subtitle), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant ) } Icon( imageVector = Icons.Default.Notifications, - contentDescription = "Notification preferences", + contentDescription = stringResource(Res.string.profile_notifications), tint = MaterialTheme.colorScheme.primary ) } @@ -279,16 +281,16 @@ fun ProfileScreen( verticalArrangement = Arrangement.spacedBy(AppSpacing.xs) ) { Text( - text = if (SubscriptionHelper.currentTier == "pro") "Pro Plan" else "Free Plan", + text = if (SubscriptionHelper.currentTier == "pro") stringResource(Res.string.profile_pro_plan) else stringResource(Res.string.profile_free_plan), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) Text( text = if (SubscriptionHelper.currentTier == "pro" && currentSubscription?.expiresAt != null) { - "Active until ${currentSubscription?.expiresAt}" + stringResource(Res.string.profile_active_until, currentSubscription?.expiresAt ?: "") } else { - "Limited features" + stringResource(Res.string.profile_limited_features) }, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant @@ -309,11 +311,11 @@ fun ProfileScreen( contentDescription = null ) Spacer(modifier = Modifier.width(AppSpacing.sm)) - Text("Upgrade to Pro", fontWeight = FontWeight.SemiBold) + Text(stringResource(Res.string.profile_upgrade_to_pro), fontWeight = FontWeight.SemiBold) } } else { Text( - text = "Manage your subscription in the Google Play Store", + text = stringResource(Res.string.profile_manage_subscription), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = AppSpacing.xs) @@ -326,7 +328,7 @@ fun ProfileScreen( } Text( - "Profile Information", + stringResource(Res.string.profile_information), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold, modifier = Modifier.align(Alignment.Start) @@ -335,7 +337,7 @@ fun ProfileScreen( OutlinedTextField( value = firstName, onValueChange = { firstName = it }, - label = { Text("First Name") }, + label = { Text(stringResource(Res.string.profile_first_name)) }, leadingIcon = { Icon(Icons.Default.Person, contentDescription = null) }, @@ -347,7 +349,7 @@ fun ProfileScreen( OutlinedTextField( value = lastName, onValueChange = { lastName = it }, - label = { Text("Last Name") }, + label = { Text(stringResource(Res.string.profile_last_name)) }, leadingIcon = { Icon(Icons.Default.Person, contentDescription = null) }, @@ -359,7 +361,7 @@ fun ProfileScreen( OutlinedTextField( value = email, onValueChange = { email = it }, - label = { Text("Email") }, + label = { Text(stringResource(Res.string.profile_email)) }, leadingIcon = { Icon(Icons.Default.Email, contentDescription = null) }, @@ -369,6 +371,13 @@ fun ProfileScreen( ) if (errorMessage.isNotEmpty()) { + val displayError = when (errorMessage) { + "profile_load_failed" -> stringResource(Res.string.profile_load_failed) + "profile_not_authenticated" -> stringResource(Res.string.profile_not_authenticated) + "profile_update_coming_soon" -> stringResource(Res.string.profile_update_coming_soon) + "profile_email_required" -> stringResource(Res.string.profile_email_required) + else -> errorMessage + } Card( modifier = Modifier.fillMaxWidth(), colors = CardDefaults.cardColors( @@ -389,7 +398,7 @@ fun ProfileScreen( tint = MaterialTheme.colorScheme.error ) Text( - errorMessage, + displayError, color = MaterialTheme.colorScheme.error, style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.SemiBold @@ -434,9 +443,9 @@ fun ProfileScreen( onClick = { if (email.isNotEmpty()) { // viewModel.updateProfile not available yet - errorMessage = "Profile update coming soon" + errorMessage = "profile_update_coming_soon" } else { - errorMessage = "Email is required" + errorMessage = "profile_email_required" } }, modifier = Modifier @@ -458,7 +467,7 @@ fun ProfileScreen( ) { Icon(Icons.Default.Save, contentDescription = null) Text( - "Save Changes", + stringResource(Res.string.profile_save), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/RegisterScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/RegisterScreen.kt index 9f1fffb..2bb0e1a 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/RegisterScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/RegisterScreen.kt @@ -19,6 +19,8 @@ import com.example.casera.ui.components.auth.AuthHeader import com.example.casera.ui.components.common.ErrorCard import com.example.casera.viewmodel.AuthViewModel import com.example.casera.network.ApiResult +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -39,7 +41,7 @@ fun RegisterScreen( // Handle errors for registration createState.HandleErrors( onRetry = { viewModel.register(username, email, password) }, - errorTitle = "Registration Failed" + errorTitle = stringResource(Res.string.error_generic) ) LaunchedEffect(createState) { @@ -55,10 +57,10 @@ fun RegisterScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Create Account", fontWeight = FontWeight.SemiBold) }, + title = { Text(stringResource(Res.string.auth_register_title), fontWeight = FontWeight.SemiBold) }, navigationIcon = { IconButton(onClick = onNavigateBack) { - Icon(Icons.Default.ArrowBack, contentDescription = "Back") + Icon(Icons.Default.ArrowBack, contentDescription = stringResource(Res.string.common_back)) } }, colors = TopAppBarDefaults.topAppBarColors( @@ -80,8 +82,8 @@ fun RegisterScreen( AuthHeader( icon = Icons.Default.PersonAdd, - title = "Join myCrib", - subtitle = "Start managing your properties today" + title = stringResource(Res.string.auth_register_title), + subtitle = stringResource(Res.string.auth_register_subtitle) ) Spacer(modifier = Modifier.height(16.dp)) @@ -89,7 +91,7 @@ fun RegisterScreen( OutlinedTextField( value = username, onValueChange = { username = it }, - label = { Text("Username") }, + label = { Text(stringResource(Res.string.auth_register_username)) }, leadingIcon = { Icon(Icons.Default.Person, contentDescription = null) }, @@ -101,7 +103,7 @@ fun RegisterScreen( OutlinedTextField( value = email, onValueChange = { email = it }, - label = { Text("Email") }, + label = { Text(stringResource(Res.string.auth_register_email)) }, leadingIcon = { Icon(Icons.Default.Email, contentDescription = null) }, @@ -113,7 +115,7 @@ fun RegisterScreen( OutlinedTextField( value = password, onValueChange = { password = it }, - label = { Text("Password") }, + label = { Text(stringResource(Res.string.auth_register_password)) }, leadingIcon = { Icon(Icons.Default.Lock, contentDescription = null) }, @@ -126,7 +128,7 @@ fun RegisterScreen( OutlinedTextField( value = confirmPassword, onValueChange = { confirmPassword = it }, - label = { Text("Confirm Password") }, + label = { Text(stringResource(Res.string.auth_register_confirm_password)) }, leadingIcon = { Icon(Icons.Default.Lock, contentDescription = null) }, @@ -140,11 +142,12 @@ fun RegisterScreen( Spacer(modifier = Modifier.height(8.dp)) + val passwordsDontMatchMessage = stringResource(Res.string.auth_passwords_dont_match) Button( onClick = { when { password != confirmPassword -> { - errorMessage = "Passwords do not match" + errorMessage = passwordsDontMatchMessage } else -> { isLoading = true @@ -168,7 +171,7 @@ fun RegisterScreen( ) } else { Text( - "Create Account", + stringResource(Res.string.auth_register_button), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResetPasswordScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResetPasswordScreen.kt index 05fece0..55e0218 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResetPasswordScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResetPasswordScreen.kt @@ -20,6 +20,8 @@ import com.example.casera.ui.components.auth.RequirementItem import com.example.casera.ui.components.common.ErrorCard import com.example.casera.viewmodel.PasswordResetViewModel import com.example.casera.network.ApiResult +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -59,11 +61,11 @@ fun ResetPasswordScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Reset Password") }, + title = { Text(stringResource(Res.string.auth_reset_title)) }, navigationIcon = { onNavigateBack?.let { callback -> IconButton(onClick = callback) { - Icon(Icons.Default.ArrowBack, contentDescription = "Back") + Icon(Icons.Default.ArrowBack, contentDescription = stringResource(Res.string.common_back)) } } }, @@ -184,7 +186,7 @@ fun ResetPasswordScreen( newPassword = it viewModel.resetResetPasswordState() }, - label = { Text("New Password") }, + label = { Text(stringResource(Res.string.auth_reset_new_password)) }, leadingIcon = { Icon(Icons.Default.Lock, contentDescription = null) }, @@ -209,7 +211,7 @@ fun ResetPasswordScreen( confirmPassword = it viewModel.resetResetPasswordState() }, - label = { Text("Confirm Password") }, + label = { Text(stringResource(Res.string.auth_reset_confirm_password)) }, leadingIcon = { Icon(Icons.Default.Lock, contentDescription = null) }, @@ -250,7 +252,7 @@ fun ResetPasswordScreen( Icon(Icons.Default.LockReset, contentDescription = null) Spacer(modifier = Modifier.width(8.dp)) Text( - "Reset Password", + stringResource(Res.string.auth_reset_button), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResidenceDetailScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResidenceDetailScreen.kt index 8bd39dc..39c5db4 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResidenceDetailScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResidenceDetailScreen.kt @@ -36,6 +36,8 @@ import com.example.casera.ui.subscription.UpgradePromptDialog import com.example.casera.cache.SubscriptionCache import com.example.casera.cache.DataCache import com.example.casera.util.DateUtils +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -146,7 +148,7 @@ fun ResidenceDetailScreen( // Handle errors for generate report generateReportState.HandleErrors( onRetry = { residenceViewModel.generateTasksReport(residenceId) }, - errorTitle = "Failed to Generate Report" + errorTitle = stringResource(Res.string.properties_failed_to_generate_report) ) LaunchedEffect(generateReportState) { @@ -164,7 +166,7 @@ fun ResidenceDetailScreen( // Handle errors for delete residence deleteState.HandleErrors( onRetry = { residenceViewModel.deleteResidence(residenceId) }, - errorTitle = "Failed to Delete Property" + errorTitle = stringResource(Res.string.properties_failed_to_delete) ) // Handle delete residence state @@ -245,8 +247,8 @@ fun ResidenceDetailScreen( if (showReportConfirmation) { AlertDialog( onDismissRequest = { showReportConfirmation = false }, - title = { Text("Generate Report") }, - text = { Text("This will generate and email a maintenance report for this property. Do you want to continue?") }, + title = { Text(stringResource(Res.string.properties_generate_report)) }, + text = { Text(stringResource(Res.string.properties_generate_report_confirm)) }, confirmButton = { Button( onClick = { @@ -254,12 +256,12 @@ fun ResidenceDetailScreen( residenceViewModel.generateTasksReport(residenceId) } ) { - Text("Generate") + Text(stringResource(Res.string.properties_generate)) } }, dismissButton = { TextButton(onClick = { showReportConfirmation = false }) { - Text("Cancel") + Text(stringResource(Res.string.common_cancel)) } } ) @@ -269,8 +271,8 @@ fun ResidenceDetailScreen( val residence = (residenceState as ApiResult.Success).data AlertDialog( onDismissRequest = { showDeleteConfirmation = false }, - title = { Text("Delete Residence") }, - text = { Text("Are you sure you want to delete ${residence.name}? This action cannot be undone.") }, + title = { Text(stringResource(Res.string.properties_delete_residence)) }, + text = { Text(stringResource(Res.string.properties_delete_name_confirm, residence.name)) }, confirmButton = { Button( onClick = { @@ -281,12 +283,12 @@ fun ResidenceDetailScreen( containerColor = MaterialTheme.colorScheme.error ) ) { - Text("Delete") + Text(stringResource(Res.string.common_delete)) } }, dismissButton = { TextButton(onClick = { showDeleteConfirmation = false }) { - Text("Cancel") + Text(stringResource(Res.string.common_cancel)) } } ) @@ -298,8 +300,8 @@ fun ResidenceDetailScreen( showCancelTaskConfirmation = false taskToCancel = null }, - title = { Text("Cancel Task") }, - text = { Text("Are you sure you want to cancel \"${taskToCancel!!.title}\"? This action cannot be undone.") }, + title = { Text(stringResource(Res.string.properties_cancel_task)) }, + text = { Text(stringResource(Res.string.properties_cancel_task_confirm, taskToCancel!!.title)) }, confirmButton = { Button( onClick = { @@ -311,7 +313,7 @@ fun ResidenceDetailScreen( containerColor = MaterialTheme.colorScheme.error ) ) { - Text("Cancel Task") + Text(stringResource(Res.string.properties_cancel_task)) } }, dismissButton = { @@ -319,7 +321,7 @@ fun ResidenceDetailScreen( showCancelTaskConfirmation = false taskToCancel = null }) { - Text("Dismiss") + Text(stringResource(Res.string.properties_dismiss)) } } ) @@ -331,8 +333,8 @@ fun ResidenceDetailScreen( showArchiveTaskConfirmation = false taskToArchive = null }, - title = { Text("Archive Task") }, - text = { Text("Are you sure you want to archive \"${taskToArchive!!.title}\"? You can unarchive it later from archived tasks.") }, + title = { Text(stringResource(Res.string.properties_archive_task)) }, + text = { Text(stringResource(Res.string.properties_archive_task_confirm, taskToArchive!!.title)) }, confirmButton = { Button( onClick = { @@ -348,7 +350,7 @@ fun ResidenceDetailScreen( containerColor = MaterialTheme.colorScheme.error ) ) { - Text("Archive") + Text(stringResource(Res.string.tasks_archive)) } }, dismissButton = { @@ -356,7 +358,7 @@ fun ResidenceDetailScreen( showArchiveTaskConfirmation = false taskToArchive = null }) { - Text("Dismiss") + Text(stringResource(Res.string.properties_dismiss)) } } ) @@ -375,10 +377,10 @@ fun ResidenceDetailScreen( snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, topBar = { TopAppBar( - title = { Text("Property Details", fontWeight = FontWeight.Bold) }, + title = { Text(stringResource(Res.string.properties_details), fontWeight = FontWeight.Bold) }, navigationIcon = { IconButton(onClick = onNavigateBack) { - Icon(Icons.Default.ArrowBack, contentDescription = "Back") + Icon(Icons.Default.ArrowBack, contentDescription = stringResource(Res.string.common_back)) } }, actions = { @@ -399,7 +401,7 @@ fun ResidenceDetailScreen( strokeWidth = 2.dp ) } else { - Icon(Icons.Default.Description, contentDescription = "Generate Report") + Icon(Icons.Default.Description, contentDescription = stringResource(Res.string.properties_generate_report)) } } @@ -408,14 +410,14 @@ fun ResidenceDetailScreen( IconButton(onClick = { showManageUsersDialog = true }) { - Icon(Icons.Default.People, contentDescription = "Manage Users") + Icon(Icons.Default.People, contentDescription = stringResource(Res.string.properties_manage_users)) } } IconButton(onClick = { onNavigateToEditResidence(residence) }) { - Icon(Icons.Default.Edit, contentDescription = "Edit Residence") + Icon(Icons.Default.Edit, contentDescription = stringResource(Res.string.properties_edit_residence)) } // Delete button - only show for primary owners @@ -425,7 +427,7 @@ fun ResidenceDetailScreen( }) { Icon( Icons.Default.Delete, - contentDescription = "Delete Residence", + contentDescription = stringResource(Res.string.properties_delete_residence), tint = MaterialTheme.colorScheme.error ) } @@ -453,7 +455,7 @@ fun ResidenceDetailScreen( containerColor = MaterialTheme.colorScheme.primary, shape = RoundedCornerShape(16.dp) ) { - Icon(Icons.Default.Add, contentDescription = "Add Task") + Icon(Icons.Default.Add, contentDescription = stringResource(Res.string.properties_add_task)) } } } @@ -466,7 +468,7 @@ fun ResidenceDetailScreen( } }, modifier = Modifier.padding(paddingValues), - errorTitle = "Failed to Load Property", + errorTitle = stringResource(Res.string.properties_failed_to_load), loadingContent = { Column( horizontalAlignment = Alignment.CenterHorizontally, @@ -474,7 +476,7 @@ fun ResidenceDetailScreen( ) { CircularProgressIndicator() Text( - text = "Loading residence...", + text = stringResource(Res.string.properties_loading), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -528,7 +530,7 @@ fun ResidenceDetailScreen( item { InfoCard( icon = Icons.Default.LocationOn, - title = "Address" + title = stringResource(Res.string.properties_address_section) ) { if (residence.streetAddress != null) { Text(text = residence.streetAddress) @@ -552,7 +554,7 @@ fun ResidenceDetailScreen( item { InfoCard( icon = Icons.Default.Info, - title = "Property Details" + title = stringResource(Res.string.properties_property_details_section) ) { Row( modifier = Modifier.fillMaxWidth(), @@ -584,7 +586,7 @@ fun ResidenceDetailScreen( item { InfoCard( icon = Icons.Default.Description, - title = "Description" + title = stringResource(Res.string.properties_description_section) ) { Text( text = residence.description, @@ -600,7 +602,7 @@ fun ResidenceDetailScreen( item { InfoCard( icon = Icons.Default.AttachMoney, - title = "Purchase Information" + title = stringResource(Res.string.properties_purchase_info) ) { residence.purchaseDate?.let { DetailRow(Icons.Default.Event, "Purchase Date", DateUtils.formatDateMedium(it)) @@ -628,7 +630,7 @@ fun ResidenceDetailScreen( ) Spacer(modifier = Modifier.width(8.dp)) Text( - text = "Tasks", + text = stringResource(Res.string.tasks_title), style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.primary @@ -688,12 +690,12 @@ fun ResidenceDetailScreen( ) Spacer(modifier = Modifier.height(16.dp)) Text( - "No tasks yet", + stringResource(Res.string.properties_no_tasks), style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.SemiBold ) Text( - "Add a task to get started", + stringResource(Res.string.properties_add_task_start), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -767,7 +769,7 @@ fun ResidenceDetailScreen( ) Spacer(modifier = Modifier.width(8.dp)) Text( - text = "Contractors", + text = stringResource(Res.string.contractors_title), style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.primary @@ -826,12 +828,12 @@ fun ResidenceDetailScreen( ) Spacer(modifier = Modifier.height(12.dp)) Text( - "No contractors yet", + stringResource(Res.string.properties_no_contractors), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) Text( - "Add contractors from the Contractors tab", + stringResource(Res.string.properties_add_contractors_hint), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant ) diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResidenceFormScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResidenceFormScreen.kt index a9de9c4..cdc7210 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResidenceFormScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResidenceFormScreen.kt @@ -18,6 +18,8 @@ import com.example.casera.models.Residence import com.example.casera.models.ResidenceCreateRequest import com.example.casera.models.ResidenceType import com.example.casera.network.ApiResult +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -85,11 +87,13 @@ fun ResidenceFormScreen( } } + val nameRequiredError = stringResource(Res.string.properties_form_name_error) + fun validateForm(): Boolean { var isValid = true if (name.isBlank()) { - nameError = "Name is required" + nameError = nameRequiredError isValid = false } else { nameError = "" @@ -101,10 +105,10 @@ fun ResidenceFormScreen( Scaffold( topBar = { TopAppBar( - title = { Text(if (isEditMode) "Edit Residence" else "Add Residence") }, + title = { Text(if (isEditMode) stringResource(Res.string.properties_edit_title) else stringResource(Res.string.properties_add_title)) }, navigationIcon = { IconButton(onClick = onNavigateBack) { - Icon(Icons.Default.ArrowBack, contentDescription = "Back") + Icon(Icons.Default.ArrowBack, contentDescription = stringResource(Res.string.common_back)) } } ) @@ -120,7 +124,7 @@ fun ResidenceFormScreen( ) { // Basic Information section Text( - text = "Property Details", + text = stringResource(Res.string.properties_details), style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.primary ) @@ -128,13 +132,13 @@ fun ResidenceFormScreen( OutlinedTextField( value = name, onValueChange = { name = it }, - label = { Text("Property Name *") }, + label = { Text(stringResource(Res.string.properties_form_name_required)) }, modifier = Modifier.fillMaxWidth(), isError = nameError.isNotEmpty(), supportingText = if (nameError.isNotEmpty()) { { Text(nameError, color = MaterialTheme.colorScheme.error) } } else { - { Text("Required", color = MaterialTheme.colorScheme.error) } + { Text(stringResource(Res.string.properties_form_required), color = MaterialTheme.colorScheme.error) } } ) @@ -146,7 +150,7 @@ fun ResidenceFormScreen( value = propertyType?.name?.replaceFirstChar { it.uppercase() } ?: "", onValueChange = {}, readOnly = true, - label = { Text("Property Type") }, + label = { Text(stringResource(Res.string.properties_type_label)) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, modifier = Modifier .fillMaxWidth() @@ -171,7 +175,7 @@ fun ResidenceFormScreen( // Address section Text( - text = "Address", + text = stringResource(Res.string.properties_address_section), style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.primary ) @@ -179,49 +183,49 @@ fun ResidenceFormScreen( OutlinedTextField( value = streetAddress, onValueChange = { streetAddress = it }, - label = { Text("Street Address") }, + label = { Text(stringResource(Res.string.properties_form_street)) }, modifier = Modifier.fillMaxWidth() ) OutlinedTextField( value = apartmentUnit, onValueChange = { apartmentUnit = it }, - label = { Text("Apartment/Unit #") }, + label = { Text(stringResource(Res.string.properties_form_apartment)) }, modifier = Modifier.fillMaxWidth() ) OutlinedTextField( value = city, onValueChange = { city = it }, - label = { Text("City") }, + label = { Text(stringResource(Res.string.properties_form_city)) }, modifier = Modifier.fillMaxWidth() ) OutlinedTextField( value = stateProvince, onValueChange = { stateProvince = it }, - label = { Text("State/Province") }, + label = { Text(stringResource(Res.string.properties_form_state)) }, modifier = Modifier.fillMaxWidth() ) OutlinedTextField( value = postalCode, onValueChange = { postalCode = it }, - label = { Text("Postal Code") }, + label = { Text(stringResource(Res.string.properties_form_postal)) }, modifier = Modifier.fillMaxWidth() ) OutlinedTextField( value = country, onValueChange = { country = it }, - label = { Text("Country") }, + label = { Text(stringResource(Res.string.properties_form_country)) }, modifier = Modifier.fillMaxWidth() ) // Optional fields section Divider() Text( - text = "Optional Details", + text = stringResource(Res.string.properties_form_optional), style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.primary ) @@ -233,7 +237,7 @@ fun ResidenceFormScreen( OutlinedTextField( value = bedrooms, onValueChange = { bedrooms = it.filter { char -> char.isDigit() } }, - label = { Text("Bedrooms") }, + label = { Text(stringResource(Res.string.properties_bedrooms)) }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), modifier = Modifier.weight(1f) ) @@ -241,7 +245,7 @@ fun ResidenceFormScreen( OutlinedTextField( value = bathrooms, onValueChange = { bathrooms = it }, - label = { Text("Bathrooms") }, + label = { Text(stringResource(Res.string.properties_bathrooms)) }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal), modifier = Modifier.weight(1f) ) @@ -250,7 +254,7 @@ fun ResidenceFormScreen( OutlinedTextField( value = squareFootage, onValueChange = { squareFootage = it.filter { char -> char.isDigit() } }, - label = { Text("Square Footage") }, + label = { Text(stringResource(Res.string.properties_form_sqft)) }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), modifier = Modifier.fillMaxWidth() ) @@ -258,7 +262,7 @@ fun ResidenceFormScreen( OutlinedTextField( value = lotSize, onValueChange = { lotSize = it }, - label = { Text("Lot Size (acres)") }, + label = { Text(stringResource(Res.string.properties_form_lot_size)) }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal), modifier = Modifier.fillMaxWidth() ) @@ -266,7 +270,7 @@ fun ResidenceFormScreen( OutlinedTextField( value = yearBuilt, onValueChange = { yearBuilt = it.filter { char -> char.isDigit() } }, - label = { Text("Year Built") }, + label = { Text(stringResource(Res.string.properties_year_built)) }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), modifier = Modifier.fillMaxWidth() ) @@ -274,7 +278,7 @@ fun ResidenceFormScreen( OutlinedTextField( value = description, onValueChange = { description = it }, - label = { Text("Description") }, + label = { Text(stringResource(Res.string.properties_form_description)) }, modifier = Modifier.fillMaxWidth(), minLines = 3, maxLines = 5 @@ -284,7 +288,7 @@ fun ResidenceFormScreen( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { - Text("Primary Residence") + Text(stringResource(Res.string.properties_form_primary)) Switch( checked = isPrimary, onCheckedChange = { isPrimary = it } @@ -338,7 +342,7 @@ fun ResidenceFormScreen( color = MaterialTheme.colorScheme.onPrimary ) } else { - Text(if (isEditMode) "Update Residence" else "Create Residence") + Text(if (isEditMode) stringResource(Res.string.properties_form_update) else stringResource(Res.string.properties_form_create)) } } diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResidencesScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResidencesScreen.kt index c0add3e..cea84a0 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResidencesScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/ResidencesScreen.kt @@ -29,6 +29,8 @@ import com.example.casera.network.ApiResult import com.example.casera.utils.SubscriptionHelper import com.example.casera.ui.subscription.UpgradePromptDialog import com.example.casera.cache.SubscriptionCache +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -107,7 +109,7 @@ fun ResidencesScreen( TopAppBar( title = { Text( - "My Properties", + stringResource(Res.string.properties_title), fontWeight = FontWeight.Bold ) }, @@ -123,14 +125,14 @@ fun ResidencesScreen( showUpgradePrompt = true } }) { - Icon(Icons.Default.GroupAdd, contentDescription = "Join with Code") + Icon(Icons.Default.GroupAdd, contentDescription = stringResource(Res.string.properties_join_title)) } } IconButton(onClick = onNavigateToProfile) { - Icon(Icons.Default.AccountCircle, contentDescription = "Profile") + Icon(Icons.Default.AccountCircle, contentDescription = stringResource(Res.string.profile_title)) } IconButton(onClick = onLogout) { - Icon(Icons.Default.ExitToApp, contentDescription = "Logout") + Icon(Icons.Default.ExitToApp, contentDescription = stringResource(Res.string.home_logout)) } }, colors = TopAppBarDefaults.topAppBarColors( @@ -163,7 +165,7 @@ fun ResidencesScreen( ) { Icon( Icons.Default.Add, - contentDescription = "Add Property", + contentDescription = stringResource(Res.string.properties_add_button), tint = MaterialTheme.colorScheme.onPrimary ) } @@ -176,7 +178,7 @@ fun ResidencesScreen( state = myResidencesState, onRetry = { viewModel.loadMyResidences() }, modifier = Modifier.padding(paddingValues), - errorTitle = "Failed to Load Properties" + errorTitle = stringResource(Res.string.error_generic) ) { response -> if (response.residences.isEmpty()) { Box( @@ -197,12 +199,12 @@ fun ResidencesScreen( tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.6f) ) Text( - "No properties yet", + stringResource(Res.string.properties_empty_title), style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.SemiBold ) Text( - "Add your first property to get started!", + stringResource(Res.string.properties_empty_subtitle), style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -230,7 +232,7 @@ fun ResidencesScreen( ) { Icon(Icons.Default.Add, contentDescription = null) Text( - "Add Property", + stringResource(Res.string.properties_add_button), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) @@ -258,7 +260,7 @@ fun ResidencesScreen( ) { Icon(Icons.Default.GroupAdd, contentDescription = null) Text( - "Join with Code", + stringResource(Res.string.properties_join_button), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) @@ -339,7 +341,7 @@ fun ResidencesScreen( ) Spacer(modifier = Modifier.width(8.dp)) Text( - text = "Overview", + text = stringResource(Res.string.home_overview), style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.onPrimaryContainer @@ -353,12 +355,12 @@ fun ResidencesScreen( StatItem( icon = Icons.Default.Home, value = "${response.summary.totalResidences}", - label = "Properties" + label = stringResource(Res.string.home_properties) ) StatItem( icon = Icons.Default.Assignment, value = "${response.summary.totalTasks}", - label = "Total Tasks" + label = stringResource(Res.string.home_total_tasks) ) } @@ -373,12 +375,12 @@ fun ResidencesScreen( StatItem( icon = Icons.Default.CalendarToday, value = "${response.summary.tasksDueNextWeek}", - label = "Due This Week" + label = stringResource(Res.string.tasks_column_due_soon) ) StatItem( icon = Icons.Default.Event, value = "${response.summary.tasksDueNextMonth}", - label = "Next 30 Days" + label = stringResource(Res.string.tasks_column_upcoming) ) } } diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/TasksScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/TasksScreen.kt index d428a79..b6d1141 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/TasksScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/TasksScreen.kt @@ -19,6 +19,8 @@ import com.example.casera.ui.utils.hexToColor import com.example.casera.viewmodel.TaskCompletionViewModel import com.example.casera.viewmodel.TaskViewModel import com.example.casera.network.ApiResult +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -64,10 +66,10 @@ fun TasksScreen( Scaffold( topBar = { TopAppBar( - title = { Text("All Tasks") }, + title = { Text(stringResource(Res.string.tasks_title)) }, navigationIcon = { IconButton(onClick = onNavigateBack) { - Icon(Icons.Default.ArrowBack, contentDescription = "Back") + Icon(Icons.Default.ArrowBack, contentDescription = stringResource(Res.string.common_back)) } } ) @@ -108,20 +110,15 @@ fun TasksScreen( tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.6f) ) Text( - "No tasks yet", + stringResource(Res.string.tasks_empty_title), style = MaterialTheme.typography.headlineSmall, fontWeight = androidx.compose.ui.text.font.FontWeight.SemiBold ) Text( - "Tasks are created from your properties.", + stringResource(Res.string.tasks_empty_subtitle), style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurfaceVariant ) - Text( - "Go to Residences tab to add a property, then add tasks to it!", - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f) - ) } } } else { diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/VerifyEmailScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/VerifyEmailScreen.kt index 49969a5..4759915 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/VerifyEmailScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/VerifyEmailScreen.kt @@ -21,6 +21,8 @@ import com.example.casera.ui.components.auth.AuthHeader import com.example.casera.ui.components.common.ErrorCard import com.example.casera.viewmodel.AuthViewModel import com.example.casera.network.ApiResult +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -65,7 +67,7 @@ fun VerifyEmailScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Verify Email", fontWeight = FontWeight.SemiBold) }, + title = { Text(stringResource(Res.string.auth_verify_title), fontWeight = FontWeight.SemiBold) }, actions = { TextButton(onClick = onLogout) { Row( @@ -77,7 +79,7 @@ fun VerifyEmailScreen( contentDescription = null, modifier = Modifier.size(18.dp) ) - Text("Logout") + Text(stringResource(Res.string.home_logout)) } } }, @@ -100,8 +102,8 @@ fun VerifyEmailScreen( AuthHeader( icon = Icons.Default.MarkEmailRead, - title = "Verify Your Email", - subtitle = "You must verify your email address to continue" + title = stringResource(Res.string.auth_verify_title), + subtitle = stringResource(Res.string.auth_verify_subtitle) ) Spacer(modifier = Modifier.height(16.dp)) @@ -140,7 +142,7 @@ fun VerifyEmailScreen( code = it } }, - label = { Text("Verification Code") }, + label = { Text(stringResource(Res.string.auth_verify_code_label)) }, leadingIcon = { Icon(Icons.Default.Pin, contentDescription = null) }, @@ -184,7 +186,7 @@ fun VerifyEmailScreen( ) { Icon(Icons.Default.CheckCircle, contentDescription = null) Text( - "Verify Email", + stringResource(Res.string.auth_verify_button), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) diff --git a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/VerifyResetCodeScreen.kt b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/VerifyResetCodeScreen.kt index 560054d..c260d15 100644 --- a/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/VerifyResetCodeScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/example/casera/ui/screens/VerifyResetCodeScreen.kt @@ -19,6 +19,8 @@ import com.example.casera.ui.components.auth.AuthHeader import com.example.casera.ui.components.common.ErrorCard import com.example.casera.viewmodel.PasswordResetViewModel import com.example.casera.network.ApiResult +import casera.composeapp.generated.resources.* +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -56,10 +58,10 @@ fun VerifyResetCodeScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Verify Code") }, + title = { Text(stringResource(Res.string.auth_verify_title)) }, navigationIcon = { IconButton(onClick = onNavigateBack) { - Icon(Icons.Default.ArrowBack, contentDescription = "Back") + Icon(Icons.Default.ArrowBack, contentDescription = stringResource(Res.string.common_back)) } }, colors = TopAppBarDefaults.topAppBarColors( @@ -140,7 +142,7 @@ fun VerifyResetCodeScreen( viewModel.resetVerifyCodeState() } }, - label = { Text("Verification Code") }, + label = { Text(stringResource(Res.string.auth_verify_code_label)) }, placeholder = { Text("000000") }, modifier = Modifier.fillMaxWidth(), singleLine = true, @@ -210,7 +212,7 @@ fun VerifyResetCodeScreen( Icon(Icons.Default.CheckCircle, contentDescription = null) Spacer(modifier = Modifier.width(8.dp)) Text( - "Verify Code", + stringResource(Res.string.auth_verify_button), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) @@ -234,7 +236,7 @@ fun VerifyResetCodeScreen( onNavigateBack() }) { Text( - "Send New Code", + stringResource(Res.string.auth_verify_resend), style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.SemiBold ) diff --git a/composeApp/src/iosMain/kotlin/com/example/casera/network/ApiClient.ios.kt b/composeApp/src/iosMain/kotlin/com/example/casera/network/ApiClient.ios.kt index 75a1b2c..30a1e19 100644 --- a/composeApp/src/iosMain/kotlin/com/example/casera/network/ApiClient.ios.kt +++ b/composeApp/src/iosMain/kotlin/com/example/casera/network/ApiClient.ios.kt @@ -2,13 +2,23 @@ package com.example.casera.network import io.ktor.client.* import io.ktor.client.engine.darwin.* +import io.ktor.client.plugins.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.logging.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.json.Json +import platform.Foundation.NSLocale +import platform.Foundation.preferredLanguages actual fun getLocalhostAddress(): String = "127.0.0.1" +actual fun getDeviceLanguage(): String { + val preferredLanguages = NSLocale.preferredLanguages + val firstLanguage = preferredLanguages.firstOrNull() as? String + // Extract just the language code (e.g., "en" from "en-US") + return firstLanguage?.split("-")?.firstOrNull() ?: "en" +} + actual fun createHttpClient(): HttpClient { return HttpClient(Darwin) { install(ContentNegotiation) { @@ -24,6 +34,10 @@ actual fun createHttpClient(): HttpClient { level = LogLevel.ALL } + install(DefaultRequest) { + headers.append("Accept-Language", getDeviceLanguage()) + } + engine { configureRequest { setAllowsCellularAccess(true) diff --git a/composeApp/src/jsMain/kotlin/com/example/casera/network/ApiClient.js.kt b/composeApp/src/jsMain/kotlin/com/example/casera/network/ApiClient.js.kt index c96fac6..95f7aad 100644 --- a/composeApp/src/jsMain/kotlin/com/example/casera/network/ApiClient.js.kt +++ b/composeApp/src/jsMain/kotlin/com/example/casera/network/ApiClient.js.kt @@ -1,14 +1,20 @@ -package com.casera.shared.network +package com.example.casera.network import io.ktor.client.* import io.ktor.client.engine.js.* +import io.ktor.client.plugins.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.logging.* import io.ktor.serialization.kotlinx.json.* +import kotlinx.browser.window import kotlinx.serialization.json.Json actual fun getLocalhostAddress(): String = "127.0.0.1" +actual fun getDeviceLanguage(): String { + return window.navigator.language.split("-").firstOrNull() ?: "en" +} + actual fun createHttpClient(): HttpClient { return HttpClient(Js) { install(ContentNegotiation) { @@ -23,5 +29,9 @@ actual fun createHttpClient(): HttpClient { logger = Logger.DEFAULT level = LogLevel.ALL } + + install(DefaultRequest) { + headers.append("Accept-Language", getDeviceLanguage()) + } } } diff --git a/composeApp/src/jvmMain/kotlin/com/example/casera/network/ApiClient.jvm.kt b/composeApp/src/jvmMain/kotlin/com/example/casera/network/ApiClient.jvm.kt index 11cd810..f2fc711 100644 --- a/composeApp/src/jvmMain/kotlin/com/example/casera/network/ApiClient.jvm.kt +++ b/composeApp/src/jvmMain/kotlin/com/example/casera/network/ApiClient.jvm.kt @@ -1,14 +1,20 @@ -package com.casera.shared.network +package com.example.casera.network import io.ktor.client.* import io.ktor.client.engine.cio.* +import io.ktor.client.plugins.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.logging.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.json.Json +import java.util.Locale actual fun getLocalhostAddress(): String = "127.0.0.1" +actual fun getDeviceLanguage(): String { + return Locale.getDefault().language +} + actual fun createHttpClient(): HttpClient { return HttpClient(CIO) { install(ContentNegotiation) { @@ -23,5 +29,9 @@ actual fun createHttpClient(): HttpClient { logger = Logger.DEFAULT level = LogLevel.ALL } + + install(DefaultRequest) { + headers.append("Accept-Language", getDeviceLanguage()) + } } } diff --git a/composeApp/src/wasmJsMain/kotlin/com/example/casera/network/ApiClient.wasmJs.kt b/composeApp/src/wasmJsMain/kotlin/com/example/casera/network/ApiClient.wasmJs.kt index c96fac6..95f7aad 100644 --- a/composeApp/src/wasmJsMain/kotlin/com/example/casera/network/ApiClient.wasmJs.kt +++ b/composeApp/src/wasmJsMain/kotlin/com/example/casera/network/ApiClient.wasmJs.kt @@ -1,14 +1,20 @@ -package com.casera.shared.network +package com.example.casera.network import io.ktor.client.* import io.ktor.client.engine.js.* +import io.ktor.client.plugins.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.logging.* import io.ktor.serialization.kotlinx.json.* +import kotlinx.browser.window import kotlinx.serialization.json.Json actual fun getLocalhostAddress(): String = "127.0.0.1" +actual fun getDeviceLanguage(): String { + return window.navigator.language.split("-").firstOrNull() ?: "en" +} + actual fun createHttpClient(): HttpClient { return HttpClient(Js) { install(ContentNegotiation) { @@ -23,5 +29,9 @@ actual fun createHttpClient(): HttpClient { logger = Logger.DEFAULT level = LogLevel.ALL } + + install(DefaultRequest) { + headers.append("Accept-Language", getDeviceLanguage()) + } } } diff --git a/iosApp/iosApp/Contractor/ContractorDetailView.swift b/iosApp/iosApp/Contractor/ContractorDetailView.swift index e3252ac..727958d 100644 --- a/iosApp/iosApp/Contractor/ContractorDetailView.swift +++ b/iosApp/iosApp/Contractor/ContractorDetailView.swift @@ -29,19 +29,19 @@ struct ContractorDetailView: View { viewModel.loadContractorDetail(id: contractorId) }}) { Label( - contractor.isFavorite ? "Remove from Favorites" : "Add to Favorites", + contractor.isFavorite ? L10n.Contractors.removeFromFavorites : L10n.Contractors.addToFavorites, systemImage: contractor.isFavorite ? "star.slash" : "star" ) } Button(action: { showingEditSheet = true }) { - Label("Edit", systemImage: "pencil") + Label(L10n.Common.edit, systemImage: "pencil") } Divider() Button(role: .destructive, action: { showingDeleteAlert = true }) { - Label("Delete", systemImage: "trash") + Label(L10n.Common.delete, systemImage: "trash") } } label: { Image(systemName: "ellipsis.circle") @@ -59,13 +59,13 @@ struct ContractorDetailView: View { ) .presentationDetents([.large]) } - .alert("Delete Contractor", isPresented: $showingDeleteAlert) { - Button("Cancel", role: .cancel) {} - Button("Delete", role: .destructive) { + .alert(L10n.Contractors.deleteConfirm, isPresented: $showingDeleteAlert) { + Button(L10n.Common.cancel, role: .cancel) {} + Button(L10n.Common.delete, role: .destructive) { deleteContractor() } } message: { - Text("Are you sure you want to delete this contractor? This action cannot be undone.") + Text(L10n.Contractors.deleteMessage) } .onAppear { viewModel.loadContractorDetail(id: contractorId) @@ -200,7 +200,7 @@ struct ContractorDetailView: View { } if contractor.taskCount > 0 { - Text("\(contractor.taskCount) completed tasks") + Text(String(format: L10n.Contractors.completedTasks, contractor.taskCount)) .font(.callout) .foregroundColor(Color.appTextSecondary) } @@ -232,7 +232,7 @@ struct ContractorDetailView: View { if let phone = phone, !phone.isEmpty { QuickActionButton( icon: "phone.fill", - label: "Call", + label: L10n.Contractors.callAction, color: Color.appPrimary ) { if let url = URL(string: "tel:\(phone.replacingOccurrences(of: " ", with: ""))") { @@ -247,7 +247,7 @@ struct ContractorDetailView: View { if let email = email, !email.isEmpty { QuickActionButton( icon: "envelope.fill", - label: "Email", + label: L10n.Contractors.emailAction, color: Color.appSecondary ) { if let url = URL(string: "mailto:\(email)") { @@ -262,7 +262,7 @@ struct ContractorDetailView: View { if let website = website, !website.isEmpty { QuickActionButton( icon: "safari.fill", - label: "Website", + label: L10n.Contractors.websiteAction, color: Color.appAccent ) { var urlString = website @@ -283,7 +283,7 @@ struct ContractorDetailView: View { if hasAddress { QuickActionButton( icon: "map.fill", - label: "Directions", + label: L10n.Contractors.directionsAction, color: Color.appError ) { let address = [ @@ -310,7 +310,7 @@ struct ContractorDetailView: View { let hasWebsite = contractor.website != nil && !contractor.website!.isEmpty if hasPhone || hasEmail || hasWebsite { - DetailSection(title: "Contact Information") { + DetailSection(title: L10n.Contractors.contactInfoSection) { phoneContactRow(phone: contractor.phone) emailContactRow(email: contractor.email) websiteContactRow(website: contractor.website) @@ -323,7 +323,7 @@ struct ContractorDetailView: View { if let phone = phone, !phone.isEmpty { ContactDetailRow( icon: "phone.fill", - label: "Phone", + label: L10n.Contractors.phoneLabel, value: phone, iconColor: Color.appPrimary ) { @@ -339,7 +339,7 @@ struct ContractorDetailView: View { if let email = email, !email.isEmpty { ContactDetailRow( icon: "envelope.fill", - label: "Email", + label: L10n.Contractors.emailLabel, value: email, iconColor: Color.appSecondary ) { @@ -355,7 +355,7 @@ struct ContractorDetailView: View { if let website = website, !website.isEmpty { ContactDetailRow( icon: "safari.fill", - label: "Website", + label: L10n.Contractors.websiteLabel, value: website, iconColor: Color.appAccent ) { @@ -385,7 +385,7 @@ struct ContractorDetailView: View { ].compactMap { $0 }.filter { !$0.isEmpty } if !addressComponents.isEmpty { - DetailSection(title: "Address") { + DetailSection(title: L10n.Contractors.addressSection) { addressButton(contractor: contractor, addressComponents: addressComponents) } } @@ -414,7 +414,7 @@ struct ContractorDetailView: View { .frame(width: 20) VStack(alignment: .leading, spacing: AppSpacing.xxs) { - Text("Location") + Text(L10n.Contractors.locationLabel) .font(.caption.weight(.medium)) .foregroundColor(Color.appTextSecondary) @@ -439,14 +439,14 @@ struct ContractorDetailView: View { @ViewBuilder private func residenceSection(residenceId: Int32?) -> some View { if let residenceId = residenceId { - DetailSection(title: "Associated Property") { + DetailSection(title: L10n.Contractors.associatedPropertySection) { HStack(spacing: AppSpacing.sm) { Image(systemName: "house.fill") .foregroundColor(Color.appPrimary) .frame(width: 20) VStack(alignment: .leading, spacing: AppSpacing.xxs) { - Text("Property") + Text(L10n.Contractors.propertyLabel) .font(.caption.weight(.medium)) .foregroundColor(Color.appTextSecondary) @@ -473,7 +473,7 @@ struct ContractorDetailView: View { @ViewBuilder private func notesSection(notes: String?) -> some View { if let notes = notes, !notes.isEmpty { - DetailSection(title: "Notes") { + DetailSection(title: L10n.Contractors.notesSection) { HStack(alignment: .top, spacing: AppSpacing.sm) { Image(systemName: "note.text") .foregroundColor(Color.appAccent) @@ -493,12 +493,12 @@ struct ContractorDetailView: View { @ViewBuilder private func statisticsSection(contractor: Contractor) -> some View { - DetailSection(title: "Statistics") { + DetailSection(title: L10n.Contractors.statisticsSection) { HStack(spacing: AppSpacing.lg) { StatCard( icon: "checkmark.circle.fill", value: "\(contractor.taskCount)", - label: "Tasks Completed", + label: L10n.Contractors.tasksCompletedLabel, color: Color.appPrimary ) @@ -506,7 +506,7 @@ struct ContractorDetailView: View { StatCard( icon: "star.fill", value: String(format: "%.1f", rating.doubleValue), - label: "Average Rating", + label: L10n.Contractors.averageRatingLabel, color: Color.appAccent ) } @@ -519,7 +519,7 @@ struct ContractorDetailView: View { @ViewBuilder private func metadataSection(contractor: Contractor) -> some View { - DetailSection(title: "Info") { + DetailSection(title: L10n.Contractors.infoSection) { VStack(spacing: 0) { createdByRow(createdBy: contractor.createdBy) memberSinceRow(createdAt: contractor.createdAt) @@ -536,7 +536,7 @@ struct ContractorDetailView: View { .frame(width: 20) VStack(alignment: .leading, spacing: AppSpacing.xxs) { - Text("Added By") + Text(L10n.Contractors.addedByLabel) .font(.caption.weight(.medium)) .foregroundColor(Color.appTextSecondary) @@ -562,7 +562,7 @@ struct ContractorDetailView: View { .frame(width: 20) VStack(alignment: .leading, spacing: AppSpacing.xxs) { - Text("Member Since") + Text(L10n.Contractors.memberSinceLabel) .font(.caption.weight(.medium)) .foregroundColor(Color.appTextSecondary) diff --git a/iosApp/iosApp/Contractor/ContractorFormSheet.swift b/iosApp/iosApp/Contractor/ContractorFormSheet.swift index 3689ae5..956afc9 100644 --- a/iosApp/iosApp/Contractor/ContractorFormSheet.swift +++ b/iosApp/iosApp/Contractor/ContractorFormSheet.swift @@ -57,7 +57,7 @@ struct ContractorFormSheet: View { Image(systemName: "person") .foregroundColor(Color.appPrimary) .frame(width: 24) - TextField("Name", text: $name) + TextField(L10n.Contractors.nameLabel, text: $name) .focused($focusedField, equals: .name) } @@ -65,13 +65,13 @@ struct ContractorFormSheet: View { Image(systemName: "building.2") .foregroundColor(Color.appPrimary) .frame(width: 24) - TextField("Company", text: $company) + TextField(L10n.Contractors.companyLabel, text: $company) .focused($focusedField, equals: .company) } } header: { - Text("Basic Information") + Text(L10n.Contractors.basicInfoSection) } footer: { - Text("Required: Name") + Text(L10n.Contractors.basicInfoFooter) .font(.caption) .foregroundColor(Color.appError) } @@ -84,7 +84,7 @@ struct ContractorFormSheet: View { Image(systemName: "house") .foregroundColor(Color.appPrimary) .frame(width: 24) - Text(selectedResidenceName ?? "Personal (No Residence)") + Text(selectedResidenceName ?? L10n.Contractors.personalNoResidence) .foregroundColor(selectedResidenceName == nil ? Color.appTextSecondary.opacity(0.7) : Color.appTextPrimary) Spacer() Image(systemName: "chevron.down") @@ -93,11 +93,11 @@ struct ContractorFormSheet: View { } } } header: { - Text("Residence (Optional)") + Text(L10n.Contractors.residenceSection) } footer: { Text(selectedResidenceId == nil - ? "Only you will see this contractor" - : "All users of \(selectedResidenceName ?? "") will see this contractor") + ? L10n.Contractors.residenceFooterPersonal + : String(format: L10n.Contractors.residenceFooterShared, selectedResidenceName ?? "")) .font(.caption) } .listRowBackground(Color.appBackgroundSecondary) @@ -108,7 +108,7 @@ struct ContractorFormSheet: View { Image(systemName: "phone.fill") .foregroundColor(Color.appPrimary) .frame(width: 24) - TextField("Phone", text: $phone) + TextField(L10n.Contractors.phoneLabel, text: $phone) .keyboardType(.phonePad) .focused($focusedField, equals: .phone) } @@ -117,7 +117,7 @@ struct ContractorFormSheet: View { Image(systemName: "envelope.fill") .foregroundColor(Color.appAccent) .frame(width: 24) - TextField("Email", text: $email) + TextField(L10n.Contractors.emailLabel, text: $email) .keyboardType(.emailAddress) .textInputAutocapitalization(.never) .autocorrectionDisabled() @@ -128,14 +128,14 @@ struct ContractorFormSheet: View { Image(systemName: "globe") .foregroundColor(Color.appAccent) .frame(width: 24) - TextField("Website", text: $website) + TextField(L10n.Contractors.websiteLabel, text: $website) .keyboardType(.URL) .textInputAutocapitalization(.never) .autocorrectionDisabled() .focused($focusedField, equals: .website) } } header: { - Text("Contact Information") + Text(L10n.Contractors.contactInfoSection) } .listRowBackground(Color.appBackgroundSecondary) @@ -147,7 +147,7 @@ struct ContractorFormSheet: View { .foregroundColor(Color.appPrimary) .frame(width: 24) if selectedSpecialtyIds.isEmpty { - Text("Select Specialties") + Text(L10n.Contractors.selectSpecialtiesPlaceholder) .foregroundColor(Color.appTextSecondary.opacity(0.5)) } else { let selectedNames = specialties @@ -164,7 +164,7 @@ struct ContractorFormSheet: View { } } } header: { - Text("Specialties") + Text(L10n.Contractors.specialtiesSection) } .listRowBackground(Color.appBackgroundSecondary) @@ -174,7 +174,7 @@ struct ContractorFormSheet: View { Image(systemName: "location.fill") .foregroundColor(Color.appError) .frame(width: 24) - TextField("Street Address", text: $streetAddress) + TextField(L10n.Contractors.streetAddressLabel, text: $streetAddress) .focused($focusedField, equals: .streetAddress) } @@ -182,7 +182,7 @@ struct ContractorFormSheet: View { Image(systemName: "building.2.crop.circle") .foregroundColor(Color.appPrimary) .frame(width: 24) - TextField("City", text: $city) + TextField(L10n.Contractors.cityLabel, text: $city) .focused($focusedField, equals: .city) } @@ -191,20 +191,20 @@ struct ContractorFormSheet: View { Image(systemName: "map") .foregroundColor(Color.appAccent) .frame(width: 24) - TextField("State", text: $stateProvince) + TextField(L10n.Contractors.stateLabel, text: $stateProvince) .focused($focusedField, equals: .stateProvince) } Divider() .frame(height: 24) - TextField("ZIP", text: $postalCode) + TextField(L10n.Contractors.zipLabel, text: $postalCode) .keyboardType(.numberPad) .focused($focusedField, equals: .postalCode) .frame(maxWidth: 100) } } header: { - Text("Address") + Text(L10n.Contractors.addressSection) } .listRowBackground(Color.appBackgroundSecondary) @@ -221,9 +221,9 @@ struct ContractorFormSheet: View { .focused($focusedField, equals: .notes) } } header: { - Text("Notes") + Text(L10n.Contractors.notesSection) } footer: { - Text("Private notes about this contractor") + Text(L10n.Contractors.notesFooter) .font(.caption) } .listRowBackground(Color.appBackgroundSecondary) @@ -231,7 +231,7 @@ struct ContractorFormSheet: View { // Favorite Section { Toggle(isOn: $isFavorite) { - Label("Mark as Favorite", systemImage: "star.fill") + Label(L10n.Contractors.favoriteLabel, systemImage: "star.fill") .foregroundColor(isFavorite ? Color.appAccent : Color.appTextPrimary) } .tint(Color.appAccent) @@ -255,11 +255,11 @@ struct ContractorFormSheet: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle(contractor == nil ? "Add Contractor" : "Edit Contractor") + .navigationTitle(contractor == nil ? L10n.Contractors.addTitle : L10n.Contractors.editTitle) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Cancel") { + Button(L10n.Common.cancel) { dismiss() } } @@ -269,7 +269,7 @@ struct ContractorFormSheet: View { if viewModel.isCreating || viewModel.isUpdating { ProgressView() } else { - Text(contractor == nil ? "Add" : "Save") + Text(contractor == nil ? L10n.Contractors.addButton : L10n.Common.save) .bold() } } @@ -305,7 +305,7 @@ struct ContractorFormSheet: View { showingResidencePicker = false }) { HStack { - Text("Personal (No Residence)") + Text(L10n.Contractors.personalNoResidence) .foregroundColor(Color.appTextPrimary) Spacer() if selectedResidenceId == nil { @@ -348,11 +348,11 @@ struct ContractorFormSheet: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle("Select Residence") + .navigationTitle(L10n.Contractors.selectResidence) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .confirmationAction) { - Button("Done") { + Button(L10n.Common.done) { showingResidencePicker = false } } @@ -390,16 +390,16 @@ struct ContractorFormSheet: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle("Select Specialties") + .navigationTitle(L10n.Contractors.selectSpecialties) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Clear") { + Button(L10n.Contractors.clearAction) { selectedSpecialtyIds.removeAll() } } ToolbarItem(placement: .confirmationAction) { - Button("Done") { + Button(L10n.Common.done) { showingSpecialtyPicker = false } } diff --git a/iosApp/iosApp/Contractor/ContractorsListView.swift b/iosApp/iosApp/Contractor/ContractorsListView.swift index 5cca975..4dde7ed 100644 --- a/iosApp/iosApp/Contractor/ContractorsListView.swift +++ b/iosApp/iosApp/Contractor/ContractorsListView.swift @@ -46,7 +46,7 @@ struct ContractorsListView: View { VStack(spacing: 0) { // Search Bar - SearchBar(text: $searchText, placeholder: "Search contractors...") + SearchBar(text: $searchText, placeholder: L10n.Contractors.searchPlaceholder) .padding(.horizontal, AppSpacing.md) .padding(.top, AppSpacing.sm) @@ -56,7 +56,7 @@ struct ContractorsListView: View { HStack(spacing: AppSpacing.xs) { if showFavoritesOnly { FilterChip( - title: "Favorites", + title: L10n.Contractors.favorites, icon: "star.fill", onRemove: { showFavoritesOnly = false } ) @@ -106,7 +106,7 @@ struct ContractorsListView: View { ) } } - .navigationTitle("Contractors") + .navigationTitle(L10n.Contractors.title) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { @@ -124,7 +124,7 @@ struct ContractorsListView: View { Button(action: { selectedSpecialty = nil }) { - Label("All Specialties", systemImage: selectedSpecialty == nil ? "checkmark" : "") + Label(L10n.Contractors.allSpecialties, systemImage: selectedSpecialty == nil ? "checkmark" : "") } Divider() @@ -302,12 +302,12 @@ struct EmptyContractorsView: View { .font(.system(size: 64)) .foregroundColor(Color.appTextSecondary.opacity(0.7)) - Text(hasFilters ? "No contractors found" : "No contractors yet") + Text(hasFilters ? L10n.Contractors.emptyFiltered : L10n.Contractors.emptyTitle) .font(.title3.weight(.semibold)) .foregroundColor(Color.appTextSecondary) if !hasFilters { - Text("Add your first contractor to get started") + Text(L10n.Contractors.emptyNoFilters) .font(.callout) .foregroundColor(Color.appTextSecondary.opacity(0.7)) } diff --git a/iosApp/iosApp/Documents/Components/DocumentsTabContent.swift b/iosApp/iosApp/Documents/Components/DocumentsTabContent.swift index 96edf09..fbbd4ac 100644 --- a/iosApp/iosApp/Documents/Components/DocumentsTabContent.swift +++ b/iosApp/iosApp/Documents/Components/DocumentsTabContent.swift @@ -28,8 +28,8 @@ struct DocumentsTabContent: View { if !subscriptionCache.shouldShowUpgradePrompt(currentCount: 0, limitKey: "documents") { EmptyStateView( icon: "doc", - title: "No documents found", - message: "Add documents related to your residence" + title: L10n.Documents.noDocumentsFound, + message: L10n.Documents.noDocumentsMessage ) } else { UpgradeFeatureView( diff --git a/iosApp/iosApp/Documents/Components/WarrantiesTabContent.swift b/iosApp/iosApp/Documents/Components/WarrantiesTabContent.swift index b4951c5..082823e 100644 --- a/iosApp/iosApp/Documents/Components/WarrantiesTabContent.swift +++ b/iosApp/iosApp/Documents/Components/WarrantiesTabContent.swift @@ -30,8 +30,8 @@ struct WarrantiesTabContent: View { if !subscriptionCache.shouldShowUpgradePrompt(currentCount: 0, limitKey: "documents") { EmptyStateView( icon: "doc.text.viewfinder", - title: "No warranties found", - message: "Add warranties to track coverage periods" + title: L10n.Documents.noWarrantiesFound, + message: L10n.Documents.noWarrantiesMessage ) } else { UpgradeFeatureView( diff --git a/iosApp/iosApp/Documents/Components/WarrantyCard.swift b/iosApp/iosApp/Documents/Components/WarrantyCard.swift index caf5aee..f541de7 100644 --- a/iosApp/iosApp/Documents/Components/WarrantyCard.swift +++ b/iosApp/iosApp/Documents/Components/WarrantyCard.swift @@ -29,10 +29,10 @@ struct WarrantyCard: View { } // Fallback to client-side calculation (shouldn't happen with updated backend) - if !document.isActive { return "Inactive" } - if daysUntilExpiration < 0 { return "Expired" } - if daysUntilExpiration < 30 { return "Expiring soon" } - return "Active" + if !document.isActive { return L10n.Documents.inactive } + if daysUntilExpiration < 0 { return L10n.Documents.expired } + if daysUntilExpiration < 30 { return L10n.Documents.expiringSoon } + return L10n.Documents.activeStatus } var body: some View { @@ -68,10 +68,10 @@ struct WarrantyCard: View { // Details HStack { VStack(alignment: .leading, spacing: 2) { - Text("Provider") + Text(L10n.Documents.provider) .font(.caption.weight(.medium)) .foregroundColor(Color.appTextSecondary) - Text(document.provider ?? "N/A") + Text(document.provider ?? L10n.Documents.na) .font(.body) .fontWeight(.medium) .foregroundColor(Color.appTextPrimary) @@ -80,10 +80,10 @@ struct WarrantyCard: View { Spacer() VStack(alignment: .trailing, spacing: 2) { - Text("Expires") + Text(L10n.Documents.expires) .font(.caption.weight(.medium)) .foregroundColor(Color.appTextSecondary) - Text(DateUtils.formatDateMedium(document.endDate) ?? "N/A") + Text(DateUtils.formatDateMedium(document.endDate) ?? L10n.Documents.na) .font(.body) .fontWeight(.medium) .foregroundColor(Color.appTextPrimary) @@ -91,7 +91,7 @@ struct WarrantyCard: View { } if document.isActive && daysUntilExpiration >= 0 { - Text("\(daysUntilExpiration) days remaining") + Text(String(format: L10n.Documents.daysRemainingCount, daysUntilExpiration)) .font(.footnote.weight(.medium)) .foregroundColor(statusColor) } diff --git a/iosApp/iosApp/Documents/DocumentDetailView.swift b/iosApp/iosApp/Documents/DocumentDetailView.swift index 6c12982..f6a94d7 100644 --- a/iosApp/iosApp/Documents/DocumentDetailView.swift +++ b/iosApp/iosApp/Documents/DocumentDetailView.swift @@ -14,7 +14,7 @@ struct DocumentDetailView: View { var body: some View { ZStack { if viewModel.documentDetailState is DocumentDetailStateLoading { - ProgressView("Loading document...") + ProgressView(L10n.Documents.loadingDocument) } else if let successState = viewModel.documentDetailState as? DocumentDetailStateSuccess { documentDetailContent(document: successState.document) } else if let errorState = viewModel.documentDetailState as? DocumentDetailStateError { @@ -24,7 +24,7 @@ struct DocumentDetailView: View { .foregroundColor(.red) Text(errorState.message) .foregroundColor(.secondary) - Button("Retry") { + Button(L10n.Common.retry) { viewModel.loadDocumentDetail(id: documentId) } .buttonStyle(.borderedProminent) @@ -33,7 +33,7 @@ struct DocumentDetailView: View { EmptyView() } } - .navigationTitle("Document Details") + .navigationTitle(L10n.Documents.documentDetails) .navigationBarTitleDisplayMode(.inline) .background( // Hidden NavigationLink for programmatic navigation to edit @@ -55,13 +55,13 @@ struct DocumentDetailView: View { Button { navigateToEdit = true } label: { - Label("Edit", systemImage: "pencil") + Label(L10n.Common.edit, systemImage: "pencil") } Button(role: .destructive) { showDeleteAlert = true } label: { - Label("Delete", systemImage: "trash") + Label(L10n.Common.delete, systemImage: "trash") } } label: { Image(systemName: "ellipsis.circle") @@ -72,13 +72,13 @@ struct DocumentDetailView: View { .onAppear { viewModel.loadDocumentDetail(id: documentId) } - .alert("Delete Document", isPresented: $showDeleteAlert) { - Button("Cancel", role: .cancel) { } - Button("Delete", role: .destructive) { + .alert(L10n.Documents.deleteDocument, isPresented: $showDeleteAlert) { + Button(L10n.Common.cancel, role: .cancel) { } + Button(L10n.Common.delete, role: .destructive) { viewModel.deleteDocument(id: documentId) } } message: { - Text("Are you sure you want to delete this document? This action cannot be undone.") + Text(L10n.Documents.deleteConfirmMessage) } .onReceive(viewModel.$deleteState) { newState in if newState is DeleteStateSuccess { @@ -112,17 +112,17 @@ struct DocumentDetailView: View { // Basic Information VStack(alignment: .leading, spacing: 12) { - sectionHeader("Basic Information") + sectionHeader(L10n.Documents.basicInformation) - detailRow(label: "Title", value: document.title) - detailRow(label: "Type", value: DocumentTypeHelper.displayName(for: document.documentType)) + detailRow(label: L10n.Documents.titleField, value: document.title) + detailRow(label: L10n.Documents.documentType, value: DocumentTypeHelper.displayName(for: document.documentType)) if let category = document.category { - detailRow(label: "Category", value: DocumentCategoryHelper.displayName(for: category)) + detailRow(label: L10n.Documents.category, value: DocumentCategoryHelper.displayName(for: category)) } if let description = document.description_, !description.isEmpty { - detailRow(label: "Description", value: description) + detailRow(label: L10n.Documents.description, value: description) } } .padding() @@ -135,22 +135,22 @@ struct DocumentDetailView: View { if document.itemName != nil || document.modelNumber != nil || document.serialNumber != nil || document.provider != nil { VStack(alignment: .leading, spacing: 12) { - sectionHeader("Item Details") + sectionHeader(L10n.Documents.itemDetails) if let itemName = document.itemName { - detailRow(label: "Item Name", value: itemName) + detailRow(label: L10n.Documents.itemName, value: itemName) } if let modelNumber = document.modelNumber { - detailRow(label: "Model Number", value: modelNumber) + detailRow(label: L10n.Documents.modelNumber, value: modelNumber) } if let serialNumber = document.serialNumber { - detailRow(label: "Serial Number", value: serialNumber) + detailRow(label: L10n.Documents.serialNumber, value: serialNumber) } if let provider = document.provider { - detailRow(label: "Provider", value: provider) + detailRow(label: L10n.Documents.provider, value: provider) } if let providerContact = document.providerContact { - detailRow(label: "Provider Contact", value: providerContact) + detailRow(label: L10n.Documents.providerContact, value: providerContact) } } .padding() @@ -163,16 +163,16 @@ struct DocumentDetailView: View { if document.claimPhone != nil || document.claimEmail != nil || document.claimWebsite != nil { VStack(alignment: .leading, spacing: 12) { - sectionHeader("Claim Information") + sectionHeader(L10n.Documents.claimInformation) if let claimPhone = document.claimPhone { - detailRow(label: "Claim Phone", value: claimPhone) + detailRow(label: L10n.Documents.claimPhone, value: claimPhone) } if let claimEmail = document.claimEmail { - detailRow(label: "Claim Email", value: claimEmail) + detailRow(label: L10n.Documents.claimEmail, value: claimEmail) } if let claimWebsite = document.claimWebsite { - detailRow(label: "Claim Website", value: claimWebsite) + detailRow(label: L10n.Documents.claimWebsite, value: claimWebsite) } } .padding() @@ -185,16 +185,16 @@ struct DocumentDetailView: View { if document.purchaseDate != nil || document.startDate != nil || document.endDate != nil { VStack(alignment: .leading, spacing: 12) { - sectionHeader("Important Dates") + sectionHeader(L10n.Documents.importantDates) if let purchaseDate = document.purchaseDate { - detailRow(label: "Purchase Date", value: DateUtils.formatDateMedium(purchaseDate)) + detailRow(label: L10n.Documents.purchaseDate, value: DateUtils.formatDateMedium(purchaseDate)) } if let startDate = document.startDate { - detailRow(label: "Start Date", value: DateUtils.formatDateMedium(startDate)) + detailRow(label: L10n.Documents.startDate, value: DateUtils.formatDateMedium(startDate)) } if let endDate = document.endDate { - detailRow(label: "End Date", value: DateUtils.formatDateMedium(endDate)) + detailRow(label: L10n.Documents.endDate, value: DateUtils.formatDateMedium(endDate)) } } .padding() @@ -207,7 +207,7 @@ struct DocumentDetailView: View { // Images if !document.images.isEmpty { VStack(alignment: .leading, spacing: 12) { - sectionHeader("Images (\(document.images.count))") + sectionHeader("\(L10n.Documents.images) (\(document.images.count))") LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())], spacing: 8) { ForEach(Array(document.images.prefix(6).enumerated()), id: \.element.id) { index, image in @@ -256,16 +256,16 @@ struct DocumentDetailView: View { // Associations VStack(alignment: .leading, spacing: 12) { - sectionHeader("Associations") + sectionHeader(L10n.Documents.associations) if let residenceAddress = document.residenceAddress { - detailRow(label: "Residence", value: residenceAddress) + detailRow(label: L10n.Documents.residence, value: residenceAddress) } if let contractorName = document.contractorName { - detailRow(label: "Contractor", value: contractorName) + detailRow(label: L10n.Documents.contractor, value: contractorName) } if let contractorPhone = document.contractorPhone { - detailRow(label: "Contractor Phone", value: contractorPhone) + detailRow(label: L10n.Documents.contractorPhone, value: contractorPhone) } } .padding() @@ -276,13 +276,13 @@ struct DocumentDetailView: View { // Additional Information if document.tags != nil || document.notes != nil { VStack(alignment: .leading, spacing: 12) { - sectionHeader("Additional Information") + sectionHeader(L10n.Documents.additionalInformation) if let tags = document.tags, !tags.isEmpty { - detailRow(label: "Tags", value: tags) + detailRow(label: L10n.Documents.tags, value: tags) } if let notes = document.notes, !notes.isEmpty { - detailRow(label: "Notes", value: notes) + detailRow(label: L10n.Documents.notes, value: notes) } } .padding() @@ -294,13 +294,13 @@ struct DocumentDetailView: View { // File Information if document.fileUrl != nil { VStack(alignment: .leading, spacing: 12) { - sectionHeader("Attached File") + sectionHeader(L10n.Documents.attachedFile) if let fileType = document.fileType { - detailRow(label: "File Type", value: fileType) + detailRow(label: L10n.Documents.fileType, value: fileType) } if let fileSize = document.fileSize { - detailRow(label: "File Size", value: formatFileSize(bytes: Int(fileSize))) + detailRow(label: L10n.Documents.fileSize, value: formatFileSize(bytes: Int(fileSize))) } Button(action: { @@ -308,7 +308,7 @@ struct DocumentDetailView: View { }) { HStack { Image(systemName: "arrow.down.circle") - Text("Download File") + Text(L10n.Documents.downloadFile) } .frame(maxWidth: .infinity) .padding() @@ -325,16 +325,16 @@ struct DocumentDetailView: View { // Metadata VStack(alignment: .leading, spacing: 12) { - sectionHeader("Metadata") + sectionHeader(L10n.Documents.metadata) if let uploadedBy = document.uploadedByUsername { - detailRow(label: "Uploaded By", value: uploadedBy) + detailRow(label: L10n.Documents.uploadedBy, value: uploadedBy) } if let createdAt = document.createdAt { - detailRow(label: "Created", value: DateUtils.formatDateTime(createdAt)) + detailRow(label: L10n.Documents.created, value: DateUtils.formatDateTime(createdAt)) } if let updatedAt = document.updatedAt { - detailRow(label: "Updated", value: DateUtils.formatDateTime(updatedAt)) + detailRow(label: L10n.Documents.updated, value: DateUtils.formatDateTime(updatedAt)) } } .padding() @@ -355,7 +355,7 @@ struct DocumentDetailView: View { HStack { VStack(alignment: .leading, spacing: 4) { - Text("Status") + Text(L10n.Documents.status) .font(.caption) .foregroundColor(.secondary) Text(statusText) @@ -368,7 +368,7 @@ struct DocumentDetailView: View { if document.isActive && daysUntilExpiration >= 0 { VStack(alignment: .trailing, spacing: 4) { - Text("Days Remaining") + Text(L10n.Documents.daysRemaining) .font(.caption) .foregroundColor(.secondary) Text("\(daysUntilExpiration)") @@ -421,13 +421,13 @@ struct DocumentDetailView: View { private func getStatusText(isActive: Bool, daysUntilExpiration: Int32) -> String { if !isActive { - return "Inactive" + return L10n.Documents.inactive } else if daysUntilExpiration < 0 { - return "Expired" + return L10n.Documents.expired } else if daysUntilExpiration < 30 { - return "Expiring Soon" + return L10n.Documents.expiringSoon } else { - return "Active" + return L10n.Documents.activeStatus } } diff --git a/iosApp/iosApp/Documents/DocumentFormView.swift b/iosApp/iosApp/Documents/DocumentFormView.swift index ba221bb..7921716 100644 --- a/iosApp/iosApp/Documents/DocumentFormView.swift +++ b/iosApp/iosApp/Documents/DocumentFormView.swift @@ -115,47 +115,47 @@ struct DocumentFormView: View { private var warrantySection: some View { if isWarranty { Section { - TextField("Item Name", text: $itemName) + TextField(L10n.Documents.itemName, text: $itemName) if !itemNameError.isEmpty { Text(itemNameError) .font(.caption) .foregroundColor(Color.appError) } - TextField("Model Number (optional)", text: $modelNumber) - TextField("Serial Number (optional)", text: $serialNumber) + TextField(L10n.Documents.modelNumberOptional, text: $modelNumber) + TextField(L10n.Documents.serialNumberOptional, text: $serialNumber) - TextField("Provider/Company", text: $provider) + TextField(L10n.Documents.providerCompany, text: $provider) if !providerError.isEmpty { Text(providerError) .font(.caption) .foregroundColor(Color.appError) } - TextField("Provider Contact (optional)", text: $providerContact) + TextField(L10n.Documents.providerContactOptional, text: $providerContact) } header: { - Text("Warranty Details") + Text(L10n.Documents.warrantyDetails) } footer: { - Text("Required for warranties: Item Name and Provider") + Text(L10n.Documents.requiredWarrantyFields) .font(.caption) .foregroundColor(Color.appError) } .listRowBackground(Color.appBackgroundSecondary) - Section("Warranty Claims") { - TextField("Claim Phone (optional)", text: $claimPhone) + Section(L10n.Documents.warrantyClaims) { + TextField(L10n.Documents.claimPhoneOptional, text: $claimPhone) .keyboardType(.phonePad) - TextField("Claim Email (optional)", text: $claimEmail) + TextField(L10n.Documents.claimEmailOptional, text: $claimEmail) .keyboardType(.emailAddress) - TextField("Claim Website (optional)", text: $claimWebsite) + TextField(L10n.Documents.claimWebsiteOptional, text: $claimWebsite) .keyboardType(.URL) } .listRowBackground(Color.appBackgroundSecondary) - Section("Warranty Dates") { - TextField("Purchase Date (YYYY-MM-DD)", text: $purchaseDate) - TextField("Warranty Start Date (YYYY-MM-DD)", text: $startDate) - TextField("Warranty End Date (YYYY-MM-DD)", text: $endDate) + Section(L10n.Documents.warrantyDates) { + TextField(L10n.Documents.purchaseDate, text: $purchaseDate) + TextField(L10n.Documents.startDate, text: $startDate) + TextField(L10n.Documents.endDate, text: $endDate) } .listRowBackground(Color.appBackgroundSecondary) } @@ -164,7 +164,7 @@ struct DocumentFormView: View { @ViewBuilder private var photosSections: some View { if isEditMode && !existingImages.isEmpty { - Section("Existing Photos") { + Section(L10n.Documents.existingPhotos) { ForEach(existingImages, id: \.id) { image in AsyncImage(url: URL(string: image.imageUrl)) { phase in switch phase { @@ -187,19 +187,19 @@ struct DocumentFormView: View { .listRowBackground(Color.appBackgroundSecondary) } - Section("Photos") { + Section(L10n.Documents.photos) { PhotosPicker(selection: $selectedPhotoItems, maxSelectionCount: isEditMode ? 10 : 5, matching: .images) { - Label("Select from Library", systemImage: "photo") + Label(L10n.Documents.selectFromLibrary, systemImage: "photo") } Button { showCamera = true } label: { - Label("Take Photo", systemImage: "camera") + Label(L10n.Documents.takePhoto, systemImage: "camera") } if !selectedImages.isEmpty { - Text("\(selectedImages.count) photo(s) selected") + Text(String(format: L10n.Documents.photosSelected, selectedImages.count)) .font(.caption) .foregroundColor(.secondary) } @@ -215,11 +215,11 @@ struct DocumentFormView: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle(isEditMode ? (isWarranty ? "Edit Warranty" : "Edit Document") : (isWarranty ? "Add Warranty" : "Add Document")) + .navigationTitle(isEditMode ? (isWarranty ? L10n.Documents.editWarranty : L10n.Documents.editDocument) : (isWarranty ? L10n.Documents.addWarranty : L10n.Documents.addDocument)) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Cancel") { + Button(L10n.Common.cancel) { if isEditMode { dismiss() } else { @@ -229,7 +229,7 @@ struct DocumentFormView: View { } ToolbarItem(placement: .confirmationAction) { - Button(isEditMode ? "Update" : "Save") { + Button(isEditMode ? L10n.Documents.update : L10n.Common.save) { submitForm() } .disabled(!canSave || isProcessing) @@ -264,8 +264,8 @@ struct DocumentFormView: View { existingImages = doc.images } } - .alert("Error", isPresented: $showAlert) { - Button("OK", role: .cancel) {} + .alert(L10n.Common.error, isPresented: $showAlert) { + Button(L10n.Common.ok, role: .cancel) {} } message: { Text(alertMessage) } @@ -280,8 +280,8 @@ struct DocumentFormView: View { if residenceViewModel.isLoading { ProgressView() } else { - Picker("Select Property", selection: $selectedResidenceId) { - Text("Select Property").tag(nil as Int?) + Picker(L10n.Documents.selectProperty, selection: $selectedResidenceId) { + Text(L10n.Documents.selectProperty).tag(nil as Int?) ForEach(residencesArray, id: \.id) { residence in Text(residence.name).tag(residence.id as Int?) } @@ -294,9 +294,9 @@ struct DocumentFormView: View { } } } header: { - Text("Property") + Text(L10n.Documents.property) } footer: { - Text("Required") + Text(L10n.Documents.required) .font(.caption) .foregroundColor(Color.appError) } @@ -307,16 +307,16 @@ struct DocumentFormView: View { Section { if isEditMode { HStack { - Text("Document Type") + Text(L10n.Documents.documentType) Spacer() Text(DocumentTypeHelper.displayName(for: selectedDocumentType)) .foregroundColor(.secondary) } - Text("Document type cannot be changed") + Text(L10n.Documents.documentTypeCannotChange) .font(.caption) .foregroundColor(.secondary) } else { - Picker("Document Type", selection: $selectedDocumentType) { + Picker(L10n.Documents.documentType, selection: $selectedDocumentType) { ForEach(DocumentTypeHelper.allTypes, id: \.self) { type in Text(DocumentTypeHelper.displayName(for: type)).tag(type) } @@ -327,19 +327,19 @@ struct DocumentFormView: View { // Basic Information Section { - TextField("Title", text: $title) + TextField(L10n.Documents.titleField, text: $title) if !titleError.isEmpty { Text(titleError) .font(.caption) .foregroundColor(Color.appError) } - TextField("Description (optional)", text: $description, axis: .vertical) + TextField(L10n.Documents.descriptionOptional, text: $description, axis: .vertical) .lineLimit(3...6) } header: { - Text("Basic Information") + Text(L10n.Documents.basicInformation) } footer: { - Text("Required: Title") + Text(L10n.Documents.requiredTitle) .font(.caption) .foregroundColor(Color.appError) } @@ -350,9 +350,9 @@ struct DocumentFormView: View { // Category if isWarranty || ["inspection", "manual", "receipt"].contains(selectedDocumentType) { - Section("Category") { - Picker("Category (optional)", selection: $selectedCategory) { - Text("None").tag(nil as String?) + Section(L10n.Documents.category) { + Picker(L10n.Documents.categoryOptional, selection: $selectedCategory) { + Text(L10n.Documents.none).tag(nil as String?) ForEach(DocumentCategoryHelper.allCategories, id: \.self) { category in Text(DocumentCategoryHelper.displayName(for: category)).tag(category as String?) } @@ -362,10 +362,10 @@ struct DocumentFormView: View { } // Additional Information - Section("Additional Information") { - TextField("Tags (optional)", text: $tags) + Section(L10n.Documents.additionalInformation) { + TextField(L10n.Documents.tagsOptional, text: $tags) .textInputAutocapitalization(.never) - TextField("Notes (optional)", text: $notes, axis: .vertical) + TextField(L10n.Documents.notesOptional, text: $notes, axis: .vertical) .lineLimit(3...6) } .listRowBackground(Color.appBackgroundSecondary) @@ -373,7 +373,7 @@ struct DocumentFormView: View { // Active Status (Edit mode only) if isEditMode { Section { - Toggle("Active", isOn: $isActive) + Toggle(L10n.Documents.active, isOn: $isActive) } .listRowBackground(Color.appBackgroundSecondary) } @@ -391,22 +391,22 @@ struct DocumentFormView: View { residenceError = "" if title.isEmpty { - titleError = "Title is required" + titleError = L10n.Documents.titleRequired isValid = false } if needsResidenceSelection && selectedResidenceId == nil { - residenceError = "Property is required" + residenceError = L10n.Documents.propertyRequired isValid = false } if isWarranty { if itemName.isEmpty { - itemNameError = "Item name is required for warranties" + itemNameError = L10n.Documents.itemNameRequired isValid = false } if provider.isEmpty { - providerError = "Provider is required for warranties" + providerError = L10n.Documents.providerRequired isValid = false } } @@ -416,7 +416,7 @@ struct DocumentFormView: View { private func submitForm() { guard validateForm() else { - alertMessage = "Please fill in all required fields" + alertMessage = L10n.Documents.fillRequiredFields showAlert = true return } @@ -432,7 +432,7 @@ struct DocumentFormView: View { actualResidenceId = Int32(selectedId) } else { isProcessing = false - alertMessage = "No residence selected" + alertMessage = L10n.Documents.noResidenceSelected showAlert = true return } @@ -441,7 +441,7 @@ struct DocumentFormView: View { // Update document guard let docId = doc.id else { isProcessing = false - alertMessage = "Document ID is missing" + alertMessage = L10n.Documents.documentIdMissing showAlert = true return } @@ -474,7 +474,7 @@ struct DocumentFormView: View { documentViewModel.loadDocuments(residenceId: residenceId) dismiss() } else { - alertMessage = error ?? "Failed to update document" + alertMessage = error ?? L10n.Documents.failedToUpdate showAlert = true } } @@ -509,7 +509,7 @@ struct DocumentFormView: View { documentViewModel.loadDocuments(residenceId: actualResidenceId) isPresented = false } else { - alertMessage = error ?? "Failed to create document" + alertMessage = error ?? L10n.Documents.failedToCreate showAlert = true } } diff --git a/iosApp/iosApp/Documents/DocumentsWarrantiesView.swift b/iosApp/iosApp/Documents/DocumentsWarrantiesView.swift index d9a4b0e..17fdd8e 100644 --- a/iosApp/iosApp/Documents/DocumentsWarrantiesView.swift +++ b/iosApp/iosApp/Documents/DocumentsWarrantiesView.swift @@ -40,9 +40,9 @@ struct DocumentsWarrantiesView: View { VStack(spacing: 0) { // Segmented Control for Tabs Picker("", selection: $selectedTab) { - Label("Warranties", systemImage: "checkmark.shield") + Label(L10n.Documents.warranties, systemImage: "checkmark.shield") .tag(DocumentWarrantyTab.warranties) - Label("Documents", systemImage: "doc.text") + Label(L10n.Documents.documents, systemImage: "doc.text") .tag(DocumentWarrantyTab.documents) } .pickerStyle(SegmentedPickerStyle()) @@ -50,7 +50,7 @@ struct DocumentsWarrantiesView: View { .padding(.top, AppSpacing.sm) // Search Bar - SearchBar(text: $searchText, placeholder: "Search...") + SearchBar(text: $searchText, placeholder: L10n.Documents.searchPlaceholder) .padding(.horizontal, AppSpacing.md) .padding(.top, AppSpacing.xs) @@ -60,7 +60,7 @@ struct DocumentsWarrantiesView: View { HStack(spacing: AppSpacing.xs) { if selectedTab == .warranties && showActiveOnly { FilterChip( - title: "Active Only", + title: L10n.Documents.activeOnly, icon: "checkmark.circle.fill", onRemove: { showActiveOnly = false } ) @@ -99,7 +99,7 @@ struct DocumentsWarrantiesView: View { } } } - .navigationTitle("Documents & Warranties") + .navigationTitle(L10n.Documents.documentsAndWarranties) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { @@ -122,7 +122,7 @@ struct DocumentsWarrantiesView: View { selectedCategory = nil loadWarranties() }) { - Label("All Categories", systemImage: selectedCategory == nil ? "checkmark" : "") + Label(L10n.Documents.allCategories, systemImage: selectedCategory == nil ? "checkmark" : "") } Divider() @@ -140,7 +140,7 @@ struct DocumentsWarrantiesView: View { selectedDocType = nil loadDocuments() }) { - Label("All Types", systemImage: selectedDocType == nil ? "checkmark" : "") + Label(L10n.Documents.allTypes, systemImage: selectedDocType == nil ? "checkmark" : "") } Divider() diff --git a/iosApp/iosApp/Helpers/L10n.swift b/iosApp/iosApp/Helpers/L10n.swift new file mode 100644 index 0000000..de92c3d --- /dev/null +++ b/iosApp/iosApp/Helpers/L10n.swift @@ -0,0 +1,577 @@ +import Foundation + +// MARK: - L10n - Type-safe Localized Strings +// Usage: L10n.auth.loginTitle + +enum L10n { + // MARK: - App + enum App { + static var name: String { String(localized: "app_name") } + static var tagline: String { String(localized: "app_tagline") } + } + + // MARK: - Auth + enum Auth { + // Login + static var loginTitle: String { String(localized: "auth_login_title") } + static var loginSubtitle: String { String(localized: "auth_login_subtitle") } + static var loginUsernameLabel: String { String(localized: "auth_login_username_label") } + static var loginPasswordLabel: String { String(localized: "auth_login_password_label") } + static var loginButton: String { String(localized: "auth_login_button") } + static var forgotPassword: String { String(localized: "auth_forgot_password") } + static var noAccount: String { String(localized: "auth_no_account") } + static var loginFailed: String { String(localized: "auth_login_failed") } + static var showPassword: String { String(localized: "auth_show_password") } + static var hidePassword: String { String(localized: "auth_hide_password") } + static var welcomeBack: String { String(localized: "auth_welcome_back") } + static var signInSubtitle: String { String(localized: "auth_sign_in_subtitle") } + static var enterEmail: String { String(localized: "auth_enter_email") } + static var enterPassword: String { String(localized: "auth_enter_password") } + static var signingIn: String { String(localized: "auth_signing_in") } + static var orDivider: String { String(localized: "auth_or_divider") } + static var signingInWithApple: String { String(localized: "auth_signing_in_with_apple") } + static var dontHaveAccount: String { String(localized: "auth_dont_have_account") } + static var signUp: String { String(localized: "auth_sign_up") } + + // Register + static var registerTitle: String { String(localized: "auth_register_title") } + static var registerSubtitle: String { String(localized: "auth_register_subtitle") } + static var registerFirstName: String { String(localized: "auth_register_first_name") } + static var registerLastName: String { String(localized: "auth_register_last_name") } + static var registerEmail: String { String(localized: "auth_register_email") } + static var registerUsername: String { String(localized: "auth_register_username") } + static var registerPassword: String { String(localized: "auth_register_password") } + static var registerConfirmPassword: String { String(localized: "auth_register_confirm_password") } + static var registerButton: String { String(localized: "auth_register_button") } + static var haveAccount: String { String(localized: "auth_have_account") } + static var passwordsDontMatch: String { String(localized: "auth_passwords_dont_match") } + static var joinCasera: String { String(localized: "auth_join_casera") } + static var startManaging: String { String(localized: "auth_start_managing") } + static var accountInfo: String { String(localized: "auth_account_info") } + static var security: String { String(localized: "auth_security") } + static var passwordSuggestion: String { String(localized: "auth_password_suggestion") } + + // Verify Email + static var verifyTitle: String { String(localized: "auth_verify_title") } + static var verifySubtitle: String { String(localized: "auth_verify_subtitle") } + static var verifyCodeLabel: String { String(localized: "auth_verify_code_label") } + static var verifyButton: String { String(localized: "auth_verify_button") } + static var verifyResend: String { String(localized: "auth_verify_resend") } + static var verifySuccess: String { String(localized: "auth_verify_success") } + static var verifyYourEmail: String { String(localized: "auth_verify_your_email") } + static var verifyMustVerify: String { String(localized: "auth_verify_must_verify") } + static var verifyCheckInbox: String { String(localized: "auth_verify_check_inbox") } + static var verifyCodeMustBe6: String { String(localized: "auth_verify_code_must_be_6") } + static var verifyEmailButton: String { String(localized: "auth_verify_email_button") } + static var verifyHelpText: String { String(localized: "auth_verify_help_text") } + static var logout: String { String(localized: "auth_logout") } + + // Forgot Password + static var forgotTitle: String { String(localized: "auth_forgot_title") } + static var forgotSubtitle: String { String(localized: "auth_forgot_subtitle") } + static var forgotEmailLabel: String { String(localized: "auth_forgot_email_label") } + static var forgotButton: String { String(localized: "auth_forgot_button") } + static var forgotSuccess: String { String(localized: "auth_forgot_success") } + + // Reset Password + static var resetTitle: String { String(localized: "auth_reset_title") } + static var resetSubtitle: String { String(localized: "auth_reset_subtitle") } + static var resetCodeLabel: String { String(localized: "auth_reset_code_label") } + static var resetNewPassword: String { String(localized: "auth_reset_new_password") } + static var resetConfirmPassword: String { String(localized: "auth_reset_confirm_password") } + static var resetButton: String { String(localized: "auth_reset_button") } + static var resetSuccess: String { String(localized: "auth_reset_success") } + } + + // MARK: - Properties + enum Properties { + static var title: String { String(localized: "properties_title") } + static var emptyTitle: String { String(localized: "properties_empty_title") } + static var emptySubtitle: String { String(localized: "properties_empty_subtitle") } + static var addButton: String { String(localized: "properties_add_button") } + static var addTitle: String { String(localized: "properties_add_title") } + static var editTitle: String { String(localized: "properties_edit_title") } + static var nameLabel: String { String(localized: "properties_name_label") } + static var addressLabel: String { String(localized: "properties_address_label") } + static var typeLabel: String { String(localized: "properties_type_label") } + static var notesLabel: String { String(localized: "properties_notes_label") } + static var deleteConfirm: String { String(localized: "properties_delete_confirm") } + static var deleted: String { String(localized: "properties_deleted") } + } + + // MARK: - Residences + enum Residences { + // List + static var title: String { String(localized: "residences_title") } + static var yourProperties: String { String(localized: "residences_your_properties") } + static var property: String { String(localized: "residences_property") } + static var properties: String { String(localized: "residences_properties") } + + // Form + static var addTitle: String { String(localized: "residences_add_title") } + static var editTitle: String { String(localized: "residences_edit_title") } + static var propertyName: String { String(localized: "residences_property_name") } + static var propertyType: String { String(localized: "residences_property_type") } + static var selectType: String { String(localized: "residences_select_type") } + static var propertyDetails: String { String(localized: "residences_property_details") } + static var requiredName: String { String(localized: "residences_required_name") } + static var nameRequired: String { String(localized: "residences_name_required") } + + // Address + static var address: String { String(localized: "residences_address") } + static var streetAddress: String { String(localized: "residences_street_address") } + static var apartmentUnit: String { String(localized: "residences_apartment_unit") } + static var city: String { String(localized: "residences_city") } + static var stateProvince: String { String(localized: "residences_state_province") } + static var postalCode: String { String(localized: "residences_postal_code") } + static var country: String { String(localized: "residences_country") } + + // Features + static var propertyFeatures: String { String(localized: "residences_property_features") } + static var bedrooms: String { String(localized: "residences_bedrooms") } + static var bathrooms: String { String(localized: "residences_bathrooms") } + static var squareFootage: String { String(localized: "residences_square_footage") } + static var lotSize: String { String(localized: "residences_lot_size") } + static var yearBuilt: String { String(localized: "residences_year_built") } + + // Additional + static var additionalDetails: String { String(localized: "residences_additional_details") } + static var description: String { String(localized: "residences_description") } + static var primaryResidence: String { String(localized: "residences_primary_residence") } + + // Detail + static var loadingResidence: String { String(localized: "residences_loading_residence") } + static var generateReport: String { String(localized: "residences_generate_report") } + static var generateReportMessage: String { String(localized: "residences_generate_report_message") } + static var maintenanceReport: String { String(localized: "residences_maintenance_report") } + static var contractors: String { String(localized: "residences_contractors") } + static var noContractors: String { String(localized: "residences_no_contractors") } + static var addContractorsPrompt: String { String(localized: "residences_add_contractors_prompt") } + static var loadingTasks: String { String(localized: "residences_loading_tasks") } + static var errorLoadingTasks: String { String(localized: "residences_error_loading_tasks") } + static var generate: String { String(localized: "residences_generate") } + + // Delete + static var deleteTitle: String { String(localized: "residences_delete_title") } + static var deleteConfirmMessage: String { String(localized: "residences_delete_confirm_message") } + + // Join + static var joinTitle: String { String(localized: "residences_join_title") } + static var shareCode: String { String(localized: "residences_share_code") } + static var enterShareCode: String { String(localized: "residences_enter_share_code") } + static var shareCodeFooter: String { String(localized: "residences_share_code_footer") } + static var joinButton: String { String(localized: "residences_join_button") } + static var shareCodeMust6: String { String(localized: "residences_share_code_must_6") } + + // Manage Users + static var manageUsers: String { String(localized: "residences_manage_users") } + static var users: String { String(localized: "residences_users") } + } + + // MARK: - Tasks + enum Tasks { + static var title: String { String(localized: "tasks_title") } + static var emptyTitle: String { String(localized: "tasks_empty_title") } + static var emptySubtitle: String { String(localized: "tasks_empty_subtitle") } + static var addButton: String { String(localized: "tasks_add_button") } + static var addTitle: String { String(localized: "tasks_add_title") } + static var editTitle: String { String(localized: "tasks_edit_title") } + static var titleLabel: String { String(localized: "tasks_title_label") } + static var descriptionLabel: String { String(localized: "tasks_description_label") } + static var deleteConfirm: String { String(localized: "tasks_delete_confirm") } + + // Form Fields + static var property: String { String(localized: "tasks_property") } + static var selectProperty: String { String(localized: "tasks_select_property") } + static var required: String { String(localized: "tasks_required") } + static var taskDetails: String { String(localized: "tasks_task_details") } + static var titleRequired: String { String(localized: "tasks_title_required") } + static var descriptionOptional: String { String(localized: "tasks_description_optional") } + static var category: String { String(localized: "tasks_category") } + static var selectCategory: String { String(localized: "tasks_select_category") } + static var scheduling: String { String(localized: "tasks_scheduling") } + static var frequency: String { String(localized: "tasks_frequency") } + static var selectFrequency: String { String(localized: "tasks_select_frequency") } + static var customInterval: String { String(localized: "tasks_custom_interval") } + static var dueDate: String { String(localized: "tasks_due_date") } + static var priorityAndStatus: String { String(localized: "tasks_priority_status") } + static var priority: String { String(localized: "tasks_priority") } + static var selectPriority: String { String(localized: "tasks_select_priority") } + static var status: String { String(localized: "tasks_status") } + static var selectStatus: String { String(localized: "tasks_select_status") } + static var bothRequired: String { String(localized: "tasks_both_required") } + static var cost: String { String(localized: "tasks_cost") } + static var estimatedCost: String { String(localized: "tasks_estimated_cost") } + static var loading: String { String(localized: "tasks_loading") } + + // All Tasks View + static var allTasks: String { String(localized: "tasks_all_tasks") } + static var noTasksYet: String { String(localized: "tasks_no_tasks_yet") } + static var createFirst: String { String(localized: "tasks_create_first") } + static var addPropertyFirst: String { String(localized: "tasks_add_property_first") } + static var archiveTask: String { String(localized: "tasks_archive_task") } + static var deleteTask: String { String(localized: "tasks_delete_task") } + static var archiveConfirm: String { String(localized: "tasks_archive_confirm") } + static var archive: String { String(localized: "tasks_archive") } + static var noTasks: String { String(localized: "tasks_no_tasks") } + + // Complete Task View + static var completeTask: String { String(localized: "tasks_complete_task") } + static var selectContractor: String { String(localized: "tasks_select_contractor") } + static var contractorOptional: String { String(localized: "tasks_contractor_optional") } + static var contractorHelper: String { String(localized: "tasks_contractor_helper") } + static var completedBy: String { String(localized: "tasks_completed_by") } + static var yourName: String { String(localized: "tasks_your_name") } + static var actualCost: String { String(localized: "tasks_actual_cost") } + static var optionalInfo: String { String(localized: "tasks_optional_info") } + static var optionalDetails: String { String(localized: "tasks_optional_details") } + static var notes: String { String(localized: "tasks_notes") } + static var optionalNotes: String { String(localized: "tasks_optional_notes") } + static var qualityRating: String { String(localized: "tasks_quality_rating") } + static var rateQuality: String { String(localized: "tasks_rate_quality") } + static var photos: String { String(localized: "tasks_photos") } + static var addPhotos: String { String(localized: "tasks_add_photos") } + static var takePhoto: String { String(localized: "tasks_take_photo") } + static var library: String { String(localized: "tasks_library") } + static var none: String { String(localized: "tasks_none") } + static var noneManual: String { String(localized: "tasks_none_manual") } + static var enterManually: String { String(localized: "tasks_enter_manually") } + static var error: String { String(localized: "tasks_error") } + + // Completion History + static var completionHistory: String { String(localized: "tasks_completion_history") } + static var loadingCompletions: String { String(localized: "tasks_loading_completions") } + static var failedToLoad: String { String(localized: "tasks_failed_to_load") } + static var noCompletionsYet: String { String(localized: "tasks_no_completions_yet") } + static var notCompleted: String { String(localized: "tasks_not_completed") } + static var completions: String { String(localized: "tasks_completions") } + static var completion: String { String(localized: "tasks_completion") } + static var completedByName: String { String(localized: "tasks_completed_by_name") } + static var viewPhotos: String { String(localized: "tasks_view_photos") } + + // Task Card Actions + static var inProgress: String { String(localized: "tasks_in_progress") } + static var complete: String { String(localized: "tasks_complete") } + static var edit: String { String(localized: "tasks_edit") } + static var cancel: String { String(localized: "tasks_cancel") } + static var restore: String { String(localized: "tasks_restore") } + static var unarchive: String { String(localized: "tasks_unarchive") } + } + + // MARK: - Contractors + enum Contractors { + static var title: String { String(localized: "contractors_title") } + static var emptyTitle: String { String(localized: "contractors_empty_title") } + static var emptySubtitle: String { String(localized: "contractors_empty_subtitle") } + static var emptyNoFilters: String { String(localized: "contractors_empty_no_filters") } + static var emptyFiltered: String { String(localized: "contractors_empty_filtered") } + static var addButton: String { String(localized: "contractors_add_button") } + static var addTitle: String { String(localized: "contractors_add_title") } + static var editTitle: String { String(localized: "contractors_edit_title") } + + // Search & Filter + static var searchPlaceholder: String { String(localized: "contractors_search_placeholder") } + static var favorites: String { String(localized: "contractors_favorites") } + static var allSpecialties: String { String(localized: "contractors_all_specialties") } + + // Form Fields + static var nameLabel: String { String(localized: "contractors_name_label") } + static var companyLabel: String { String(localized: "contractors_company_label") } + static var phoneLabel: String { String(localized: "contractors_phone_label") } + static var emailLabel: String { String(localized: "contractors_email_label") } + static var websiteLabel: String { String(localized: "contractors_website_label") } + static var streetAddressLabel: String { String(localized: "contractors_street_address_label") } + static var cityLabel: String { String(localized: "contractors_city_label") } + static var stateLabel: String { String(localized: "contractors_state_label") } + static var zipLabel: String { String(localized: "contractors_zip_label") } + static var notesLabel: String { String(localized: "contractors_notes_label") } + + // Form Sections + static var basicInfoSection: String { String(localized: "contractors_basic_info_section") } + static var basicInfoFooter: String { String(localized: "contractors_basic_info_footer") } + static var residenceSection: String { String(localized: "contractors_residence_section") } + static var residenceFooterPersonal: String { String(localized: "contractors_residence_footer_personal") } + static var residenceFooterShared: String { String(localized: "contractors_residence_footer_shared") } + static var contactInfoSection: String { String(localized: "contractors_contact_info_section") } + static var specialtiesSection: String { String(localized: "contractors_specialties_section") } + static var addressSection: String { String(localized: "contractors_address_section") } + static var notesSection: String { String(localized: "contractors_notes_section") } + static var notesFooter: String { String(localized: "contractors_notes_footer") } + static var favoriteLabel: String { String(localized: "contractors_favorite_label") } + + // Detail View + static var removeFromFavorites: String { String(localized: "contractors_remove_from_favorites") } + static var addToFavorites: String { String(localized: "contractors_add_to_favorites") } + static var deleteConfirm: String { String(localized: "contractors_delete_confirm") } + static var deleteMessage: String { String(localized: "contractors_delete_message") } + static var completedTasks: String { String(localized: "contractors_completed_tasks") } + static var callAction: String { String(localized: "contractors_call_action") } + static var emailAction: String { String(localized: "contractors_email_action") } + static var websiteAction: String { String(localized: "contractors_website_action") } + static var directionsAction: String { String(localized: "contractors_directions_action") } + static var locationLabel: String { String(localized: "contractors_location_label") } + static var propertyLabel: String { String(localized: "contractors_property_label") } + static var associatedPropertySection: String { String(localized: "contractors_associated_property_section") } + static var statisticsSection: String { String(localized: "contractors_statistics_section") } + static var tasksCompletedLabel: String { String(localized: "contractors_tasks_completed_label") } + static var averageRatingLabel: String { String(localized: "contractors_average_rating_label") } + static var infoSection: String { String(localized: "contractors_info_section") } + static var addedByLabel: String { String(localized: "contractors_added_by_label") } + static var memberSinceLabel: String { String(localized: "contractors_member_since_label") } + + // Picker Sheets + static var selectResidence: String { String(localized: "contractors_select_residence") } + static var personalNoResidence: String { String(localized: "contractors_personal_no_residence") } + static var selectSpecialties: String { String(localized: "contractors_select_specialties") } + static var selectSpecialtiesPlaceholder: String { String(localized: "contractors_select_specialties_placeholder") } + static var clearAction: String { String(localized: "contractors_clear_action") } + + // Stats + static var tasksLabel: String { String(localized: "contractors_tasks_label") } + } + + // MARK: - Documents + enum Documents { + // Main view + static var title: String { String(localized: "documents_title") } + static var documentsAndWarranties: String { String(localized: "documents_and_warranties") } + static var warranties: String { String(localized: "documents_warranties") } + static var documents: String { String(localized: "documents_documents") } + static var searchPlaceholder: String { String(localized: "documents_search_placeholder") } + + // Filters + static var activeOnly: String { String(localized: "documents_active_only") } + static var allCategories: String { String(localized: "documents_all_categories") } + static var allTypes: String { String(localized: "documents_all_types") } + + // Empty states + static var emptyTitle: String { String(localized: "documents_empty_title") } + static var emptySubtitle: String { String(localized: "documents_empty_subtitle") } + static var noDocumentsFound: String { String(localized: "documents_no_documents_found") } + static var noDocumentsMessage: String { String(localized: "documents_no_documents_message") } + static var noWarrantiesFound: String { String(localized: "documents_no_warranties_found") } + static var noWarrantiesMessage: String { String(localized: "documents_no_warranties_message") } + + // Actions + static var addButton: String { String(localized: "documents_add_button") } + + // Form titles + static var addWarranty: String { String(localized: "documents_add_warranty") } + static var addDocument: String { String(localized: "documents_add_document") } + static var editWarranty: String { String(localized: "documents_edit_warranty") } + static var editDocument: String { String(localized: "documents_edit_document") } + + // Form sections + static var property: String { String(localized: "documents_property") } + static var selectProperty: String { String(localized: "documents_select_property") } + static var documentType: String { String(localized: "documents_document_type") } + static var documentTypeCannotChange: String { String(localized: "documents_document_type_cannot_change") } + static var basicInformation: String { String(localized: "documents_basic_information") } + static var warrantyDetails: String { String(localized: "documents_warranty_details") } + static var warrantyClaims: String { String(localized: "documents_warranty_claims") } + static var warrantyDates: String { String(localized: "documents_warranty_dates") } + static var category: String { String(localized: "documents_category") } + static var additionalInformation: String { String(localized: "documents_additional_information") } + static var active: String { String(localized: "documents_active") } + static var photos: String { String(localized: "documents_photos") } + static var existingPhotos: String { String(localized: "documents_existing_photos") } + + // Form fields + static var titleField: String { String(localized: "documents_title_field") } + static var description: String { String(localized: "documents_description") } + static var descriptionOptional: String { String(localized: "documents_description_optional") } + static var itemName: String { String(localized: "documents_item_name") } + static var modelNumber: String { String(localized: "documents_model_number") } + static var modelNumberOptional: String { String(localized: "documents_model_number_optional") } + static var serialNumber: String { String(localized: "documents_serial_number") } + static var serialNumberOptional: String { String(localized: "documents_serial_number_optional") } + static var provider: String { String(localized: "documents_provider") } + static var providerCompany: String { String(localized: "documents_provider_company") } + static var providerContact: String { String(localized: "documents_provider_contact") } + static var providerContactOptional: String { String(localized: "documents_provider_contact_optional") } + static var claimPhone: String { String(localized: "documents_claim_phone") } + static var claimPhoneOptional: String { String(localized: "documents_claim_phone_optional") } + static var claimEmail: String { String(localized: "documents_claim_email") } + static var claimEmailOptional: String { String(localized: "documents_claim_email_optional") } + static var claimWebsite: String { String(localized: "documents_claim_website") } + static var claimWebsiteOptional: String { String(localized: "documents_claim_website_optional") } + static var purchaseDate: String { String(localized: "documents_purchase_date") } + static var startDate: String { String(localized: "documents_start_date") } + static var endDate: String { String(localized: "documents_end_date") } + static var tags: String { String(localized: "documents_tags") } + static var tagsOptional: String { String(localized: "documents_tags_optional") } + static var notes: String { String(localized: "documents_notes") } + static var notesOptional: String { String(localized: "documents_notes_optional") } + static var categoryOptional: String { String(localized: "documents_category_optional") } + + // Form footer messages + static var required: String { String(localized: "documents_required") } + static var requiredTitle: String { String(localized: "documents_required_title") } + static var requiredWarrantyFields: String { String(localized: "documents_required_warranty_fields") } + + // Photo actions + static var selectFromLibrary: String { String(localized: "documents_select_from_library") } + static var takePhoto: String { String(localized: "documents_take_photo") } + static var photosSelected: String { String(localized: "documents_photos_selected") } + + // Detail view + static var documentDetails: String { String(localized: "documents_document_details") } + static var loadingDocument: String { String(localized: "documents_loading_document") } + static var status: String { String(localized: "documents_status") } + static var daysRemaining: String { String(localized: "documents_days_remaining") } + static var itemDetails: String { String(localized: "documents_item_details") } + static var claimInformation: String { String(localized: "documents_claim_information") } + static var importantDates: String { String(localized: "documents_important_dates") } + static var images: String { String(localized: "documents_images") } + static var associations: String { String(localized: "documents_associations") } + static var residence: String { String(localized: "documents_residence") } + static var contractor: String { String(localized: "documents_contractor") } + static var contractorPhone: String { String(localized: "documents_contractor_phone") } + static var attachedFile: String { String(localized: "documents_attached_file") } + static var fileType: String { String(localized: "documents_file_type") } + static var fileSize: String { String(localized: "documents_file_size") } + static var downloadFile: String { String(localized: "documents_download_file") } + static var metadata: String { String(localized: "documents_metadata") } + static var uploadedBy: String { String(localized: "documents_uploaded_by") } + static var created: String { String(localized: "documents_created") } + static var updated: String { String(localized: "documents_updated") } + + // Warranty statuses + static var inactive: String { String(localized: "documents_inactive") } + static var expired: String { String(localized: "documents_expired") } + static var expiringSoon: String { String(localized: "documents_expiring_soon") } + static var activeStatus: String { String(localized: "documents_active_status") } + + // Warranty card + static var expires: String { String(localized: "documents_expires") } + static var daysRemainingCount: String { String(localized: "documents_days_remaining_count") } + + // Delete + static var deleteDocument: String { String(localized: "documents_delete_document") } + static var deleteConfirmMessage: String { String(localized: "documents_delete_confirm_message") } + + // Validation errors + static var titleRequired: String { String(localized: "documents_title_required") } + static var propertyRequired: String { String(localized: "documents_property_required") } + static var itemNameRequired: String { String(localized: "documents_item_name_required") } + static var providerRequired: String { String(localized: "documents_provider_required") } + static var fillRequiredFields: String { String(localized: "documents_fill_required_fields") } + static var noResidenceSelected: String { String(localized: "documents_no_residence_selected") } + static var documentIdMissing: String { String(localized: "documents_document_id_missing") } + static var failedToUpdate: String { String(localized: "documents_failed_to_update") } + static var failedToCreate: String { String(localized: "documents_failed_to_create") } + + // Document type names + static var typeWarranty: String { String(localized: "documents_type_warranty") } + static var typeManual: String { String(localized: "documents_type_manual") } + static var typeReceipt: String { String(localized: "documents_type_receipt") } + static var typeInspection: String { String(localized: "documents_type_inspection") } + static var typePermit: String { String(localized: "documents_type_permit") } + static var typeDeed: String { String(localized: "documents_type_deed") } + static var typeInsurance: String { String(localized: "documents_type_insurance") } + static var typeContract: String { String(localized: "documents_type_contract") } + static var typePhoto: String { String(localized: "documents_type_photo") } + static var typeOther: String { String(localized: "documents_type_other") } + static var typeUnknown: String { String(localized: "documents_type_unknown") } + + // Category names + static var categoryAppliance: String { String(localized: "documents_category_appliance") } + static var categoryHvac: String { String(localized: "documents_category_hvac") } + static var categoryPlumbing: String { String(localized: "documents_category_plumbing") } + static var categoryElectrical: String { String(localized: "documents_category_electrical") } + static var categoryRoofing: String { String(localized: "documents_category_roofing") } + static var categoryStructural: String { String(localized: "documents_category_structural") } + static var categoryOther: String { String(localized: "documents_category_other") } + static var categoryUnknown: String { String(localized: "documents_category_unknown") } + + // Common labels + static var none: String { String(localized: "documents_none") } + static var na: String { String(localized: "documents_na") } + static var update: String { String(localized: "documents_update") } + } + + // MARK: - Profile + enum Profile { + static var title: String { String(localized: "profile_title") } + static var logout: String { String(localized: "profile_logout") } + static var logoutConfirm: String { String(localized: "profile_logout_confirm") } + static var loadingProfile: String { String(localized: "profile_loading_profile") } + static var profileSettings: String { String(localized: "profile_profile_settings") } + static var firstName: String { String(localized: "profile_first_name") } + static var lastName: String { String(localized: "profile_last_name") } + static var personalInformation: String { String(localized: "profile_personal_information") } + static var email: String { String(localized: "profile_email") } + static var contact: String { String(localized: "profile_contact") } + static var emailRequiredUnique: String { String(localized: "profile_email_required_unique") } + static var saveChanges: String { String(localized: "profile_save_changes") } + static var editProfile: String { String(localized: "profile_edit_profile") } + static var account: String { String(localized: "profile_account") } + static var notifications: String { String(localized: "profile_notifications") } + static var privacy: String { String(localized: "profile_privacy") } + static var subscription: String { String(localized: "profile_subscription") } + static var proPlan: String { String(localized: "profile_pro_plan") } + static var freePlan: String { String(localized: "profile_free_plan") } + static var activeUntil: String { String(localized: "profile_active_until") } + static var limitedFeatures: String { String(localized: "profile_limited_features") } + static var upgradeToPro: String { String(localized: "profile_upgrade_to_pro") } + static var manageSubscription: String { String(localized: "profile_manage_subscription") } + static var restorePurchases: String { String(localized: "profile_restore_purchases") } + static var appearance: String { String(localized: "profile_appearance") } + static var theme: String { String(localized: "profile_theme") } + static var appName: String { String(localized: "profile_app_name") } + static var version: String { String(localized: "profile_version") } + static var purchasesRestored: String { String(localized: "profile_purchases_restored") } + static var purchasesRestoredMessage: String { String(localized: "profile_purchases_restored_message") } + + // Notification Preferences + static var notificationPreferences: String { String(localized: "profile_notification_preferences") } + static var notificationPreferencesSubtitle: String { String(localized: "profile_notification_preferences_subtitle") } + static var taskDueSoon: String { String(localized: "profile_task_due_soon") } + static var taskDueSoonDescription: String { String(localized: "profile_task_due_soon_description") } + static var taskOverdue: String { String(localized: "profile_task_overdue") } + static var taskOverdueDescription: String { String(localized: "profile_task_overdue_description") } + static var taskCompleted: String { String(localized: "profile_task_completed") } + static var taskCompletedDescription: String { String(localized: "profile_task_completed_description") } + static var taskAssigned: String { String(localized: "profile_task_assigned") } + static var taskAssignedDescription: String { String(localized: "profile_task_assigned_description") } + static var taskNotifications: String { String(localized: "profile_task_notifications") } + static var propertyShared: String { String(localized: "profile_property_shared") } + static var propertySharedDescription: String { String(localized: "profile_property_shared_description") } + static var warrantyExpiring: String { String(localized: "profile_warranty_expiring") } + static var warrantyExpiringDescription: String { String(localized: "profile_warranty_expiring_description") } + static var otherNotifications: String { String(localized: "profile_other_notifications") } + } + + // MARK: - Settings + enum Settings { + static var title: String { String(localized: "settings_title") } + static var language: String { String(localized: "settings_language") } + } + + // MARK: - Common + enum Common { + static var save: String { String(localized: "common_save") } + static var cancel: String { String(localized: "common_cancel") } + static var delete: String { String(localized: "common_delete") } + static var edit: String { String(localized: "common_edit") } + static var done: String { String(localized: "common_done") } + static var close: String { String(localized: "common_close") } + static var back: String { String(localized: "common_back") } + static var loading: String { String(localized: "common_loading") } + static var error: String { String(localized: "common_error") } + static var retry: String { String(localized: "common_retry") } + static var success: String { String(localized: "common_success") } + static var yes: String { String(localized: "common_yes") } + static var no: String { String(localized: "common_no") } + static var ok: String { String(localized: "common_ok") } + } + + // MARK: - Errors + enum Error { + static var generic: String { String(localized: "error_generic") } + static var network: String { String(localized: "error_network") } + static var unauthorized: String { String(localized: "error_unauthorized") } + static var notFound: String { String(localized: "error_not_found") } + static var requiredField: String { String(localized: "error_required_field") } + } +} diff --git a/iosApp/iosApp/Localizable.xcstrings b/iosApp/iosApp/Localizable.xcstrings new file mode 100644 index 0000000..3eddba6 --- /dev/null +++ b/iosApp/iosApp/Localizable.xcstrings @@ -0,0 +1,16033 @@ +{ + "sourceLanguage" : "en", + "strings" : { + "" : { + + }, + "%@" : { + + }, + "%@ (%lld)" : { + "comment" : "A heading that lists the number of users in a residence. The argument is the count of users.", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@ (%2$lld)" + } + } + } + }, + "%@ (%lld/5)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@ (%2$lld/5)" + } + } + } + }, + "%@ %@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@ %2$@" + } + } + } + }, + "%@, %@" : { + "comment" : "A city and state combination.", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@, %2$@" + } + } + } + }, + "%@, %@ %@" : { + "comment" : "A label displaying the city, state, and postal code of the residence.", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@, %2$@ %3$@" + } + } + } + }, + "%@: %@" : { + "comment" : "An error message displayed when there was an issue loading tasks for a residence.", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@: %2$@" + } + } + } + }, + "%d" : { + "comment" : "A badge displaying the number of tasks in a category. The argument is the count of tasks in the category.", + "isCommentAutoGenerated" : true + }, + "%d tasks" : { + "comment" : "A label showing the number of tasks a contractor has. The argument is the number of tasks.", + "isCommentAutoGenerated" : true + }, + "%lld / 5" : { + + }, + "%lld %@" : { + "comment" : "A text that shows the number of residences the user has.", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$lld %2$@" + } + } + } + }, + "+%lld" : { + + }, + "$" : { + + }, + "$%@" : { + "comment" : "A label displaying the cost of a task. The argument is the cost of the task.", + "isCommentAutoGenerated" : true + }, + "0" : { + + }, + "000000" : { + "comment" : "A placeholder text for a 6-digit code field.", + "isCommentAutoGenerated" : true + }, + "0.0" : { + + }, + "0.00" : { + + }, + "Actions" : { + "comment" : "A label for the actions menu in the task card.", + "isCommentAutoGenerated" : true + }, + "Add your first property to get started!" : { + "comment" : "A description below the image in the \"No properties yet\" view, encouraging the user to add their first property.", + "isCommentAutoGenerated" : true + }, + "app_name" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + } + } + }, + "app_tagline" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verwalten Sie Ihre Immobilien einfach" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manage your properties with ease" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Administra tus propiedades con facilidad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gérez vos propriétés facilement" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gerencie suas propriedades com facilidade" + } + } + } + }, + "Archive" : { + "comment" : "The text of a button that archives a task.", + "isCommentAutoGenerated" : true + }, + "Archive Task" : { + "comment" : "A button that archives a task. The text \"Archive Task\" is a placeholder and should be replaced with the actual translation.", + "isCommentAutoGenerated" : true + }, + "Are you sure you want to archive \"%@\"? You can unarchive it later from archived tasks." : { + "comment" : "A confirmation alert that appears when a user attempts to archive a task. The argument is the title of the task that is being archived.", + "isCommentAutoGenerated" : true + }, + "Are you sure you want to archive this task? You can unarchive it later from archived tasks." : { + "comment" : "An alert message displayed when the user taps the \"Archive\" button on a task. It confirms that the user intends to archive the task and provides a hint that the task can be restored later.", + "isCommentAutoGenerated" : true + }, + "Are you sure you want to cancel this task? This action cannot be undone." : { + "comment" : "An alert message displayed when a user taps the \"Cancel Task\" button in the task details view. It confirms that the user intends to cancel the task and warns them that the action cannot be undone.", + "isCommentAutoGenerated" : true + }, + "At least 8 characters" : { + + }, + "auth_account_info" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kontoinformationen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Account Information" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Información de la cuenta" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informations du compte" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informações da conta" + } + } + } + }, + "auth_dont_have_account" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Noch kein Konto?" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Don't have an account?" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿No tienes una cuenta?" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pas encore de compte ?" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não tem uma conta?" + } + } + } + }, + "auth_enter_email" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geben Sie Ihre E-Mail ein" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter your email" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingresa tu correo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrez votre email" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Digite seu email" + } + } + } + }, + "auth_enter_password" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geben Sie Ihr Passwort ein" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter your password" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingresa tu contraseña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrez votre mot de passe" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Digite sua senha" + } + } + } + }, + "auth_forgot_button" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Code senden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Send Reset Code" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enviar Código" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Envoyer le code" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enviar Código" + } + } + } + }, + "auth_forgot_email_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "E-Mail" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Correo Electrónico" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + } + } + }, + "auth_forgot_password" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwort vergessen?" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forgot Password?" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿Olvidaste tu Contraseña?" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mot de passe oublié ?" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Esqueceu a Senha?" + } + } + } + }, + "auth_forgot_subtitle" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geben Sie Ihre E-Mail ein, um einen Code zu erhalten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter your email to receive a reset code" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingresa tu correo para recibir un código" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrez votre email pour recevoir un code" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Digite seu email para receber um código" + } + } + } + }, + "auth_forgot_success" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wenn ein Konto existiert, wurde ein Code gesendet" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "If an account exists, a reset code has been sent" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Si existe una cuenta, se envió un código" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Si un compte existe, un code a été envoyé" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Se uma conta existir, um código foi enviado" + } + } + } + }, + "auth_forgot_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwort vergessen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forgot Password" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Olvidaste tu Contraseña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mot de passe oublié" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Esqueceu a Senha" + } + } + } + }, + "auth_have_account" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bereits ein Konto? Anmelden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Already have an account? Sign In" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿Ya tienes cuenta? Inicia Sesión" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Déjà un compte ? Se connecter" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Já tem conta? Entrar" + } + } + } + }, + "auth_hide_password" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwort verbergen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hide password" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ocultar contraseña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Masquer le mot de passe" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ocultar senha" + } + } + } + }, + "auth_join_casera" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bei Casera anmelden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Join Casera" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Únete a Casera" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rejoindre Casera" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Junte-se à Casera" + } + } + } + }, + "auth_login_button" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anmelden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sign In" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Iniciar Sesión" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Se connecter" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrar" + } + } + } + }, + "auth_login_failed" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anmeldung fehlgeschlagen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Login Failed" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error de Inicio de Sesión" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Échec de connexion" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Falha no Login" + } + } + } + }, + "auth_login_password_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwort" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Password" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contraseña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mot de passe" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Senha" + } + } + } + }, + "auth_login_subtitle" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verwalten Sie Ihre Immobilien einfach" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manage your properties with ease" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Administra tus propiedades con facilidad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gérez vos propriétés facilement" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gerencie suas propriedades com facilidade" + } + } + } + }, + "auth_login_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + } + } + }, + "auth_login_username_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Benutzername oder E-Mail" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Username or Email" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Usuario o Correo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nom d'utilisateur ou Email" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Usuário ou Email" + } + } + } + }, + "auth_logout" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abmelden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logout" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cerrar sesión" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Déconnexion" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sair" + } + } + } + }, + "auth_no_account" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kein Konto? Registrieren" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Don't have an account? Register" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿No tienes cuenta? Regístrate" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pas de compte ? S'inscrire" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não tem conta? Cadastre-se" + } + } + } + }, + "auth_or_divider" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "oder" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "or" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "o" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ou" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "ou" + } + } + } + }, + "auth_password_suggestion" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tippen Sie auf das Passwortfeld für einen starken Passwortvorschlag" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tap the password field for a strong password suggestion" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toca el campo de contraseña para una sugerencia de contraseña segura" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appuyez sur le champ mot de passe pour une suggestion de mot de passe fort" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toque no campo de senha para uma sugestão de senha forte" + } + } + } + }, + "auth_passwords_dont_match" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwörter stimmen nicht überein" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwords don't match" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Las contraseñas no coinciden" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Les mots de passe ne correspondent pas" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "As senhas não coincidem" + } + } + } + }, + "auth_register_button" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konto erstellen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Create Account" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Crear Cuenta" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Créer un compte" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Criar Conta" + } + } + } + }, + "auth_register_confirm_password" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwort bestätigen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Confirm Password" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Confirmar Contraseña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Confirmer le mot de passe" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Confirmar Senha" + } + } + } + }, + "auth_register_email" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "E-Mail" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Correo Electrónico" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + } + } + }, + "auth_register_first_name" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vorname" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "First Name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nombre" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prénom" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nome" + } + } + } + }, + "auth_register_last_name" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nachname" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Last Name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apellido" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nom" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sobrenome" + } + } + } + }, + "auth_register_password" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwort" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Password" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contraseña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mot de passe" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Senha" + } + } + } + }, + "auth_register_subtitle" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Registrieren Sie sich, um zu beginnen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sign up to get started" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Regístrate para comenzar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inscrivez-vous pour commencer" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cadastre-se para começar" + } + } + } + }, + "auth_register_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konto erstellen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Create Account" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Crear Cuenta" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Créer un compte" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Criar Conta" + } + } + } + }, + "auth_register_username" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Benutzername" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Username" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Usuario" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nom d'utilisateur" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Usuário" + } + } + } + }, + "auth_reset_button" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwort zurücksetzen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reset Password" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Restablecer Contraseña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Réinitialiser" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Redefinir Senha" + } + } + } + }, + "auth_reset_code_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Code" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reset Code" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Código" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Code" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Código" + } + } + } + }, + "auth_reset_confirm_password" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Neues Passwort bestätigen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Confirm New Password" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Confirmar Nueva Contraseña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Confirmer le nouveau mot de passe" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Confirmar Nova Senha" + } + } + } + }, + "auth_reset_new_password" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Neues Passwort" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "New Password" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nueva Contraseña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nouveau mot de passe" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nova Senha" + } + } + } + }, + "auth_reset_subtitle" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geben Sie Ihr neues Passwort ein" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter your new password" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingresa tu nueva contraseña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrez votre nouveau mot de passe" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Digite sua nova senha" + } + } + } + }, + "auth_reset_success" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwort erfolgreich zurückgesetzt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Password reset successfully" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contraseña restablecida correctamente" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mot de passe réinitialisé avec succès" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Senha redefinida com sucesso" + } + } + } + }, + "auth_reset_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwort zurücksetzen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reset Password" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Restablecer Contraseña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Réinitialiser le mot de passe" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Redefinir Senha" + } + } + } + }, + "auth_security" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sicherheit" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Security" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seguridad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sécurité" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Segurança" + } + } + } + }, + "auth_show_password" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passwort anzeigen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Show password" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mostrar contraseña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Afficher le mot de passe" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mostrar senha" + } + } + } + }, + "auth_sign_in_subtitle" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Melden Sie sich an, um Ihre Immobilien zu verwalten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sign in to manage your properties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inicia sesión para administrar tus propiedades" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Connectez-vous pour gérer vos propriétés" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entre para gerenciar suas propriedades" + } + } + } + }, + "auth_sign_up" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Registrieren" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sign Up" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Registrarse" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "S'inscrire" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cadastrar" + } + } + } + }, + "auth_signing_in" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anmelden..." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Signing In..." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Iniciando sesión..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Connexion..." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrando..." + } + } + } + }, + "auth_signing_in_with_apple" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mit Apple anmelden..." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Signing in with Apple..." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Iniciando sesión con Apple..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Connexion avec Apple..." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrando com Apple..." + } + } + } + }, + "auth_start_managing" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beginnen Sie noch heute mit der Verwaltung Ihrer Immobilien" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Start managing your properties today" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Comienza a administrar tus propiedades hoy" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Commencez à gérer vos propriétés dès aujourd'hui" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Comece a gerenciar suas propriedades hoje" + } + } + } + }, + "auth_verify_button" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bestätigen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verify" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verificar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vérifier" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verificar" + } + } + } + }, + "auth_verify_check_inbox" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "E-Mail-Bestätigung erforderlich. Überprüfen Sie Ihr Postfach auf einen 6-stelligen Code." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email verification is required. Check your inbox for a 6-digit code." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Se requiere verificación de correo. Revisa tu bandeja de entrada para un código de 6 dígitos." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "La vérification de l'email est requise. Vérifiez votre boîte de réception pour un code à 6 chiffres." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verificação de email é necessária. Verifique sua caixa de entrada para um código de 6 dígitos." + } + } + } + }, + "auth_verify_code_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bestätigungscode" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verification Code" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Código de Verificación" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Code de vérification" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Código de Verificação" + } + } + } + }, + "auth_verify_code_must_be_6" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Der Code muss 6 Ziffern haben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Code must be 6 digits" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El código debe tener 6 dígitos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le code doit contenir 6 chiffres" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O código deve ter 6 dígitos" + } + } + } + }, + "auth_verify_email_button" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "E-Mail bestätigen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verify Email" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verificar correo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vérifier l'email" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verificar email" + } + } + } + }, + "auth_verify_help_text" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keinen Code erhalten? Überprüfen Sie Ihren Spam-Ordner oder kontaktieren Sie den Support." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Didn't receive the code? Check your spam folder or contact support." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿No recibiste el código? Revisa tu carpeta de spam o contacta soporte." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Code non reçu ? Vérifiez votre dossier spam ou contactez le support." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não recebeu o código? Verifique sua pasta de spam ou entre em contato com o suporte." + } + } + } + }, + "auth_verify_must_verify" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sie müssen Ihre E-Mail-Adresse bestätigen, um fortzufahren" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You must verify your email address to continue" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Debes verificar tu correo electrónico para continuar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vous devez vérifier votre adresse email pour continuer" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Você deve verificar seu email para continuar" + } + } + } + }, + "auth_verify_resend" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Code erneut senden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Resend Code" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reenviar Código" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Renvoyer le code" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reenviar Código" + } + } + } + }, + "auth_verify_subtitle" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geben Sie den 6-stelligen Code ein" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter the 6-digit code sent to your email" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingresa el código de 6 dígitos enviado a tu correo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrez le code à 6 chiffres envoyé à votre email" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Digite o código de 6 dígitos enviado para seu email" + } + } + } + }, + "auth_verify_success" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "E-Mail erfolgreich bestätigt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email verified successfully" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Correo verificado correctamente" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email vérifié avec succès" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email verificado com sucesso" + } + } + } + }, + "auth_verify_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "E-Mail bestätigen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verify Email" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verificar Correo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vérifier l'email" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verificar Email" + } + } + } + }, + "auth_verify_your_email" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "E-Mail bestätigen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verify Your Email" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verifica tu correo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vérifiez votre email" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verifique seu email" + } + } + } + }, + "auth_welcome_back" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Willkommen zurück" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Welcome Back" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bienvenido de nuevo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bon retour" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bem-vindo de volta" + } + } + } + }, + "Back" : { + + }, + "Back to Login" : { + "comment" : "A button label that takes the user back to the login screen.", + "isCommentAutoGenerated" : true + }, + "By: %@" : { + "comment" : "A line in the checkout view displaying the name of the contractor who completed a task.", + "isCommentAutoGenerated" : true + }, + "Cancel" : { + "comment" : "The label of a button that dismisses an alert.", + "isCommentAutoGenerated" : true + }, + "Cancel Task" : { + + }, + "Caption" : { + "comment" : "A label displayed above the caption of an image in the photo viewer.", + "isCommentAutoGenerated" : true + }, + "Casera" : { + "comment" : "The name of the app.", + "isCommentAutoGenerated" : true + }, + "Check Your Email" : { + "comment" : "A heading that instructs the user to check their email for a verification code.", + "isCommentAutoGenerated" : true + }, + "Check your spam folder if you don't see it" : { + "comment" : "A description below the \"Send New Code\" button, instructing the user to check their spam folder if they haven't received the verification code.", + "isCommentAutoGenerated" : true + }, + "Choose Your Plan" : { + "comment" : "A heading displayed at the top of the feature comparison view.", + "isCommentAutoGenerated" : true + }, + "Close" : { + + }, + "Code expires in 15 minutes" : { + "comment" : "A description of how long the verification code is valid for.", + "isCommentAutoGenerated" : true + }, + "common_back" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zurück" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Back" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Atrás" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Retour" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Voltar" + } + } + } + }, + "common_cancel" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abbrechen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancel" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancelar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Annuler" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancelar" + } + } + } + }, + "common_close" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Schließen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cerrar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fermer" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fechar" + } + } + } + }, + "common_delete" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Löschen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eliminar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Supprimer" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Excluir" + } + } + } + }, + "common_done" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fertig" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Done" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Listo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Terminé" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pronto" + } + } + } + }, + "common_edit" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bearbeiten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifier" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar" + } + } + } + }, + "common_error" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fehler" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erreur" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erro" + } + } + } + }, + "common_loading" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wird geladen..." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loading..." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cargando..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chargement..." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carregando..." + } + } + } + }, + "common_no" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nein" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Non" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não" + } + } + } + }, + "common_ok" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "OK" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "OK" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "OK" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "OK" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "OK" + } + } + } + }, + "common_retry" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erneut versuchen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Retry" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reintentar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Réessayer" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tentar Novamente" + } + } + } + }, + "common_save" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Speichern" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Guardar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enregistrer" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Salvar" + } + } + } + }, + "common_success" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erfolg" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Success" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Éxito" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Succès" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sucesso" + } + } + } + }, + "common_yes" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ja" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yes" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sí" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Oui" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sim" + } + } + } + }, + "Compare Free vs Pro" : { + "comment" : "A button label that links to a view comparing free and pro plans.", + "isCommentAutoGenerated" : true + }, + "Complete" : { + "comment" : "A button label that indicates a task has been completed.", + "isCommentAutoGenerated" : true + }, + "Complete Task" : { + "comment" : "A button label that says \"Complete Task\".", + "isCommentAutoGenerated" : true + }, + "Completion Photos" : { + "comment" : "The title for the view that shows a user's photo submissions.", + "isCommentAutoGenerated" : true + }, + "Confirm Password" : { + + }, + "Contains letters" : { + + }, + "Contains numbers" : { + + }, + "Contractors" : { + "comment" : "A tab label for the contractors section.", + "isCommentAutoGenerated" : true + }, + "contractors_add_button" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dienstleister hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add Contractor" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar Contratista" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter un prestataire" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar Prestador" + } + } + } + }, + "contractors_add_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dienstleister hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add Contractor" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar Contratista" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter un prestataire" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar Prestador" + } + } + } + }, + "contractors_add_to_favorites" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zu Favoriten hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add to Favorites" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar a Favoritos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter aux Favoris" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar aos Favoritos" + } + } + } + }, + "contractors_added_by_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hinzugefügt von" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Added By" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregado Por" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouté Par" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionado Por" + } + } + } + }, + "contractors_address_section" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adresse" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Address" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dirección" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adresse" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Endereço" + } + } + } + }, + "contractors_all_specialties" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alle Fachgebiete" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "All Specialties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Todas las Especialidades" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toutes les Spécialités" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Todas as Especialidades" + } + } + } + }, + "contractors_associated_property_section" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zugehörige Immobilie" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Associated Property" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propiedad Asociada" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriété Associée" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriedade Associada" + } + } + } + }, + "contractors_average_rating_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Durchschnittsbewertung" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Average Rating" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Calificación Promedio" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Note Moyenne" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avaliação Média" + } + } + } + }, + "contractors_basic_info_footer" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erforderlich: Name" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Required: Name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requerido: Nombre" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requis : Nom" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obrigatório: Nome" + } + } + } + }, + "contractors_basic_info_section" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Grundinformationen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basic Information" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Información Básica" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informations de Base" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informações Básicas" + } + } + } + }, + "contractors_call_action" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anrufen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Call" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Llamar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appeler" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ligar" + } + } + } + }, + "contractors_city_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stadt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "City" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciudad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ville" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cidade" + } + } + } + }, + "contractors_clear_action" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Löschen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Clear" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limpiar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Effacer" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limpar" + } + } + } + }, + "contractors_company_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Firma" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Company" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Empresa" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entreprise" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Empresa" + } + } + } + }, + "contractors_completed_tasks" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d abgeschlossene Aufgaben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d completed tasks" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d tareas completadas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d tâches terminées" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d tarefas concluídas" + } + } + } + }, + "contractors_contact_info_section" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kontaktinformationen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contact Information" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Información de Contacto" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informations de Contact" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informações de Contato" + } + } + } + }, + "contractors_delete_confirm" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dienstleister löschen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete Contractor" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eliminar Contratista" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Supprimer le Prestataire" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Excluir Prestador" + } + } + } + }, + "contractors_delete_message" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Möchten Sie diesen Dienstleister wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Are you sure you want to delete this contractor? This action cannot be undone." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿Estás seguro de que quieres eliminar este contratista? Esta acción no se puede deshacer." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Êtes-vous sûr de vouloir supprimer ce prestataire ? Cette action ne peut pas être annulée." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tem certeza de que deseja excluir este prestador? Esta ação não pode ser desfeita." + } + } + } + }, + "contractors_directions_action" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wegbeschreibung" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Directions" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Direcciones" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Itinéraire" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Direções" + } + } + } + }, + "contractors_edit_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dienstleister bearbeiten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit Contractor" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Contratista" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifier le prestataire" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Prestador" + } + } + } + }, + "contractors_email_action" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "E-Mail" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Correo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + } + } + }, + "contractors_email_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "E-Mail" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Correo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + } + } + }, + "contractors_empty_filtered" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Dienstleister gefunden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No contractors found" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se encontraron contratistas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucun prestataire trouvé" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nenhum prestador encontrado" + } + } + } + }, + "contractors_empty_no_filters" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fügen Sie Ihren ersten Dienstleister hinzu, um zu beginnen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add your first contractor to get started" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agrega tu primer contratista para comenzar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajoutez votre premier prestataire pour commencer" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicione seu primeiro prestador para começar" + } + } + } + }, + "contractors_empty_subtitle" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fügen Sie vertrauenswürdige Dienstleister hinzu" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add trusted contractors for your property" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agrega contratistas de confianza" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajoutez des prestataires de confiance" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicione prestadores de confiança" + } + } + } + }, + "contractors_empty_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Dienstleister" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No contractors yet" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin contratistas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucun prestataire" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem prestadores" + } + } + } + }, + "contractors_favorite_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Als Favorit markieren" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mark as Favorite" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Marcar como Favorito" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Marquer comme Favori" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Marcar como Favorito" + } + } + } + }, + "contractors_favorites" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Favoriten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Favorites" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Favoritos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Favoris" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Favoritos" + } + } + } + }, + "contractors_info_section" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Info" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Info" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Info" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Info" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Info" + } + } + } + }, + "contractors_location_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Standort" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Location" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ubicación" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Emplacement" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Localização" + } + } + } + }, + "contractors_member_since_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mitglied seit" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Member Since" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Miembro Desde" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Membre Depuis" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Membro Desde" + } + } + } + }, + "contractors_name_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Name" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nombre" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nom" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nome" + } + } + } + }, + "contractors_notes_footer" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Private Notizen zu diesem Dienstleister" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Private notes about this contractor" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas privadas sobre este contratista" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes privées sur ce prestataire" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas privadas sobre este prestador" + } + } + } + }, + "contractors_notes_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notizen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas" + } + } + } + }, + "contractors_notes_section" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notizen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas" + } + } + } + }, + "contractors_personal_no_residence" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Persönlich (Keine Immobilie)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Personal (No Residence)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Personal (Sin Propiedad)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Personnel (Sans Propriété)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pessoal (Sem Propriedade)" + } + } + } + }, + "contractors_phone_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Telefon" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Phone" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Teléfono" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Téléphone" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Telefone" + } + } + } + }, + "contractors_property_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Property" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriedade" + } + } + } + }, + "contractors_remove_from_favorites" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aus Favoriten entfernen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Remove from Favorites" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eliminar de Favoritos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Retirer des Favoris" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Remover dos Favoritos" + } + } + } + }, + "contractors_residence_footer_personal" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nur Sie werden diesen Dienstleister sehen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Only you will see this contractor" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Solo tú verás este contratista" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seul vous verrez ce prestataire" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apenas você verá este prestador" + } + } + } + }, + "contractors_residence_footer_shared" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alle Benutzer von %@ werden diesen Dienstleister sehen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "All users of %@ will see this contractor" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Todos los usuarios de %@ verán este contratista" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tous les utilisateurs de %@ verront ce prestataire" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Todos os usuários de %@ verão este prestador" + } + } + } + }, + "contractors_residence_section" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie (Optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Residence (Optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propiedad (Opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriété (Optionnel)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriedade (Opcional)" + } + } + } + }, + "contractors_search_placeholder" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dienstleister suchen..." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Search contractors..." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buscar contratistas..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rechercher des prestataires..." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buscar prestadores..." + } + } + } + }, + "contractors_select_residence" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie auswählen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select Residence" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionner la Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecionar Propriedade" + } + } + } + }, + "contractors_select_specialties" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fachgebiete auswählen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select Specialties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar Especialidades" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionner les Spécialités" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecionar Especialidades" + } + } + } + }, + "contractors_select_specialties_placeholder" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fachgebiete auswählen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select Specialties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar Especialidades" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionner les Spécialités" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecionar Especialidades" + } + } + } + }, + "contractors_specialties_section" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fachgebiete" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Specialties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Especialidades" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Spécialités" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Especialidades" + } + } + } + }, + "contractors_state_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bundesland" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "State" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estado" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "État" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estado" + } + } + } + }, + "contractors_statistics_section" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Statistiken" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Statistics" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estadísticas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Statistiques" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estatísticas" + } + } + } + }, + "contractors_street_address_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Straße" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Street Address" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dirección" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adresse" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Endereço" + } + } + } + }, + "contractors_tasks_completed_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abgeschlossene Aufgaben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tasks Completed" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tareas Completadas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tâches Terminées" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tarefas Concluídas" + } + } + } + }, + "contractors_tasks_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgaben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "tasks" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "tareas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "tâches" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "tarefas" + } + } + } + }, + "contractors_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dienstleister" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contractors" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contratistas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prestataires" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prestadores" + } + } + } + }, + "contractors_website_action" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Webseite" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Website" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sitio Web" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Site Web" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Site" + } + } + } + }, + "contractors_website_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Webseite" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Website" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sitio Web" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Site Web" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Site" + } + } + } + }, + "contractors_zip_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "PLZ" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "ZIP" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Código Postal" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Code Postal" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "CEP" + } + } + } + }, + "Cost: $%@" : { + "comment" : "A label displaying the cost of a task completion. The argument is the cost as a string.", + "isCommentAutoGenerated" : true + }, + "Create a strong password to secure your account" : { + + }, + "Didn't receive the code?" : { + "comment" : "A question displayed below a button in the \"Verify Code\" view, instructing the user to request a new code if they haven't received one.", + "isCommentAutoGenerated" : true + }, + "Documents" : { + "comment" : "A label displayed above the list of documents and warranties.", + "isCommentAutoGenerated" : true + }, + "documents_active" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktiv" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Active" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Activo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actif" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ativo" + } + } + } + }, + "documents_active_only" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nur Aktive" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Active Only" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Solo Activos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actifs Uniquement" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apenas Ativos" + } + } + } + }, + "documents_active_status" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktiv" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Active" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Activo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actif" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ativo" + } + } + } + }, + "documents_add_button" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dokument hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add Document" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar Documento" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter un document" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar Documento" + } + } + } + }, + "documents_add_document" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dokument Hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add Document" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar Documento" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter un Document" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar Documento" + } + } + } + }, + "documents_add_warranty" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantie Hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add Warranty" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar Garantía" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter une Garantie" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar Garantia" + } + } + } + }, + "documents_additional_information" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zusätzliche Informationen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Additional Information" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Información Adicional" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informations Supplémentaires" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informações Adicionais" + } + } + } + }, + "documents_all_categories" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alle Kategorien" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "All Categories" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Todas las Categorías" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toutes les Catégories" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Todas as Categorias" + } + } + } + }, + "documents_all_types" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alle Typen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "All Types" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Todos los Tipos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tous les Types" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Todos os Tipos" + } + } + } + }, + "documents_and_warranties" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dokumente & Garantien" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Documents & Warranties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Documentos y Garantías" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Documents et Garanties" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Documentos e Garantias" + } + } + } + }, + "documents_associations" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zuordnungen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Associations" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Asociaciones" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Associations" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Associações" + } + } + } + }, + "documents_attached_file" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Angehängte Datei" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Attached File" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Archivo Adjunto" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fichier Joint" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Arquivo Anexado" + } + } + } + }, + "documents_basic_information" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Grundinformationen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basic Information" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Información Básica" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informations de Base" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informações Básicas" + } + } + } + }, + "documents_category" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kategorie" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Category" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Categoría" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Catégorie" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Categoria" + } + } + } + }, + "documents_category_appliance" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gerät" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appliance" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Electrodoméstico" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appareil" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eletrodoméstico" + } + } + } + }, + "documents_category_electrical" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Elektrisch" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Electrical" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eléctrico" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Électrique" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Elétrico" + } + } + } + }, + "documents_category_hvac" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "HLK" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "HVAC" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "HVAC" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "CVC" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "AVAC" + } + } + } + }, + "documents_category_optional" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kategorie (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Category (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Categoría (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Catégorie (facultatif)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Categoria (opcional)" + } + } + } + }, + "documents_category_other" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Andere" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Other" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otro" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Autre" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Outro" + } + } + } + }, + "documents_category_plumbing" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sanitär" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Plumbing" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Plomería" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Plomberie" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Encanamento" + } + } + } + }, + "documents_category_roofing" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dach" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Roofing" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Techado" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toiture" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Telhado" + } + } + } + }, + "documents_category_structural" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Strukturell" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Structural" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estructural" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Structurel" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estrutural" + } + } + } + }, + "documents_category_unknown" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unbekannt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unknown" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desconocido" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inconnu" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desconhecido" + } + } + } + }, + "documents_claim_email" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anspruchs-E-Mail" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Claim Email" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Correo de Reclamos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email de Réclamation" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email de Reclamação" + } + } + } + }, + "documents_claim_email_optional" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anspruchs-E-Mail (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Claim Email (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Correo de Reclamos (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email de Réclamation (facultatif)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email de Reclamação (opcional)" + } + } + } + }, + "documents_claim_information" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anspruchsinformationen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Claim Information" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Información de Reclamos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informations de Réclamation" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informações de Reclamação" + } + } + } + }, + "documents_claim_phone" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anspruchstelefon" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Claim Phone" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Teléfono de Reclamos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Téléphone de Réclamation" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Telefone de Reclamação" + } + } + } + }, + "documents_claim_phone_optional" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anspruchstelefon (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Claim Phone (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Teléfono de Reclamos (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Téléphone de Réclamation (facultatif)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Telefone de Reclamação (opcional)" + } + } + } + }, + "documents_claim_website" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anspruchs-Website" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Claim Website" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sitio Web de Reclamos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Site Web de Réclamation" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Site de Reclamação" + } + } + } + }, + "documents_claim_website_optional" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anspruchs-Website (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Claim Website (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sitio Web de Reclamos (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Site Web de Réclamation (facultatif)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Site de Reclamação (opcional)" + } + } + } + }, + "documents_contractor" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auftragnehmer" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contractor" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contratista" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrepreneur" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contratante" + } + } + } + }, + "documents_contractor_phone" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auftragnehmertelefon" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contractor Phone" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Teléfono del Contratista" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Téléphone de l'Entrepreneur" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Telefone do Contratante" + } + } + } + }, + "documents_created" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erstellt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Created" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Creado" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Créé" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Criado" + } + } + } + }, + "documents_days_remaining" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verbleibende Tage" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Days Remaining" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Días Restantes" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Jours Restants" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dias Restantes" + } + } + } + }, + "documents_days_remaining_count" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d Tage verbleibend" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d days remaining" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d días restantes" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d jours restants" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d dias restantes" + } + } + } + }, + "documents_delete_confirm_message" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sind Sie sicher, dass Sie dieses Dokument löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Are you sure you want to delete this document? This action cannot be undone." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿Está seguro de que desea eliminar este documento? Esta acción no se puede deshacer." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Êtes-vous sûr de vouloir supprimer ce document? Cette action ne peut pas être annulée." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tem certeza de que deseja excluir este documento? Esta ação não pode ser desfeita." + } + } + } + }, + "documents_delete_document" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dokument Löschen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete Document" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eliminar Documento" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Supprimer le Document" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Excluir Documento" + } + } + } + }, + "documents_description" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beschreibung" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Description" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descripción" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Description" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descrição" + } + } + } + }, + "documents_description_optional" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beschreibung (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Description (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descripción (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Description (facultatif)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descrição (opcional)" + } + } + } + }, + "documents_document_details" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dokumentdetails" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Document Details" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Detalles del Documento" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Détails du Document" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Detalhes do Documento" + } + } + } + }, + "documents_document_id_missing" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dokument-ID fehlt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Document ID is missing" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Falta el ID del documento" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "L'ID du document est manquant" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "ID do documento está faltando" + } + } + } + }, + "documents_document_type" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dokumenttyp" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Document Type" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tipo de Documento" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Type de Document" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tipo de Documento" + } + } + } + }, + "documents_document_type_cannot_change" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dokumenttyp kann nicht geändert werden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Document type cannot be changed" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El tipo de documento no se puede cambiar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le type de document ne peut pas être modifié" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O tipo de documento não pode ser alterado" + } + } + } + }, + "documents_documents" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dokumente" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Documents" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Documentos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Documents" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Documentos" + } + } + } + }, + "documents_download_file" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datei Herunterladen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Download File" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descargar Archivo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Télécharger le Fichier" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baixar Arquivo" + } + } + } + }, + "documents_edit_document" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dokument Bearbeiten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit Document" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Documento" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifier le Document" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Documento" + } + } + } + }, + "documents_edit_warranty" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantie Bearbeiten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit Warranty" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Garantía" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifier la Garantie" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Garantia" + } + } + } + }, + "documents_empty_subtitle" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Speichern Sie wichtige Dokumente und Garantien" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Store important documents and warranties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Guarda documentos importantes y garantías" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stockez vos documents importants et garanties" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Guarde documentos importantes e garantias" + } + } + } + }, + "documents_empty_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Dokumente" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No documents yet" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin documentos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucun document" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem documentos" + } + } + } + }, + "documents_end_date" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantieende (JJJJ-MM-TT)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warranty End Date (YYYY-MM-DD)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fecha de Fin de Garantía (AAAA-MM-DD)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Date de Fin de Garantie (AAAA-MM-JJ)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Data de Término da Garantia (AAAA-MM-DD)" + } + } + } + }, + "documents_existing_photos" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vorhandene Fotos" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Existing Photos" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fotos Existentes" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Photos Existantes" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fotos Existentes" + } + } + } + }, + "documents_expired" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abgelaufen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Expired" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vencido" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Expiré" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Expirado" + } + } + } + }, + "documents_expires" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Läuft Ab" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Expires" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vence" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Expire" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Expira" + } + } + } + }, + "documents_expiring_soon" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Läuft Bald Ab" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Expiring Soon" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vence Pronto" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Expire Bientôt" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Expirando em Breve" + } + } + } + }, + "documents_failed_to_create" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fehler beim Erstellen des Dokuments" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Failed to create document" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error al crear el documento" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Échec de la création du document" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Falha ao criar o documento" + } + } + } + }, + "documents_failed_to_update" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fehler beim Aktualisieren des Dokuments" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Failed to update document" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error al actualizar el documento" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Échec de la mise à jour du document" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Falha ao atualizar o documento" + } + } + } + }, + "documents_file_size" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dateigröße" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "File Size" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tamaño del Archivo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Taille du Fichier" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tamanho do Arquivo" + } + } + } + }, + "documents_file_type" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dateityp" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "File Type" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tipo de Archivo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Type de Fichier" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tipo de Arquivo" + } + } + } + }, + "documents_fill_required_fields" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bitte füllen Sie alle erforderlichen Felder aus" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Please fill in all required fields" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Por favor complete todos los campos obligatorios" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Veuillez remplir tous les champs requis" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Por favor, preencha todos os campos obrigatórios" + } + } + } + }, + "documents_images" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bilder" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Images" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Imágenes" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Images" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Imagens" + } + } + } + }, + "documents_important_dates" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wichtige Daten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Important Dates" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fechas Importantes" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dates Importantes" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datas Importantes" + } + } + } + }, + "documents_inactive" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inaktiv" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inactive" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inactivo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inactif" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inativo" + } + } + } + }, + "documents_item_details" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Artikeldetails" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Item Details" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Detalles del Artículo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Détails de l'Article" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Detalhes do Item" + } + } + } + }, + "documents_item_name" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Artikelname" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Item Name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nombre del Artículo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nom de l'Article" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nome do Item" + } + } + } + }, + "documents_item_name_required" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Artikelname ist für Garantien erforderlich" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Item name is required for warranties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El nombre del artículo es obligatorio para garantías" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le nom de l'article est requis pour les garanties" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O nome do item é obrigatório para garantias" + } + } + } + }, + "documents_loading_document" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dokument wird geladen..." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loading document..." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cargando documento..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chargement du document..." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carregando documento..." + } + } + } + }, + "documents_metadata" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Metadaten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Metadata" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Metadatos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Métadonnées" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Metadados" + } + } + } + }, + "documents_model_number" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modellnummer" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Model Number" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Número de Modelo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Numéro de Modèle" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Número do Modelo" + } + } + } + }, + "documents_model_number_optional" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modellnummer (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Model Number (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Número de Modelo (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Numéro de Modèle (facultatif)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Número do Modelo (opcional)" + } + } + } + }, + "documents_na" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "k.A." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "N/A" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "N/A" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "N/A" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "N/D" + } + } + } + }, + "documents_no_documents_found" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Dokumente gefunden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No documents found" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se encontraron documentos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucun document trouvé" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nenhum documento encontrado" + } + } + } + }, + "documents_no_documents_message" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fügen Sie Dokumente zu Ihrer Residenz hinzu" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add documents related to your residence" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregue documentos relacionados con su residencia" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajoutez des documents liés à votre résidence" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicione documentos relacionados à sua residência" + } + } + } + }, + "documents_no_residence_selected" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Residenz ausgewählt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No residence selected" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se seleccionó ninguna residencia" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune résidence sélectionnée" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nenhuma residência selecionada" + } + } + } + }, + "documents_no_warranties_found" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Garantien gefunden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No warranties found" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se encontraron garantías" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune garantie trouvée" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nenhuma garantia encontrada" + } + } + } + }, + "documents_no_warranties_message" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fügen Sie Garantien hinzu, um Deckungszeiträume zu verfolgen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add warranties to track coverage periods" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregue garantías para rastrear períodos de cobertura" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajoutez des garanties pour suivre les périodes de couverture" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicione garantias para rastrear períodos de cobertura" + } + } + } + }, + "documents_none" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "None" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ninguno" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucun" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nenhum" + } + } + } + }, + "documents_notes" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notizen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas" + } + } + } + }, + "documents_notes_optional" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notizen (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes (facultatif)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas (opcional)" + } + } + } + }, + "documents_photos" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fotos" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Photos" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fotos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Photos" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fotos" + } + } + } + }, + "documents_photos_selected" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d Foto(s) ausgewählt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d photo(s) selected" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d foto(s) seleccionada(s)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d photo(s) sélectionnée(s)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d foto(s) selecionada(s)" + } + } + } + }, + "documents_property" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Property" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriedade" + } + } + } + }, + "documents_property_required" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie ist erforderlich" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Property is required" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "La propiedad es obligatoria" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "La propriété est requise" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "A propriedade é obrigatória" + } + } + } + }, + "documents_provider" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anbieter" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Provider" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Proveedor" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fournisseur" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fornecedor" + } + } + } + }, + "documents_provider_company" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anbieter/Firma" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Provider/Company" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Proveedor/Empresa" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fournisseur/Entreprise" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fornecedor/Empresa" + } + } + } + }, + "documents_provider_contact" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anbieterkontakt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Provider Contact" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contacto del Proveedor" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contact du Fournisseur" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contato do Fornecedor" + } + } + } + }, + "documents_provider_contact_optional" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anbieterkontakt (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Provider Contact (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contacto del Proveedor (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contact du Fournisseur (facultatif)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contato do Fornecedor (opcional)" + } + } + } + }, + "documents_provider_required" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anbieter ist für Garantien erforderlich" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Provider is required for warranties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El proveedor es obligatorio para garantías" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le fournisseur est requis pour les garanties" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O fornecedor é obrigatório para garantias" + } + } + } + }, + "documents_purchase_date" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kaufdatum (JJJJ-MM-TT)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Purchase Date (YYYY-MM-DD)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fecha de Compra (AAAA-MM-DD)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Date d'Achat (AAAA-MM-JJ)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Data de Compra (AAAA-MM-DD)" + } + } + } + }, + "documents_required" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erforderlich" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Required" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requerido" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requis" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obrigatório" + } + } + } + }, + "documents_required_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erforderlich: Titel" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Required: Title" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requerido: Título" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requis: Titre" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obrigatório: Título" + } + } + } + }, + "documents_required_warranty_fields" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erforderlich für Garantien: Artikelname und Anbieter" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Required for warranties: Item Name and Provider" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requerido para garantías: Nombre del Artículo y Proveedor" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requis pour les garanties: Nom de l'Article et Fournisseur" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obrigatório para garantias: Nome do Item e Fornecedor" + } + } + } + }, + "documents_residence" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Residenz" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Residence" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Residencia" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Résidence" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Residência" + } + } + } + }, + "documents_search_placeholder" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suchen..." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Search..." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buscar..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rechercher..." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pesquisar..." + } + } + } + }, + "documents_select_from_library" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aus Bibliothek Auswählen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select from Library" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar de la Biblioteca" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionner depuis la Bibliothèque" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecionar da Biblioteca" + } + } + } + }, + "documents_select_property" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie Auswählen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select Property" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionner une Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecionar Propriedade" + } + } + } + }, + "documents_serial_number" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seriennummer" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Serial Number" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Número de Serie" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Numéro de Série" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Número de Série" + } + } + } + }, + "documents_serial_number_optional" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seriennummer (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Serial Number (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Número de Serie (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Numéro de Série (facultatif)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Número de Série (opcional)" + } + } + } + }, + "documents_start_date" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantiebeginn (JJJJ-MM-TT)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warranty Start Date (YYYY-MM-DD)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fecha de Inicio de Garantía (AAAA-MM-DD)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Date de Début de Garantie (AAAA-MM-JJ)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Data de Início da Garantia (AAAA-MM-DD)" + } + } + } + }, + "documents_status" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Status" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Status" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estado" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Statut" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Status" + } + } + } + }, + "documents_tags" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tags" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tags" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Etiquetas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Étiquettes" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Etiquetas" + } + } + } + }, + "documents_tags_optional" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tags (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tags (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Etiquetas (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Étiquettes (facultatif)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Etiquetas (opcional)" + } + } + } + }, + "documents_take_photo" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Foto Aufnehmen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Take Photo" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tomar Foto" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prendre une Photo" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tirar Foto" + } + } + } + }, + "documents_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dokumente" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Documents" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Documentos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Documents" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Documentos" + } + } + } + }, + "documents_title_field" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Titel" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Title" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Título" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Titre" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Título" + } + } + } + }, + "documents_title_required" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Titel ist erforderlich" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Title is required" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El título es obligatorio" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le titre est requis" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O título é obrigatório" + } + } + } + }, + "documents_type_contract" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vertrag" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contract" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contrato" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contrat" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contrato" + } + } + } + }, + "documents_type_deed" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Urkunde" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deed" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Escritura" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Acte" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Escritura" + } + } + } + }, + "documents_type_inspection" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inspektion" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inspection" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inspección" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inspection" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inspeção" + } + } + } + }, + "documents_type_insurance" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Versicherung" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insurance" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seguro" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Assurance" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seguro" + } + } + } + }, + "documents_type_manual" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Handbuch" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manual" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manual" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuel" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manual" + } + } + } + }, + "documents_type_other" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Andere" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Other" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otro" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Autre" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Outro" + } + } + } + }, + "documents_type_permit" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Genehmigung" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Permit" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Permiso" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Permis" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Permissão" + } + } + } + }, + "documents_type_photo" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Foto" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Photo" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Foto" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Photo" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Foto" + } + } + } + }, + "documents_type_receipt" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quittung" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Receipt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recibo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reçu" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recibo" + } + } + } + }, + "documents_type_unknown" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unbekannt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unknown" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desconocido" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inconnu" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desconhecido" + } + } + } + }, + "documents_type_warranty" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantie" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warranty" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantía" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantie" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantia" + } + } + } + }, + "documents_update" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktualisieren" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Update" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actualizar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mettre à Jour" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Atualizar" + } + } + } + }, + "documents_updated" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktualisiert" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Updated" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actualizado" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mis à Jour" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Atualizado" + } + } + } + }, + "documents_uploaded_by" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hochgeladen Von" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uploaded By" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Subido Por" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Téléchargé Par" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enviado Por" + } + } + } + }, + "documents_warranties" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantien" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warranties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantías" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garanties" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantias" + } + } + } + }, + "documents_warranty_claims" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantieansprüche" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warranty Claims" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reclamos de Garantía" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Réclamations de Garantie" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reclamações de Garantia" + } + } + } + }, + "documents_warranty_dates" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantiedaten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warranty Dates" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fechas de Garantía" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dates de Garantie" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datas de Garantia" + } + } + } + }, + "documents_warranty_details" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantiedetails" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warranty Details" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Detalles de la Garantía" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Détails de la Garantie" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Detalhes da Garantia" + } + } + } + }, + "Done" : { + "comment" : "A button that dismisses an image viewer sheet.", + "isCommentAutoGenerated" : true + }, + "Edit" : { + "comment" : "A label for an edit action.", + "isCommentAutoGenerated" : true + }, + "Edit Task" : { + "comment" : "A label for an \"Edit Task\" button.", + "isCommentAutoGenerated" : true + }, + "Email" : { + "comment" : "A label displayed above the email text field in the \"Forgot Password?\" view.", + "isCommentAutoGenerated" : true + }, + "Email Address" : { + "comment" : "A label for the user to input their email address.", + "isCommentAutoGenerated" : true + }, + "Enter new password" : { + + }, + "Enter the 6-digit code from your email" : { + "comment" : "A footer label explaining that users should enter the 6-digit code they received in their email.", + "isCommentAutoGenerated" : true + }, + "Enter your email address and we'll send you a verification code" : { + "comment" : "A description below the email input field, instructing the user to enter their email address to receive a password reset code.", + "isCommentAutoGenerated" : true + }, + "error_generic" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Etwas ist schiefgelaufen. Bitte versuchen Sie es erneut." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Something went wrong. Please try again." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Algo salió mal. Por favor intenta de nuevo." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Une erreur s'est produite. Veuillez réessayer." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Algo deu errado. Por favor, tente novamente." + } + } + } + }, + "error_network" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Netzwerkfehler. Überprüfen Sie Ihre Verbindung." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Network error. Please check your connection." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error de red. Verifica tu conexión." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erreur réseau. Vérifiez votre connexion." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erro de rede. Verifique sua conexão." + } + } + } + }, + "error_not_found" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nicht gefunden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Not found" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No encontrado" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Non trouvé" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não encontrado" + } + } + } + }, + "error_required_field" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dieses Feld ist erforderlich" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This field is required" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Este campo es requerido" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ce champ est requis" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Este campo é obrigatório" + } + } + } + }, + "error_unauthorized" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sitzung abgelaufen. Bitte melden Sie sich erneut an." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Session expired. Please log in again." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sesión expirada. Inicia sesión de nuevo." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Session expirée. Veuillez vous reconnecter." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sessão expirada. Entre novamente." + } + } + } + }, + "Error: %@" : { + "comment" : "An error message displayed in the checkout view. The content of this message is determined by the `message` variable.", + "isCommentAutoGenerated" : true + }, + "Failed to load" : { + "comment" : "A message displayed when an image fails to load.", + "isCommentAutoGenerated" : true + }, + "Failed to load image" : { + "comment" : "A message displayed when an image fails to load.", + "isCommentAutoGenerated" : true + }, + "Feature" : { + "comment" : "The header for a feature in the feature comparison table.", + "isCommentAutoGenerated" : true + }, + "Forgot Password?" : { + "comment" : "A title for the \"Forgot Password?\" screen.", + "isCommentAutoGenerated" : true + }, + "Free" : { + "comment" : "A label indicating a free feature.", + "isCommentAutoGenerated" : true + }, + "Generate" : { + "comment" : "A button label that says \"Generate\".", + "isCommentAutoGenerated" : true + }, + "Image %lld of %lld" : { + "comment" : "A navigation title that shows the current image index and the total number of images.", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Image %1$lld of %2$lld" + } + } + } + }, + "In Progress" : { + "comment" : "A label displayed next to an image of a play button, indicating that a task is currently in progress.", + "isCommentAutoGenerated" : true + }, + "Join Casera" : { + "comment" : "A title for the registration screen.", + "isCommentAutoGenerated" : true + }, + "Loading..." : { + "comment" : "A placeholder text indicating that content is loading.", + "isCommentAutoGenerated" : true + }, + "Mark Task In Progress" : { + "comment" : "A button label that says \"Mark Task In Progress\".", + "isCommentAutoGenerated" : true + }, + "New Code" : { + "comment" : "A button label that appears when the user has already generated a share code.", + "isCommentAutoGenerated" : true + }, + "New Password" : { + + }, + "No active code" : { + "comment" : "A message indicating that a user does not have an active share code.", + "isCommentAutoGenerated" : true + }, + "No properties yet" : { + + }, + "No tasks yet" : { + "comment" : "A description displayed when a user has no tasks.", + "isCommentAutoGenerated" : true + }, + "Overview" : { + "comment" : "The title of the overview card.", + "isCommentAutoGenerated" : true + }, + "Owner" : { + "comment" : "A label indicating that a user is an owner of a residence.", + "isCommentAutoGenerated" : true + }, + "Password Requirements" : { + + }, + "Passwords match" : { + + }, + "Photo" : { + "comment" : "A title for a view that displays a single photo.", + "isCommentAutoGenerated" : true + }, + "Pro" : { + "comment" : "The title of the \"Pro\" plan in the feature comparison view.", + "isCommentAutoGenerated" : true + }, + "Profile" : { + "comment" : "A label for the \"Profile\" tab in the main tab view.", + "isCommentAutoGenerated" : true + }, + "profile_account" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konto" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Account" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cuenta" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Compte" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Conta" + } + } + } + }, + "profile_active_until" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktiv bis" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Active until" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Activo hasta" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actif jusqu'au" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ativo até" + } + } + } + }, + "profile_app_name" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Casera" + } + } + } + }, + "profile_appearance" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erscheinungsbild" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appearance" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apariencia" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apparence" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aparência" + } + } + } + }, + "profile_contact" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kontakt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contact" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contacto" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contact" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contato" + } + } + } + }, + "profile_edit_profile" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profil bearbeiten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit Profile" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Perfil" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifier le Profil" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Perfil" + } + } + } + }, + "profile_email" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "E-Mail" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Correo Electrónico" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + } + } + }, + "profile_email_required_unique" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "E-Mail ist erforderlich und muss eindeutig sein" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email is required and must be unique" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El correo electrónico es obligatorio y debe ser único" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "L'email est requis et doit être unique" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O email é obrigatório e deve ser único" + } + } + } + }, + "profile_first_name" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vorname" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "First Name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nombre" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prénom" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Primeiro Nome" + } + } + } + }, + "profile_free_plan" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kostenloser Plan" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Free Plan" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Plan Gratuito" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Plan Gratuit" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Plano Gratuito" + } + } + } + }, + "profile_last_name" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nachname" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Last Name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apellido" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nom de famille" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sobrenome" + } + } + } + }, + "profile_limited_features" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eingeschränkte Funktionen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limited features" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Funciones limitadas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fonctionnalités limitées" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recursos limitados" + } + } + } + }, + "profile_loading_profile" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profil wird geladen..." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loading profile..." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cargando perfil..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chargement du profil..." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carregando perfil..." + } + } + } + }, + "profile_logout" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abmelden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Log Out" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cerrar Sesión" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Se déconnecter" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sair" + } + } + } + }, + "profile_logout_confirm" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Möchten Sie sich wirklich abmelden?" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Are you sure you want to log out?" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿Seguro que quieres cerrar sesión?" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Êtes-vous sûr de vouloir vous déconnecter ?" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tem certeza que deseja sair?" + } + } + } + }, + "profile_manage_subscription" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abonnement verwalten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manage Subscription" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Administrar Suscripción" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gérer l'Abonnement" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gerenciar Assinatura" + } + } + } + }, + "profile_notification_preferences" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Benachrichtigungspräferenzen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notification Preferences" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Preferencias de Notificación" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Préférences de Notification" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Preferências de Notificação" + } + } + } + }, + "profile_notification_preferences_subtitle" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wählen Sie, welche Benachrichtigungen Sie erhalten möchten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Choose which notifications you'd like to receive" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Elige qué notificaciones te gustaría recibir" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Choisissez les notifications que vous souhaitez recevoir" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Escolha quais notificações você gostaria de receber" + } + } + } + }, + "profile_notifications" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Benachrichtigungen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notifications" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notificaciones" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notifications" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notificações" + } + } + } + }, + "profile_other_notifications" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Andere Benachrichtigungen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Other Notifications" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otras Notificaciones" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Autres Notifications" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Outras Notificações" + } + } + } + }, + "profile_personal_information" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Persönliche Informationen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Personal Information" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Información Personal" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informations Personnelles" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informações Pessoais" + } + } + } + }, + "profile_privacy" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datenschutz" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacidad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Confidentialité" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacidade" + } + } + } + }, + "profile_pro_plan" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pro-Plan" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pro Plan" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Plan Pro" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Plan Pro" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Plano Pro" + } + } + } + }, + "profile_profile_settings" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profileinstellungen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profile Settings" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configuración de Perfil" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Paramètres du Profil" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configurações de Perfil" + } + } + } + }, + "profile_property_shared" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie geteilt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Property Shared" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propiedad Compartida" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriété Partagée" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriedade Compartilhada" + } + } + } + }, + "profile_property_shared_description" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wenn jemand eine Immobilie mit Ihnen teilt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "When someone shares a property with you" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cuando alguien comparte una propiedad contigo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quand quelqu'un partage une propriété avec vous" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quando alguém compartilha uma propriedade com você" + } + } + } + }, + "profile_purchases_restored" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Käufe wiederhergestellt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Purchases Restored" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Compras Restauradas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Achats Restaurés" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Compras Restauradas" + } + } + } + }, + "profile_purchases_restored_message" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ihre Käufe wurden erfolgreich wiederhergestellt." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Your purchases have been restored successfully." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tus compras se han restaurado correctamente." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vos achats ont été restaurés avec succès." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suas compras foram restauradas com sucesso." + } + } + } + }, + "profile_restore_purchases" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Käufe wiederherstellen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Restore Purchases" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Restaurar Compras" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Restaurer les Achats" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Restaurar Compras" + } + } + } + }, + "profile_save_changes" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Änderungen speichern" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save Changes" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Guardar Cambios" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enregistrer les Modifications" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Salvar Alterações" + } + } + } + }, + "profile_subscription" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abonnement" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Subscription" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suscripción" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abonnement" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Assinatura" + } + } + } + }, + "profile_task_assigned" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabe zugewiesen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Task Assigned" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tarea Asignada" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tâche Assignée" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tarefa Atribuída" + } + } + } + }, + "profile_task_assigned_description" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wenn Ihnen eine Aufgabe zugewiesen wird" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "When a task is assigned to you" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cuando se te asigna una tarea" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quand une tâche vous est assignée" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quando uma tarefa é atribuída a você" + } + } + } + }, + "profile_task_completed" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabe abgeschlossen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Task Completed" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tarea Completada" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tâche Terminée" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tarefa Concluída" + } + } + } + }, + "profile_task_completed_description" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wenn jemand eine Aufgabe abschließt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "When someone completes a task" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cuando alguien completa una tarea" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quand quelqu'un termine une tâche" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quando alguém conclui uma tarefa" + } + } + } + }, + "profile_task_due_soon" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabe bald fällig" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Task Due Soon" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tarea Vence Pronto" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tâche Bientôt Due" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tarefa Vence em Breve" + } + } + } + }, + "profile_task_due_soon_description" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erinnerungen an bevorstehende Aufgaben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reminders for upcoming tasks" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recordatorios para tareas próximas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rappels pour les tâches à venir" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lembretes para tarefas próximas" + } + } + } + }, + "profile_task_notifications" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabenbenachrichtigungen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Task Notifications" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notificaciones de Tareas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notifications de Tâches" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notificações de Tarefas" + } + } + } + }, + "profile_task_overdue" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabe überfällig" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Task Overdue" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tarea Atrasada" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tâche en Retard" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tarefa Atrasada" + } + } + } + }, + "profile_task_overdue_description" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warnungen für überfällige Aufgaben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alerts for overdue tasks" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alertas para tareas atrasadas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alertes pour les tâches en retard" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alertas para tarefas atrasadas" + } + } + } + }, + "profile_theme" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thema" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Theme" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tema" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thème" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tema" + } + } + } + }, + "profile_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profil" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profile" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Perfil" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profil" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Perfil" + } + } + } + }, + "profile_upgrade_to_pro" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auf Pro upgraden" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Upgrade to Pro" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actualizar a Pro" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Passer à Pro" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Atualizar para Pro" + } + } + } + }, + "profile_version" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Version 1.0.0" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Version 1.0.0" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Versión 1.0.0" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Version 1.0.0" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Versão 1.0.0" + } + } + } + }, + "profile_warranty_expiring" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantie läuft ab" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warranty Expiring" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantía Venciendo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantie Expirant" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Garantia Expirando" + } + } + } + }, + "profile_warranty_expiring_description" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erinnerungen an ablaufende Garantien" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reminders for expiring warranties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recordatorios para garantías que vencen" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rappels pour les garanties expirant" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lembretes para garantias expirando" + } + } + } + }, + "properties_add_button" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add Property" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter une propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar Propriedade" + } + } + } + }, + "properties_add_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add Property" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter une propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar Propriedade" + } + } + } + }, + "properties_address_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adresse" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Address" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dirección" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adresse" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Endereço" + } + } + } + }, + "properties_delete_confirm" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Möchten Sie diese Immobilie wirklich löschen?" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Are you sure you want to delete this property?" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿Seguro que quieres eliminar esta propiedad?" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Êtes-vous sûr de vouloir supprimer cette propriété ?" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tem certeza que deseja excluir esta propriedade?" + } + } + } + }, + "properties_deleted" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie gelöscht" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Property deleted" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propiedad eliminada" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriété supprimée" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriedade excluída" + } + } + } + }, + "properties_edit_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie bearbeiten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit Property" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifier la propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Propriedade" + } + } + } + }, + "properties_empty_subtitle" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fügen Sie Ihre erste Immobilie hinzu!" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add your first property to get started!" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¡Agrega tu primera propiedad para comenzar!" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajoutez votre première propriété pour commencer !" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicione sua primeira propriedade para começar!" + } + } + } + }, + "properties_empty_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Immobilien" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No properties yet" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin propiedades" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem propriedades" + } + } + } + }, + "properties_name_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Name der Immobilie" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Property Name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nombre de la Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nom de la propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nome da Propriedade" + } + } + } + }, + "properties_notes_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notizen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas" + } + } + } + }, + "properties_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Meine Immobilien" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "My Properties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mis Propiedades" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mes Propriétés" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Minhas Propriedades" + } + } + } + }, + "properties_type_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilientyp" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Property Type" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tipo de Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Type de propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tipo de Propriedade" + } + } + } + }, + "Property #%d" : { + "comment" : "A fallback text that appears when the associated residence ID is not found in the user's residences. The placeholder number is replaced with the actual residence ID.", + "isCommentAutoGenerated" : true + }, + "Re-enter new password" : { + + }, + "Reset Password" : { + "comment" : "The title of the screen where users can reset their passwords.", + "isCommentAutoGenerated" : true + }, + "Residences" : { + "comment" : "A tab label for the \"Residences\" section in the main tab view.", + "isCommentAutoGenerated" : true + }, + "residences_add_contractors_prompt" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auftragnehmer aus der Registerkarte 'Auftragnehmer' hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add contractors from the Contractors tab" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar contratistas desde la pestaña Contratistas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter des entrepreneurs depuis l'onglet Entrepreneurs" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar empreiteiros da aba Empreiteiros" + } + } + } + }, + "residences_add_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add Residence" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter une Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar Propriedade" + } + } + } + }, + "residences_additional_details" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zusätzliche Details" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Additional Details" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Detalles Adicionales" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Détails Supplémentaires" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Detalhes Adicionais" + } + } + } + }, + "residences_address" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adresse" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Address" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dirección" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adresse" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Endereço" + } + } + } + }, + "residences_apartment_unit" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wohnung/Einheit (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apartment/Unit (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apartamento/Unidad (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appartement/Unité (optionnel)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apartamento/Unidade (opcional)" + } + } + } + }, + "residences_bathrooms" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Badezimmer" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bathrooms" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baños" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Salles de bain" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Banheiros" + } + } + } + }, + "residences_bedrooms" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Schlafzimmer" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bedrooms" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dormitorios" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chambres" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quartos" + } + } + } + }, + "residences_city" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stadt" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "City" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciudad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ville" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cidade" + } + } + } + }, + "residences_contractors" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auftragnehmer" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contractors" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contratistas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrepreneurs" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Empreiteiros" + } + } + } + }, + "residences_country" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Land" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Country" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "País" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pays" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "País" + } + } + } + }, + "residences_delete_confirm_message" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sind Sie sicher, dass Sie diese Immobilie löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden und löscht alle zugehörigen Aufgaben, Dokumente und Daten." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Are you sure you want to delete this property? This action cannot be undone and will delete all associated tasks, documents, and data." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿Está seguro de que desea eliminar esta propiedad? Esta acción no se puede deshacer y eliminará todas las tareas, documentos y datos asociados." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Êtes-vous sûr de vouloir supprimer cette propriété ? Cette action ne peut pas être annulée et supprimera toutes les tâches, documents et données associés." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tem certeza de que deseja excluir esta propriedade? Esta ação não pode ser desfeita e excluirá todas as tarefas, documentos e dados associados." + } + } + } + }, + "residences_delete_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie löschen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete Residence" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eliminar Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Supprimer la Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Excluir Propriedade" + } + } + } + }, + "residences_description" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beschreibung (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Description (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descripción (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Description (optionnel)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descrição (opcional)" + } + } + } + }, + "residences_edit_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie bearbeiten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit Residence" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifier la Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Propriedade" + } + } + } + }, + "residences_enter_share_code" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Freigabecode eingeben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter Share Code" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Introducir Código de Compartir" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrer le Code de Partage" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inserir Código de Compartilhamento" + } + } + } + }, + "residences_error_loading_tasks" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fehler beim Laden der Aufgaben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error loading tasks" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error al cargar tareas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erreur lors du chargement des tâches" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erro ao carregar tarefas" + } + } + } + }, + "residences_generate" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erstellen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Generate" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Generar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Générer" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gerar" + } + } + } + }, + "residences_generate_report" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bericht erstellen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Generate Report" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Generar Informe" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Générer un Rapport" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gerar Relatório" + } + } + } + }, + "residences_generate_report_message" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dies erstellt einen umfassenden Bericht über Ihre Immobilie einschließlich aller Aufgaben, Dokumente und Auftragnehmer." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This will generate a comprehensive report of your property including all tasks, documents, and contractors." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Esto generará un informe completo de su propiedad incluyendo todas las tareas, documentos y contratistas." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cela générera un rapport complet de votre propriété incluant toutes les tâches, documents et entrepreneurs." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Isso gerará um relatório abrangente da sua propriedade incluindo todas as tarefas, documentos e empreiteiros." + } + } + } + }, + "residences_join_button" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie beitreten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Join Residence" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unirse a Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rejoindre la Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Participar da Propriedade" + } + } + } + }, + "residences_join_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie beitreten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Join Residence" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unirse a Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rejoindre la Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Participar da Propriedade" + } + } + } + }, + "residences_loading_residence" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie wird geladen..." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loading residence..." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cargando propiedad..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chargement de la propriété..." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carregando propriedade..." + } + } + } + }, + "residences_loading_tasks" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgaben werden geladen..." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loading tasks..." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cargando tareas..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chargement des tâches..." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carregando tarefas..." + } + } + } + }, + "residences_lot_size" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Grundstücksgröße (Hektar)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lot Size (acres)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tamaño del Lote (acres)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Taille du Terrain (acres)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tamanho do Lote (acres)" + } + } + } + }, + "residences_maintenance_report" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wartungsbericht" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Maintenance Report" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informe de Mantenimiento" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rapport de Maintenance" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Relatório de Manutenção" + } + } + } + }, + "residences_manage_users" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Benutzer verwalten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manage Users" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Administrar Usuarios" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gérer les Utilisateurs" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gerenciar Usuários" + } + } + } + }, + "residences_name_required" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Name ist erforderlich" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Name is required" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El nombre es obligatorio" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le nom est requis" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O nome é obrigatório" + } + } + } + }, + "residences_no_contractors" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Noch keine Auftragnehmer" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No contractors yet" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aún no hay contratistas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pas encore d'entrepreneurs" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ainda não há empreiteiros" + } + } + } + }, + "residences_postal_code" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Postleitzahl" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Postal Code" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Código Postal" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Code Postal" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Código Postal" + } + } + } + }, + "residences_primary_residence" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hauptwohnsitz" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Primary Residence" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Residencia Principal" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Résidence Principale" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Residência Principal" + } + } + } + }, + "residences_properties" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilien" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "properties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "propiedades" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "propriétés" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "propriedades" + } + } + } + }, + "residences_property" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "property" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "propriedade" + } + } + } + }, + "residences_property_details" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobiliendetails" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Property Details" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Detalles de la Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Détails de la Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Detalhes da Propriedade" + } + } + } + }, + "residences_property_features" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilienmerkmale" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Property Features" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Características de la Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Caractéristiques de la Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Características da Propriedade" + } + } + } + }, + "residences_property_name" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilienname" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Property Name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nombre de la Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nom de la Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nome da Propriedade" + } + } + } + }, + "residences_property_type" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilientyp" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Property Type" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tipo de Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Type de Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tipo de Propriedade" + } + } + } + }, + "residences_required_name" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erforderlich: Name" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Required: Name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requerido: Nombre" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requis : Nom" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obrigatório: Nome" + } + } + } + }, + "residences_select_type" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Typ auswählen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select Type" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar Tipo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionner le Type" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecionar Tipo" + } + } + } + }, + "residences_share_code" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Freigabecode" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Share Code" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Código de Compartir" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Code de Partage" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Código de Compartilhamento" + } + } + } + }, + "residences_share_code_footer" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geben Sie den 6-stelligen Code ein, der mit Ihnen geteilt wurde, um einer Immobilie beizutreten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter the 6-character code shared with you to join a residence" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingrese el código de 6 caracteres compartido con usted para unirse a una propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrez le code à 6 caractères partagé avec vous pour rejoindre une propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insira o código de 6 caracteres compartilhado com você para participar de uma propriedade" + } + } + } + }, + "residences_share_code_must_6" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Der Freigabecode muss 6 Zeichen lang sein" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Share code must be 6 characters" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El código de compartir debe tener 6 caracteres" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le code de partage doit comporter 6 caractères" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O código de compartilhamento deve ter 6 caracteres" + } + } + } + }, + "residences_square_footage" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quadratmeter" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Square Footage" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Metros Cuadrados" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Surface en pieds carrés" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Área em pés quadrados" + } + } + } + }, + "residences_state_province" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bundesland/Provinz" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "State/Province" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estado/Provincia" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "État/Province" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estado/Província" + } + } + } + }, + "residences_street_address" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Straßenadresse" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Street Address" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dirección" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adresse" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Endereço" + } + } + } + }, + "residences_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Meine Immobilien" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "My Properties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mis Propiedades" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mes Propriétés" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Minhas Propriedades" + } + } + } + }, + "residences_users" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Benutzer" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Users" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Usuarios" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Utilisateurs" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Usuários" + } + } + } + }, + "residences_year_built" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baujahr" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Year Built" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Año de Construcción" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Année de Construction" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ano de Construção" + } + } + } + }, + "residences_your_properties" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ihre Immobilien" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Your Properties" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tus Propiedades" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vos Propriétés" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suas Propriedades" + } + } + } + }, + "Restore" : { + "comment" : "A button that restores a cancelled task.", + "isCommentAutoGenerated" : true + }, + "Restore Purchases" : { + "comment" : "A button label that allows users to restore previous purchases.", + "isCommentAutoGenerated" : true + }, + "Restore Task" : { + "comment" : "A button that restores a cancelled or archived task.", + "isCommentAutoGenerated" : true + }, + "Retry" : { + "comment" : "A button label that says \"Retry\".", + "isCommentAutoGenerated" : true + }, + "Retry Loading Products" : { + "comment" : "A button label that appears when the app is unable to load in-app purchase products. It instructs the user to try again.", + "isCommentAutoGenerated" : true + }, + "Return to Login" : { + + }, + "Send New Code" : { + "comment" : "A button label that allows a user to request a new verification code.", + "isCommentAutoGenerated" : true + }, + "Send Reset Code" : { + "comment" : "A button label that says \"Send Reset Code\".", + "isCommentAutoGenerated" : true + }, + "Set New Password" : { + + }, + "settings_language" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sprache" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Language" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Idioma" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Langue" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Idioma" + } + } + } + }, + "settings_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Einstellungen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Settings" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configuración" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Paramètres" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configurações" + } + } + } + }, + "Share Code" : { + "comment" : "A label displayed above the share code section of the view.", + "isCommentAutoGenerated" : true + }, + "Share this code with others to give them access to %@" : { + "comment" : "A caption below the share code, explaining that it can be shared with others to give them access to a residence. The argument is the name of the residence.", + "isCommentAutoGenerated" : true + }, + "Something went wrong" : { + "comment" : "A description of an error that occurs during an asynchronous operation.", + "isCommentAutoGenerated" : true + }, + "Start managing your properties today" : { + "comment" : "A description below the title of the screen.", + "isCommentAutoGenerated" : true + }, + "Subscription Active" : { + "comment" : "The title of an alert that appears when a user successfully upgrades to a premium subscription.", + "isCommentAutoGenerated" : true + }, + "Tasks" : { + "comment" : "A label displayed above the list of task categories.", + "isCommentAutoGenerated" : true + }, + "tasks_actual_cost" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tatsächliche Kosten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actual Cost" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Costo Real" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Coût Réel" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Custo Real" + } + } + } + }, + "tasks_add_button" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabe hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add Task" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar Tarea" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter une tâche" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar Tarefa" + } + } + } + }, + "tasks_add_photos" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fügen Sie bis zu 5 Fotos hinzu, die die abgeschlossene Arbeit dokumentieren." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add up to 5 photos documenting the completed work." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agrega hasta 5 fotos documentando el trabajo completado." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajoutez jusqu'à 5 photos documentant le travail terminé." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicione até 5 fotos documentando o trabalho concluído." + } + } + } + }, + "tasks_add_property_first" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fügen Sie zuerst eine Immobilie aus dem Tab Residenzen hinzu" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add a property first from the Residences tab" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agrega una propiedad primero desde la pestaña Residencias" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajoutez d'abord une propriété depuis l'onglet Résidences" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicione uma propriedade primeiro na aba Residências" + } + } + } + }, + "tasks_add_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabe hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add Task" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar Tarea" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter une tâche" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar Tarefa" + } + } + } + }, + "tasks_all_tasks" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alle Aufgaben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "All Tasks" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Todas las Tareas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toutes les Tâches" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Todas as Tarefas" + } + } + } + }, + "tasks_archive" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Archivieren" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Archive" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Archivar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Archiver" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Arquivar" + } + } + } + }, + "tasks_archive_confirm" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Möchten Sie diese Aufgabe wirklich archivieren? Sie können sie später aus archivierten Aufgaben wiederherstellen." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Are you sure you want to archive this task? You can unarchive it later from archived tasks." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿Estás seguro de que quieres archivar esta tarea? Puedes desarchivarla más tarde desde tareas archivadas." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Êtes-vous sûr de vouloir archiver cette tâche ? Vous pouvez la désarchiver plus tard depuis les tâches archivées." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tem certeza de que deseja arquivar esta tarefa? Você pode desarquivá-la mais tarde nas tarefas arquivadas." + } + } + } + }, + "tasks_archive_task" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabe Archivieren" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Archive Task" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Archivar Tarea" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Archiver la Tâche" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Arquivar Tarefa" + } + } + } + }, + "tasks_both_required" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erforderlich: Priorität und Status" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Required: Both Priority and Status" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requerido: Prioridad y Estado" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requis: Priorité et Statut" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obrigatório: Prioridade e Status" + } + } + } + }, + "tasks_cancel" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abbrechen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancel" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancelar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Annuler" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancelar" + } + } + } + }, + "tasks_category" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kategorie" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Category" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Categoría" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Catégorie" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Categoria" + } + } + } + }, + "tasks_complete" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abschließen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Complete" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Completar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Terminer" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Concluir" + } + } + } + }, + "tasks_complete_task" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabe Abschließen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Complete Task" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Completar Tarea" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Terminer la Tâche" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Concluir Tarefa" + } + } + } + }, + "tasks_completed_by" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abgeschlossen Von" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Completed By" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Completado Por" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Terminé Par" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Concluído Por" + } + } + } + }, + "tasks_completed_by_name" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abgeschlossen von" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Completed by" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Completado por" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Terminé par" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Concluído por" + } + } + } + }, + "tasks_completion" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abschluss" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "completion" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "completado" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "achèvement" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "conclusão" + } + } + } + }, + "tasks_completion_history" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abschlussverlauf" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Completion History" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Historial de Completado" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Historique d'Achèvement" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Histórico de Conclusão" + } + } + } + }, + "tasks_completions" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abschlüsse" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "completions" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "completados" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "achèvements" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "conclusões" + } + } + } + }, + "tasks_contractor_helper" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wählen Sie einen Auftragnehmer aus, wenn er diese Arbeit abgeschlossen hat, oder lassen Sie es für manuelle Eingabe leer." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select a contractor if they completed this work, or leave blank for manual entry." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecciona un contratista si completó este trabajo, o déjalo en blanco para entrada manual." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionnez un entrepreneur s'il a terminé ce travail, ou laissez vide pour une saisie manuelle." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecione um empreiteiro se ele concluiu este trabalho, ou deixe em branco para entrada manual." + } + } + } + }, + "tasks_contractor_optional" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auftragnehmer (Optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contractor (Optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contratista (Opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrepreneur (Optionnel)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Empreiteiro (Opcional)" + } + } + } + }, + "tasks_cost" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kosten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cost" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Costo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Coût" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Custo" + } + } + } + }, + "tasks_create_first" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erstellen Sie Ihre erste Aufgabe, um zu beginnen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Create your first task to get started" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Crea tu primera tarea para comenzar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Créez votre première tâche pour commencer" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Crie sua primeira tarefa para começar" + } + } + } + }, + "tasks_custom_interval" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Benutzerdefiniertes Intervall (Tage, optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Custom Interval (days, optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Intervalo Personalizado (días, opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Intervalle Personnalisé (jours, optionnel)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Intervalo Personalizado (dias, opcional)" + } + } + } + }, + "tasks_delete_confirm" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Möchten Sie diese Aufgabe wirklich löschen?" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Are you sure you want to delete this task?" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿Seguro que quieres eliminar esta tarea?" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Êtes-vous sûr de vouloir supprimer cette tâche ?" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tem certeza que deseja excluir esta tarefa?" + } + } + } + }, + "tasks_delete_task" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabe Löschen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete Task" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eliminar Tarea" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Supprimer la Tâche" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Excluir Tarefa" + } + } + } + }, + "tasks_description_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beschreibung" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Description" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descripción" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Description" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descrição" + } + } + } + }, + "tasks_description_optional" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beschreibung (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Description (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descripción (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Description (optionnelle)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descrição (opcional)" + } + } + } + }, + "tasks_due_date" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fälligkeitsdatum" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Due Date" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fecha de Vencimiento" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Date d'Échéance" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Data de Vencimento" + } + } + } + }, + "tasks_edit" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bearbeiten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifier" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar" + } + } + } + }, + "tasks_edit_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabe bearbeiten" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit Task" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Tarea" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifier la tâche" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar Tarefa" + } + } + } + }, + "tasks_empty_subtitle" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fügen Sie Ihre erste Wartungsaufgabe hinzu" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add your first maintenance task" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agrega tu primera tarea de mantenimiento" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajoutez votre première tâche de maintenance" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicione sua primeira tarefa de manutenção" + } + } + } + }, + "tasks_empty_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Aufgaben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No tasks yet" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin tareas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune tâche" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem tarefas" + } + } + } + }, + "tasks_enter_manually" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Name manuell eingeben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter name manually" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingresar nombre manualmente" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entrer le nom manuellement" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inserir nome manualmente" + } + } + } + }, + "tasks_error" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fehler" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erreur" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erro" + } + } + } + }, + "tasks_estimated_cost" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geschätzte Kosten (optional)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estimated Cost (optional)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Costo Estimado (opcional)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Coût Estimé (optionnel)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Custo Estimado (opcional)" + } + } + } + }, + "tasks_failed_to_load" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fehler beim Laden der Abschlüsse" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Failed to load completions" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error al cargar completados" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Échec du chargement des achèvements" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Falha ao carregar conclusões" + } + } + } + }, + "tasks_frequency" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Häufigkeit" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Frequency" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Frecuencia" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fréquence" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Frequência" + } + } + } + }, + "tasks_in_progress" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "In Bearbeitung" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "In Progress" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "En Progreso" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "En Cours" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Em Andamento" + } + } + } + }, + "tasks_library" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bibliothek" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Library" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Biblioteca" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bibliothèque" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Biblioteca" + } + } + } + }, + "tasks_loading" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Laden..." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loading..." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cargando..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chargement..." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carregando..." + } + } + } + }, + "tasks_loading_completions" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abschlüsse werden geladen..." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loading completions..." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cargando completados..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chargement des achèvements..." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carregando conclusões..." + } + } + } + }, + "tasks_no_completions_yet" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Noch Keine Abschlüsse" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No Completions Yet" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aún No Hay Completados" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucun Achèvement Pour le Moment" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ainda Não Há Conclusões" + } + } + } + }, + "tasks_no_tasks" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Aufgaben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No tasks" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin tareas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune tâche" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem tarefas" + } + } + } + }, + "tasks_no_tasks_yet" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Noch keine Aufgaben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No tasks yet" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aún no hay tareas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune tâche pour le moment" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ainda não há tarefas" + } + } + } + }, + "tasks_none" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "None" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ninguno" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucun" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nenhum" + } + } + } + }, + "tasks_none_manual" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine (Manuelle Eingabe)" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "None (Manual Entry)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ninguno (Entrada Manual)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucun (Saisie Manuelle)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nenhum (Entrada Manual)" + } + } + } + }, + "tasks_not_completed" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Diese Aufgabe wurde noch nicht abgeschlossen." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This task has not been completed." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Esta tarea no ha sido completada." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cette tâche n'a pas été terminée." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Esta tarefa não foi concluída." + } + } + } + }, + "tasks_notes" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notizen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas" + } + } + } + }, + "tasks_optional_details" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fügen Sie beliebige zusätzliche Details zum Abschluss dieser Aufgabe hinzu." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add any additional details about completing this task." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agrega cualquier detalle adicional sobre completar esta tarea." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajoutez tous les détails supplémentaires sur l'achèvement de cette tâche." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicione quaisquer detalhes adicionais sobre a conclusão desta tarefa." + } + } + } + }, + "tasks_optional_info" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Optionale Informationen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Optional Information" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Información Opcional" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informations Optionnelles" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informações Opcionais" + } + } + } + }, + "tasks_optional_notes" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Optionale Notizen über die abgeschlossene Arbeit." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Optional notes about the work completed." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas opcionales sobre el trabajo completado." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notes optionnelles sur le travail effectué." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notas opcionais sobre o trabalho concluído." + } + } + } + }, + "tasks_photos" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fotos" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Photos" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fotos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Photos" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fotos" + } + } + } + }, + "tasks_priority" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Priorität" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Priority" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prioridad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Priorité" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prioridade" + } + } + } + }, + "tasks_priority_status" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Priorität & Status" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Priority & Status" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prioridad y Estado" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Priorité et Statut" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prioridade e Status" + } + } + } + }, + "tasks_property" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Property" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Propriedade" + } + } + } + }, + "tasks_quality_rating" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Qualitätsbewertung" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quality Rating" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Calificación de Calidad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Note de Qualité" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avaliação de Qualidade" + } + } + } + }, + "tasks_rate_quality" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bewerten Sie die Arbeitsqualität von 1 bis 5 Sternen." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rate the quality of work from 1 to 5 stars." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Califica la calidad del trabajo de 1 a 5 estrellas." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Évaluez la qualité du travail de 1 à 5 étoiles." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avalie a qualidade do trabalho de 1 a 5 estrelas." + } + } + } + }, + "tasks_required" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erforderlich" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Required" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requerido" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requis" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obrigatório" + } + } + } + }, + "tasks_restore" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wiederherstellen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Restore" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Restaurar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Restaurer" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Restaurar" + } + } + } + }, + "tasks_scheduling" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Terminplanung" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Scheduling" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Programación" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Planification" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agendamento" + } + } + } + }, + "tasks_select_category" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kategorie Auswählen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select Category" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar Categoría" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionner la Catégorie" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecionar Categoria" + } + } + } + }, + "tasks_select_contractor" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auftragnehmer Auswählen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select Contractor" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar Contratista" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionner l'Entrepreneur" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecionar Empreiteiro" + } + } + } + }, + "tasks_select_frequency" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Häufigkeit Auswählen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select Frequency" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar Frecuencia" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionner la Fréquence" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecionar Frequência" + } + } + } + }, + "tasks_select_priority" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Priorität Auswählen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select Priority" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar Prioridad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionner la Priorité" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecionar Prioridade" + } + } + } + }, + "tasks_select_property" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immobilie Auswählen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select Property" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar Propiedad" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionner la Propriété" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecionar Propriedade" + } + } + } + }, + "tasks_select_status" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Status Auswählen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select Status" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar Estado" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sélectionner le Statut" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selecionar Status" + } + } + } + }, + "tasks_status" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Status" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Status" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estado" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Statut" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Status" + } + } + } + }, + "tasks_take_photo" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Foto Aufnehmen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Take Photo" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tomar Foto" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prendre une Photo" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tirar Foto" + } + } + } + }, + "tasks_task_details" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabendetails" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Task Details" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Detalles de la Tarea" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Détails de la Tâche" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Detalhes da Tarefa" + } + } + } + }, + "tasks_title" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgaben" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tasks" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tareas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tâches" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tarefas" + } + } + } + }, + "tasks_title_label" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufgabentitel" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Task Title" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Título de la Tarea" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Titre de la tâche" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Título da Tarefa" + } + } + } + }, + "tasks_title_required" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erforderlich: Titel" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Required: Title" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requerido: Título" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requis: Titre" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obrigatório: Título" + } + } + } + }, + "tasks_unarchive" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wiederherstellen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unarchive" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desarchivar" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Désarchiver" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desarquivar" + } + } + } + }, + "tasks_view_photos" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fotos Ansehen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "View Photos" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ver Fotos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Voir les Photos" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ver Fotos" + } + } + } + }, + "tasks_your_name" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ihr Name" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Your name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tu nombre" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Votre nom" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seu nome" + } + } + } + }, + "Try Again" : { + "comment" : "A button label that says \"Try Again\".", + "isCommentAutoGenerated" : true + }, + "Unarchive" : { + "comment" : "A button that unarchives a task.", + "isCommentAutoGenerated" : true + }, + "Unarchive Task" : { + + }, + "Upgrade to Pro" : { + "comment" : "A button label that says \"Upgrade to Pro\".", + "isCommentAutoGenerated" : true + }, + "Upgrade to Pro for unlimited access" : { + "comment" : "A description of the benefit of upgrading to the Pro plan.", + "isCommentAutoGenerated" : true + }, + "Verification Code" : { + "comment" : "A label displayed above the text field for entering a verification code.", + "isCommentAutoGenerated" : true + }, + "Verify Code" : { + "comment" : "A button that verifies a user's reset code.", + "isCommentAutoGenerated" : true + }, + "View Photos (%lld)" : { + "comment" : "A button that, when tapped, opens a view displaying photos taken during a task completion. The number in parentheses is replaced with the actual number of photos.", + "isCommentAutoGenerated" : true + }, + "We sent a 6-digit code to" : { + "comment" : "A message explaining that a verification code has been sent to their email.", + "isCommentAutoGenerated" : true + }, + "We'll send a 6-digit verification code to this address" : { + "comment" : "A footer label within the \"Forgot Password?\" view, instructing the user to check their email for a verification code.", + "isCommentAutoGenerated" : true + }, + "You now have full access to all Pro features!" : { + "comment" : "A message displayed to users after successfully upgrading to the Pro version of the app.", + "isCommentAutoGenerated" : true + } + }, + "version" : "1.1" +} \ No newline at end of file diff --git a/iosApp/iosApp/Login/LoginView.swift b/iosApp/iosApp/Login/LoginView.swift index 89a0163..a978a55 100644 --- a/iosApp/iosApp/Login/LoginView.swift +++ b/iosApp/iosApp/Login/LoginView.swift @@ -59,11 +59,11 @@ struct LoginView: View { } VStack(spacing: AppSpacing.xs) { - Text("Welcome Back") + Text(L10n.Auth.welcomeBack) .font(.title2.weight(.bold)) .foregroundColor(Color.appTextPrimary) - Text("Sign in to manage your properties") + Text(L10n.Auth.signInSubtitle) .font(.body) .foregroundColor(Color.appTextSecondary) } @@ -73,7 +73,7 @@ struct LoginView: View { VStack(spacing: AppSpacing.lg) { // Username Field VStack(alignment: .leading, spacing: AppSpacing.xs) { - Text("Email or Username") + Text(L10n.Auth.loginUsernameLabel) .font(.subheadline.weight(.medium)) .foregroundColor(Color.appTextSecondary) @@ -82,7 +82,7 @@ struct LoginView: View { .foregroundColor(Color.appTextSecondary) .frame(width: 20) - TextField("Enter your email", text: $viewModel.username) + TextField(L10n.Auth.enterEmail, text: $viewModel.username) .textInputAutocapitalization(.never) .autocorrectionDisabled() .keyboardType(.emailAddress) @@ -110,7 +110,7 @@ struct LoginView: View { // Password Field VStack(alignment: .leading, spacing: AppSpacing.xs) { - Text("Password") + Text(L10n.Auth.loginPasswordLabel) .font(.subheadline.weight(.medium)) .foregroundColor(Color.appTextSecondary) @@ -121,7 +121,7 @@ struct LoginView: View { Group { if isPasswordVisible { - TextField("Enter your password", text: $viewModel.password) + TextField(L10n.Auth.enterPassword, text: $viewModel.password) .textInputAutocapitalization(.never) .autocorrectionDisabled() .textContentType(.password) @@ -132,7 +132,7 @@ struct LoginView: View { } .accessibilityIdentifier(AccessibilityIdentifiers.Authentication.passwordField) } else { - SecureField("Enter your password", text: $viewModel.password) + SecureField(L10n.Auth.enterPassword, text: $viewModel.password) .textContentType(.password) .focused($focusedField, equals: .password) .submitLabel(.go) @@ -169,7 +169,7 @@ struct LoginView: View { // Forgot Password HStack { Spacer() - Button("Forgot Password?") { + Button(L10n.Auth.forgotPassword) { showPasswordReset = true } .font(.subheadline.weight(.medium)) @@ -204,7 +204,7 @@ struct LoginView: View { Rectangle() .fill(Color.appTextSecondary.opacity(0.3)) .frame(height: 1) - Text("or") + Text(L10n.Auth.orDivider) .font(.subheadline) .foregroundColor(Color.appTextSecondary) .padding(.horizontal, AppSpacing.sm) @@ -241,7 +241,7 @@ struct LoginView: View { HStack { ProgressView() .progressViewStyle(CircularProgressViewStyle()) - Text("Signing in with Apple...") + Text(L10n.Auth.signingInWithApple) .font(.subheadline) .foregroundColor(Color.appTextSecondary) } @@ -265,11 +265,11 @@ struct LoginView: View { // Sign Up Link HStack(spacing: AppSpacing.xs) { - Text("Don't have an account?") + Text(L10n.Auth.dontHaveAccount) .font(.body) .foregroundColor(Color.appTextSecondary) - Button("Sign Up") { + Button(L10n.Auth.signUp) { showingRegister = true } .font(.body) @@ -357,7 +357,7 @@ struct LoginView: View { ProgressView() .progressViewStyle(CircularProgressViewStyle(tint: .white)) } - Text(viewModel.isLoading ? "Signing In..." : "Sign In") + Text(viewModel.isLoading ? L10n.Auth.signingIn : L10n.Auth.loginButton) .font(.headline) .fontWeight(.semibold) } diff --git a/iosApp/iosApp/Profile/NotificationPreferencesView.swift b/iosApp/iosApp/Profile/NotificationPreferencesView.swift index b94bbf4..36dafb7 100644 --- a/iosApp/iosApp/Profile/NotificationPreferencesView.swift +++ b/iosApp/iosApp/Profile/NotificationPreferencesView.swift @@ -15,12 +15,12 @@ struct NotificationPreferencesView: View { .font(.system(size: 60)) .foregroundStyle(Color.appPrimary.gradient) - Text("Notification Preferences") + Text(L10n.Profile.notificationPreferences) .font(.title2) .fontWeight(.bold) .foregroundColor(Color.appTextPrimary) - Text("Choose which notifications you'd like to receive") + Text(L10n.Profile.notificationPreferencesSubtitle) .font(.subheadline) .foregroundColor(Color.appTextSecondary) .multilineTextAlignment(.center) @@ -51,7 +51,7 @@ struct NotificationPreferencesView: View { .font(.subheadline) } - Button("Retry") { + Button(L10n.Common.retry) { viewModel.loadPreferences() } .foregroundColor(Color.appPrimary) @@ -63,9 +63,9 @@ struct NotificationPreferencesView: View { Toggle(isOn: $viewModel.taskDueSoon) { Label { VStack(alignment: .leading, spacing: 2) { - Text("Task Due Soon") + Text(L10n.Profile.taskDueSoon) .foregroundColor(Color.appTextPrimary) - Text("Reminders for upcoming tasks") + Text(L10n.Profile.taskDueSoonDescription) .font(.caption) .foregroundColor(Color.appTextSecondary) } @@ -82,9 +82,9 @@ struct NotificationPreferencesView: View { Toggle(isOn: $viewModel.taskOverdue) { Label { VStack(alignment: .leading, spacing: 2) { - Text("Task Overdue") + Text(L10n.Profile.taskOverdue) .foregroundColor(Color.appTextPrimary) - Text("Alerts for overdue tasks") + Text(L10n.Profile.taskOverdueDescription) .font(.caption) .foregroundColor(Color.appTextSecondary) } @@ -101,9 +101,9 @@ struct NotificationPreferencesView: View { Toggle(isOn: $viewModel.taskCompleted) { Label { VStack(alignment: .leading, spacing: 2) { - Text("Task Completed") + Text(L10n.Profile.taskCompleted) .foregroundColor(Color.appTextPrimary) - Text("When someone completes a task") + Text(L10n.Profile.taskCompletedDescription) .font(.caption) .foregroundColor(Color.appTextSecondary) } @@ -120,9 +120,9 @@ struct NotificationPreferencesView: View { Toggle(isOn: $viewModel.taskAssigned) { Label { VStack(alignment: .leading, spacing: 2) { - Text("Task Assigned") + Text(L10n.Profile.taskAssigned) .foregroundColor(Color.appTextPrimary) - Text("When a task is assigned to you") + Text(L10n.Profile.taskAssignedDescription) .font(.caption) .foregroundColor(Color.appTextSecondary) } @@ -136,7 +136,7 @@ struct NotificationPreferencesView: View { viewModel.updatePreference(taskAssigned: newValue) } } header: { - Text("Task Notifications") + Text(L10n.Profile.taskNotifications) } .listRowBackground(Color.appBackgroundSecondary) @@ -145,9 +145,9 @@ struct NotificationPreferencesView: View { Toggle(isOn: $viewModel.residenceShared) { Label { VStack(alignment: .leading, spacing: 2) { - Text("Property Shared") + Text(L10n.Profile.propertyShared) .foregroundColor(Color.appTextPrimary) - Text("When someone shares a property with you") + Text(L10n.Profile.propertySharedDescription) .font(.caption) .foregroundColor(Color.appTextSecondary) } @@ -172,9 +172,9 @@ struct NotificationPreferencesView: View { Toggle(isOn: $viewModel.warrantyExpiring) { Label { VStack(alignment: .leading, spacing: 2) { - Text("Warranty Expiring") + Text(L10n.Profile.warrantyExpiring) .foregroundColor(Color.appTextPrimary) - Text("Reminders for expiring warranties") + Text(L10n.Profile.warrantyExpiringDescription) .font(.caption) .foregroundColor(Color.appTextSecondary) } @@ -188,7 +188,7 @@ struct NotificationPreferencesView: View { viewModel.updatePreference(warrantyExpiring: newValue) } } header: { - Text("Other Notifications") + Text(L10n.Profile.otherNotifications) } .listRowBackground(Color.appBackgroundSecondary) } @@ -196,11 +196,11 @@ struct NotificationPreferencesView: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle("Notifications") + .navigationTitle(L10n.Profile.notifications) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Done") { + Button(L10n.Common.done) { dismiss() } .foregroundColor(Color.appPrimary) diff --git a/iosApp/iosApp/Profile/ProfileTabView.swift b/iosApp/iosApp/Profile/ProfileTabView.swift index dd1698a..e076ae7 100644 --- a/iosApp/iosApp/Profile/ProfileTabView.swift +++ b/iosApp/iosApp/Profile/ProfileTabView.swift @@ -35,11 +35,11 @@ struct ProfileTabView: View { // .listRowBackground(Color.appBackgroundSecondary) // } - Section("Account") { + Section(L10n.Profile.account) { Button(action: { showingProfileEdit = true }) { - Label("Edit Profile", systemImage: "person.crop.circle") + Label(L10n.Profile.editProfile, systemImage: "person.crop.circle") .foregroundColor(Color.appTextPrimary) } @@ -47,7 +47,7 @@ struct ProfileTabView: View { showingNotificationPreferences = true }) { HStack { - Label("Notifications", systemImage: "bell") + Label(L10n.Profile.notifications, systemImage: "bell") .foregroundColor(Color.appTextPrimary) Spacer() Image(systemName: "chevron.right") @@ -56,31 +56,31 @@ struct ProfileTabView: View { } } - NavigationLink(destination: Text("Privacy")) { - Label("Privacy", systemImage: "lock.shield") + NavigationLink(destination: Text(L10n.Profile.privacy)) { + Label(L10n.Profile.privacy, systemImage: "lock.shield") } } .listRowBackground(Color.appBackgroundSecondary) // Subscription Section - Only show if limitations are enabled on backend if let subscription = subscriptionCache.currentSubscription, subscription.limitationsEnabled { - Section("Subscription") { + Section(L10n.Profile.subscription) { HStack { Image(systemName: "crown.fill") .foregroundColor(subscriptionCache.currentTier == "pro" ? Color.appAccent : Color.appTextSecondary) VStack(alignment: .leading, spacing: 4) { - Text(subscriptionCache.currentTier == "pro" ? "Pro Plan" : "Free Plan") + Text(subscriptionCache.currentTier == "pro" ? L10n.Profile.proPlan : L10n.Profile.freePlan) .font(.headline) .foregroundColor(Color.appTextPrimary) if subscriptionCache.currentTier == "pro", let expiresAt = subscription.expiresAt { - Text("Active until \(DateUtils.formatDateMedium(expiresAt))") + Text("\(L10n.Profile.activeUntil) \(DateUtils.formatDateMedium(expiresAt))") .font(.caption) .foregroundColor(Color.appTextSecondary) } else { - Text("Limited features") + Text(L10n.Profile.limitedFeatures) .font(.caption) .foregroundColor(Color.appTextSecondary) } @@ -90,7 +90,7 @@ struct ProfileTabView: View { if subscriptionCache.currentTier != "pro" { Button(action: { showUpgradePrompt = true }) { - Label("Upgrade to Pro", systemImage: "arrow.up.circle.fill") + Label(L10n.Profile.upgradeToPro, systemImage: "arrow.up.circle.fill") .foregroundColor(Color.appPrimary) } } else { @@ -99,7 +99,7 @@ struct ProfileTabView: View { UIApplication.shared.open(url) } }) { - Label("Manage Subscription", systemImage: "gearshape.fill") + Label(L10n.Profile.manageSubscription, systemImage: "gearshape.fill") .foregroundColor(Color.appTextPrimary) } } @@ -110,19 +110,19 @@ struct ProfileTabView: View { showRestoreSuccess = true } }) { - Label("Restore Purchases", systemImage: "arrow.clockwise") + Label(L10n.Profile.restorePurchases, systemImage: "arrow.clockwise") .foregroundColor(Color.appTextSecondary) } } .listRowBackground(Color.appBackgroundSecondary) } - Section("Appearance") { + Section(L10n.Profile.appearance) { Button(action: { showingThemeSelection = true }) { HStack { - Label("Theme", systemImage: "paintpalette") + Label(L10n.Profile.theme, systemImage: "paintpalette") .foregroundColor(Color.appTextPrimary) Spacer() @@ -143,7 +143,7 @@ struct ProfileTabView: View { Button(action: { showingLogoutAlert = true }) { - Label("Log Out", systemImage: "rectangle.portrait.and.arrow.right") + Label(L10n.Profile.logout, systemImage: "rectangle.portrait.and.arrow.right") .foregroundColor(Color.appError) } .accessibilityIdentifier(AccessibilityIdentifiers.Profile.logoutButton) @@ -152,12 +152,12 @@ struct ProfileTabView: View { Section { VStack(alignment: .leading, spacing: 4) { - Text("Casera") + Text(L10n.Profile.appName) .font(.caption) .fontWeight(.semibold) .foregroundColor(Color.appTextPrimary) - Text("Version 1.0.0") + Text(L10n.Profile.version) .font(.caption2) .foregroundColor(Color.appTextSecondary) } @@ -166,7 +166,7 @@ struct ProfileTabView: View { } .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle("Profile") + .navigationTitle(L10n.Profile.title) .sheet(isPresented: $showingProfileEdit) { ProfileView() } @@ -176,21 +176,21 @@ struct ProfileTabView: View { .sheet(isPresented: $showingNotificationPreferences) { NotificationPreferencesView() } - .alert("Log Out", isPresented: $showingLogoutAlert) { - Button("Cancel", role: .cancel) { } - Button("Log Out", role: .destructive) { + .alert(L10n.Profile.logout, isPresented: $showingLogoutAlert) { + Button(L10n.Common.cancel, role: .cancel) { } + Button(L10n.Profile.logout, role: .destructive) { AuthenticationManager.shared.logout() } } message: { - Text("Are you sure you want to log out?") + Text(L10n.Profile.logoutConfirm) } .sheet(isPresented: $showUpgradePrompt) { UpgradePromptView(triggerKey: "user_profile", isPresented: $showUpgradePrompt) } - .alert("Purchases Restored", isPresented: $showRestoreSuccess) { - Button("OK", role: .cancel) { } + .alert(L10n.Profile.purchasesRestored, isPresented: $showRestoreSuccess) { + Button(L10n.Common.ok, role: .cancel) { } } message: { - Text("Your purchases have been restored successfully.") + Text(L10n.Profile.purchasesRestoredMessage) } } } diff --git a/iosApp/iosApp/Profile/ProfileView.swift b/iosApp/iosApp/Profile/ProfileView.swift index 491220f..325e3c3 100644 --- a/iosApp/iosApp/Profile/ProfileView.swift +++ b/iosApp/iosApp/Profile/ProfileView.swift @@ -14,7 +14,7 @@ struct ProfileView: View { if viewModel.isLoadingUser { VStack { ProgressView() - Text("Loading profile...") + Text(L10n.Profile.loadingProfile) .font(.subheadline) .foregroundColor(Color.appTextSecondary) .padding(.top, 8) @@ -27,7 +27,7 @@ struct ProfileView: View { .font(.system(size: 60)) .foregroundStyle(Color.appPrimary.gradient) - Text("Profile Settings") + Text(L10n.Profile.profileSettings) .font(.title2) .fontWeight(.bold) .foregroundColor(Color.appTextPrimary) @@ -38,7 +38,7 @@ struct ProfileView: View { .listRowBackground(Color.clear) Section { - TextField("First Name", text: $viewModel.firstName) + TextField(L10n.Profile.firstName, text: $viewModel.firstName) .textInputAutocapitalization(.words) .autocorrectionDisabled() .focused($focusedField, equals: .firstName) @@ -47,7 +47,7 @@ struct ProfileView: View { focusedField = .lastName } - TextField("Last Name", text: $viewModel.lastName) + TextField(L10n.Profile.lastName, text: $viewModel.lastName) .textInputAutocapitalization(.words) .autocorrectionDisabled() .focused($focusedField, equals: .lastName) @@ -56,12 +56,12 @@ struct ProfileView: View { focusedField = .email } } header: { - Text("Personal Information") + Text(L10n.Profile.personalInformation) } .listRowBackground(Color.appBackgroundSecondary) Section { - TextField("Email", text: $viewModel.email) + TextField(L10n.Profile.email, text: $viewModel.email) .textInputAutocapitalization(.never) .autocorrectionDisabled() .keyboardType(.emailAddress) @@ -71,9 +71,9 @@ struct ProfileView: View { viewModel.updateProfile() } } header: { - Text("Contact") + Text(L10n.Profile.contact) } footer: { - Text("Email is required and must be unique") + Text(L10n.Profile.emailRequiredUnique) } .listRowBackground(Color.appBackgroundSecondary) @@ -110,7 +110,7 @@ struct ProfileView: View { if viewModel.isLoading { ProgressView() } else { - Text("Save Changes") + Text(L10n.Profile.saveChanges) .fontWeight(.semibold) } Spacer() @@ -123,11 +123,11 @@ struct ProfileView: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle("Profile") + .navigationTitle(L10n.Profile.title) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarLeading) { - Button("Cancel") { + Button(L10n.Common.cancel) { dismiss() } } diff --git a/iosApp/iosApp/Profile/ThemeSelectionView.swift b/iosApp/iosApp/Profile/ThemeSelectionView.swift index 444c08a..5cf6080 100644 --- a/iosApp/iosApp/Profile/ThemeSelectionView.swift +++ b/iosApp/iosApp/Profile/ThemeSelectionView.swift @@ -22,11 +22,11 @@ struct ThemeSelectionView: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle("Appearance") + .navigationTitle(L10n.Profile.appearance) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .confirmationAction) { - Button("Done") { + Button(L10n.Common.done) { dismiss() } } diff --git a/iosApp/iosApp/Register/RegisterView.swift b/iosApp/iosApp/Register/RegisterView.swift index 0800c2e..dfb2ea6 100644 --- a/iosApp/iosApp/Register/RegisterView.swift +++ b/iosApp/iosApp/Register/RegisterView.swift @@ -20,11 +20,11 @@ struct RegisterView: View { .font(.system(size: 60)) .foregroundStyle(Color.appPrimary.gradient) - Text("Join Casera") + Text(L10n.Auth.joinCasera) .font(.largeTitle) .fontWeight(.bold) - Text("Start managing your properties today") + Text(L10n.Auth.startManaging) .font(.subheadline) .foregroundColor(Color.appTextSecondary) } @@ -34,7 +34,7 @@ struct RegisterView: View { .listRowBackground(Color.clear) Section { - TextField("Username", text: $viewModel.username) + TextField(L10n.Auth.registerUsername, text: $viewModel.username) .textInputAutocapitalization(.never) .autocorrectionDisabled() .textContentType(.username) @@ -45,7 +45,7 @@ struct RegisterView: View { } .accessibilityIdentifier(AccessibilityIdentifiers.Authentication.registerUsernameField) - TextField("Email", text: $viewModel.email) + TextField(L10n.Auth.registerEmail, text: $viewModel.email) .textInputAutocapitalization(.never) .autocorrectionDisabled() .keyboardType(.emailAddress) @@ -57,14 +57,14 @@ struct RegisterView: View { } .accessibilityIdentifier(AccessibilityIdentifiers.Authentication.registerEmailField) } header: { - Text("Account Information") + Text(L10n.Auth.accountInfo) } .listRowBackground(Color.appBackgroundSecondary) Section { // Using .newPassword enables iOS Strong Password generation // iOS will automatically offer to save to iCloud Keychain after successful registration - SecureField("Password", text: $viewModel.password) + SecureField(L10n.Auth.registerPassword, text: $viewModel.password) .textContentType(.newPassword) .focused($focusedField, equals: .password) .submitLabel(.next) @@ -73,7 +73,7 @@ struct RegisterView: View { } .accessibilityIdentifier(AccessibilityIdentifiers.Authentication.registerPasswordField) - SecureField("Confirm Password", text: $viewModel.confirmPassword) + SecureField(L10n.Auth.registerConfirmPassword, text: $viewModel.confirmPassword) .textContentType(.newPassword) .focused($focusedField, equals: .confirmPassword) .submitLabel(.go) @@ -82,9 +82,9 @@ struct RegisterView: View { } .accessibilityIdentifier(AccessibilityIdentifiers.Authentication.registerConfirmPasswordField) } header: { - Text("Security") + Text(L10n.Auth.security) } footer: { - Text("Tap the password field for a strong password suggestion") + Text(L10n.Auth.passwordSuggestion) } .listRowBackground(Color.appBackgroundSecondary) @@ -108,7 +108,7 @@ struct RegisterView: View { if viewModel.isLoading { ProgressView() } else { - Text("Create Account") + Text(L10n.Auth.registerButton) .fontWeight(.semibold) } Spacer() @@ -122,11 +122,11 @@ struct RegisterView: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle("Create Account") + .navigationTitle(L10n.Auth.registerTitle) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarLeading) { - Button("Cancel") { + Button(L10n.Common.cancel) { dismiss() } .accessibilityIdentifier(AccessibilityIdentifiers.Authentication.registerCancelButton) diff --git a/iosApp/iosApp/Residence/JoinResidenceView.swift b/iosApp/iosApp/Residence/JoinResidenceView.swift index 40396b7..ddaf06a 100644 --- a/iosApp/iosApp/Residence/JoinResidenceView.swift +++ b/iosApp/iosApp/Residence/JoinResidenceView.swift @@ -12,7 +12,7 @@ struct JoinResidenceView: View { NavigationView { Form { Section { - TextField("Share Code", text: $shareCode) + TextField(L10n.Residences.shareCode, text: $shareCode) .textInputAutocapitalization(.characters) .autocorrectionDisabled() .onChange(of: shareCode) { newValue in @@ -25,9 +25,9 @@ struct JoinResidenceView: View { } .disabled(viewModel.isLoading) } header: { - Text("Enter Share Code") + Text(L10n.Residences.enterShareCode) } footer: { - Text("Enter the 6-character code shared with you to join a residence") + Text(L10n.Residences.shareCodeFooter) .foregroundColor(Color.appTextSecondary) } .listRowBackground(Color.appBackgroundSecondary) @@ -48,7 +48,7 @@ struct JoinResidenceView: View { ProgressView() .progressViewStyle(CircularProgressViewStyle()) } else { - Text("Join Residence") + Text(L10n.Residences.joinButton) .fontWeight(.semibold) } Spacer() @@ -61,11 +61,11 @@ struct JoinResidenceView: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle("Join Residence") + .navigationTitle(L10n.Residences.joinTitle) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarLeading) { - Button("Cancel") { + Button(L10n.Common.cancel) { dismiss() } .disabled(viewModel.isLoading) @@ -76,7 +76,7 @@ struct JoinResidenceView: View { private func joinResidence() { guard shareCode.count == 6 else { - viewModel.errorMessage = "Share code must be 6 characters" + viewModel.errorMessage = L10n.Residences.shareCodeMust6 return } diff --git a/iosApp/iosApp/Residence/ManageUsersView.swift b/iosApp/iosApp/Residence/ManageUsersView.swift index b6c8297..56113d3 100644 --- a/iosApp/iosApp/Residence/ManageUsersView.swift +++ b/iosApp/iosApp/Residence/ManageUsersView.swift @@ -43,7 +43,7 @@ struct ManageUsersView: View { // Users list VStack(alignment: .leading, spacing: 12) { - Text("Users (\(users.count))") + Text("\(L10n.Residences.users) (\(users.count))") .font(.headline) .padding(.horizontal) @@ -66,11 +66,11 @@ struct ManageUsersView: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle("Manage Users") + .navigationTitle(L10n.Residences.manageUsers) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { - Button("Close") { + Button(L10n.Common.close) { dismiss() } } diff --git a/iosApp/iosApp/Residence/ResidenceDetailView.swift b/iosApp/iosApp/Residence/ResidenceDetailView.swift index 735b14d..418ea29 100644 --- a/iosApp/iosApp/Residence/ResidenceDetailView.swift +++ b/iosApp/iosApp/Residence/ResidenceDetailView.swift @@ -54,35 +54,35 @@ struct ResidenceDetailView: View { leadingToolbar trailingToolbar } - + // MARK: Alerts - .alert("Generate Report", isPresented: $showReportConfirmation) { - Button("Cancel", role: .cancel) { + .alert(L10n.Residences.generateReport, isPresented: $showReportConfirmation) { + Button(L10n.Common.cancel, role: .cancel) { showReportConfirmation = false } - Button("Generate") { + Button(L10n.Residences.generate) { viewModel.generateTasksReport(residenceId: residenceId, email: "") showReportConfirmation = false } } message: { - Text("This will generate a comprehensive report of your property including all tasks, documents, and contractors.") + Text(L10n.Residences.generateReportMessage) } - - .alert("Delete Residence", isPresented: $showDeleteConfirmation) { - Button("Cancel", role: .cancel) { } + + .alert(L10n.Residences.deleteTitle, isPresented: $showDeleteConfirmation) { + Button(L10n.Common.cancel, role: .cancel) { } .accessibilityIdentifier(AccessibilityIdentifiers.Alert.cancelButton) - Button("Delete", role: .destructive) { + Button(L10n.Common.delete, role: .destructive) { deleteResidence() } .accessibilityIdentifier(AccessibilityIdentifiers.Alert.deleteButton) } message: { if let residence = viewModel.selectedResidence { - Text("Are you sure you want to delete \(residence.name)? This action cannot be undone and will delete all associated tasks, documents, and data.") + Text("\(L10n.Residences.deleteConfirmMessage)") } } - - .alert("Maintenance Report", isPresented: $showReportAlert) { - Button("OK", role: .cancel) { } + + .alert(L10n.Residences.maintenanceReport, isPresented: $showReportAlert) { + Button(L10n.Common.ok, role: .cancel) { } } message: { Text(viewModel.reportMessage ?? "") } @@ -189,7 +189,7 @@ private extension ResidenceDetailView { var loadingView: some View { VStack(spacing: 16) { ProgressView() - Text("Loading residence...") + Text(L10n.Residences.loadingResidence) .font(.subheadline) .foregroundColor(Color.appTextSecondary) } @@ -226,9 +226,9 @@ private extension ResidenceDetailView { reloadTasks: { loadResidenceTasks() } ) } else if isLoadingTasks { - ProgressView("Loading tasks...") + ProgressView(L10n.Residences.loadingTasks) } else if let tasksError = tasksError { - Text("Error loading tasks: \(tasksError)") + Text("\(L10n.Residences.errorLoadingTasks): \(tasksError)") .foregroundColor(Color.appError) .padding() } @@ -242,7 +242,7 @@ private extension ResidenceDetailView { Image(systemName: "person.2.fill") .font(.title2) .foregroundColor(Color.appPrimary) - Text("Contractors") + Text(L10n.Residences.contractors) .font(.title2.weight(.bold)) .foregroundColor(Color.appPrimary) } @@ -256,7 +256,7 @@ private extension ResidenceDetailView { } .padding() } else if let error = contractorsError { - Text("Error: \(error)") + Text("\(L10n.Common.error): \(error)") .foregroundColor(Color.appError) .padding() } else if contractors.isEmpty { @@ -265,10 +265,10 @@ private extension ResidenceDetailView { Image(systemName: "person.crop.circle.badge.plus") .font(.system(size: 48)) .foregroundColor(Color.appTextSecondary.opacity(0.6)) - Text("No contractors yet") + Text(L10n.Residences.noContractors) .font(.headline) .foregroundColor(Color.appTextPrimary) - Text("Add contractors from the Contractors tab") + Text(L10n.Residences.addContractorsPrompt) .font(.subheadline) .foregroundColor(Color.appTextSecondary) } @@ -303,7 +303,7 @@ private extension ResidenceDetailView { var leadingToolbar: some ToolbarContent { ToolbarItem(placement: .navigationBarLeading) { if viewModel.selectedResidence != nil { - Button("Edit") { + Button(L10n.Common.edit) { showEditResidence = true } .accessibilityIdentifier(AccessibilityIdentifiers.Residence.editButton) diff --git a/iosApp/iosApp/Residence/ResidencesListView.swift b/iosApp/iosApp/Residence/ResidencesListView.swift index 75d98d4..baa57ec 100644 --- a/iosApp/iosApp/Residence/ResidencesListView.swift +++ b/iosApp/iosApp/Residence/ResidencesListView.swift @@ -43,7 +43,7 @@ struct ResidencesListView: View { }) } } - .navigationTitle("My Properties") + .navigationTitle(L10n.Residences.title) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItemGroup(placement: .navigationBarTrailing) { @@ -134,10 +134,10 @@ private struct ResidencesContent: View { // Properties Header HStack { VStack(alignment: .leading, spacing: AppSpacing.xxs) { - Text("Your Properties") + Text(L10n.Residences.yourProperties) .font(.title3.weight(.semibold)) .foregroundColor(Color.appTextPrimary) - Text("\(residences.count) \(residences.count == 1 ? "property" : "properties")") + Text("\(residences.count) \(residences.count == 1 ? L10n.Residences.property : L10n.Residences.properties)") .font(.callout) .foregroundColor(Color.appTextSecondary) } diff --git a/iosApp/iosApp/ResidenceFormView.swift b/iosApp/iosApp/ResidenceFormView.swift index 000838c..19d878d 100644 --- a/iosApp/iosApp/ResidenceFormView.swift +++ b/iosApp/iosApp/ResidenceFormView.swift @@ -48,7 +48,7 @@ struct ResidenceFormView: View { NavigationView { Form { Section { - TextField("Property Name", text: $name) + TextField(L10n.Residences.propertyName, text: $name) .focused($focusedField, equals: .name) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.nameField) @@ -58,54 +58,54 @@ struct ResidenceFormView: View { .foregroundColor(Color.appError) } - Picker("Property Type", selection: $selectedPropertyType) { - Text("Select Type").tag(nil as ResidenceType?) + Picker(L10n.Residences.propertyType, selection: $selectedPropertyType) { + Text(L10n.Residences.selectType).tag(nil as ResidenceType?) ForEach(residenceTypes, id: \.id) { type in Text(type.name).tag(type as ResidenceType?) } } .accessibilityIdentifier(AccessibilityIdentifiers.Residence.propertyTypePicker) } header: { - Text("Property Details") + Text(L10n.Residences.propertyDetails) } footer: { - Text("Required: Name") + Text(L10n.Residences.requiredName) .font(.caption) .foregroundColor(Color.appError) } .listRowBackground(Color.appBackgroundSecondary) Section { - TextField("Street Address", text: $streetAddress) + TextField(L10n.Residences.streetAddress, text: $streetAddress) .focused($focusedField, equals: .streetAddress) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.streetAddressField) - TextField("Apartment/Unit (optional)", text: $apartmentUnit) + TextField(L10n.Residences.apartmentUnit, text: $apartmentUnit) .focused($focusedField, equals: .apartmentUnit) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.apartmentUnitField) - TextField("City", text: $city) + TextField(L10n.Residences.city, text: $city) .focused($focusedField, equals: .city) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.cityField) - TextField("State/Province", text: $stateProvince) + TextField(L10n.Residences.stateProvince, text: $stateProvince) .focused($focusedField, equals: .stateProvince) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.stateProvinceField) - TextField("Postal Code", text: $postalCode) + TextField(L10n.Residences.postalCode, text: $postalCode) .focused($focusedField, equals: .postalCode) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.postalCodeField) - TextField("Country", text: $country) + TextField(L10n.Residences.country, text: $country) .focused($focusedField, equals: .country) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.countryField) } header: { - Text("Address") + Text(L10n.Residences.address) } .listRowBackground(Color.appBackgroundSecondary) - Section(header: Text("Property Features")) { + Section(header: Text(L10n.Residences.propertyFeatures)) { HStack { - Text("Bedrooms") + Text(L10n.Residences.bedrooms) Spacer() TextField("0", text: $bedrooms) .keyboardType(.numberPad) @@ -116,7 +116,7 @@ struct ResidenceFormView: View { } HStack { - Text("Bathrooms") + Text(L10n.Residences.bathrooms) Spacer() TextField("0.0", text: $bathrooms) .keyboardType(.decimalPad) @@ -126,29 +126,29 @@ struct ResidenceFormView: View { .accessibilityIdentifier(AccessibilityIdentifiers.Residence.bathroomsField) } - TextField("Square Footage", text: $squareFootage) + TextField(L10n.Residences.squareFootage, text: $squareFootage) .keyboardType(.numberPad) .focused($focusedField, equals: .squareFootage) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.squareFootageField) - TextField("Lot Size (acres)", text: $lotSize) + TextField(L10n.Residences.lotSize, text: $lotSize) .keyboardType(.decimalPad) .focused($focusedField, equals: .lotSize) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.lotSizeField) - TextField("Year Built", text: $yearBuilt) + TextField(L10n.Residences.yearBuilt, text: $yearBuilt) .keyboardType(.numberPad) .focused($focusedField, equals: .yearBuilt) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.yearBuiltField) } .listRowBackground(Color.appBackgroundSecondary) - Section(header: Text("Additional Details")) { - TextField("Description (optional)", text: $description, axis: .vertical) + Section(header: Text(L10n.Residences.additionalDetails)) { + TextField(L10n.Residences.description, text: $description, axis: .vertical) .lineLimit(3...6) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.descriptionField) - Toggle("Primary Residence", isOn: $isPrimary) + Toggle(L10n.Residences.primaryResidence, isOn: $isPrimary) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.isPrimaryToggle) } .listRowBackground(Color.appBackgroundSecondary) @@ -165,18 +165,18 @@ struct ResidenceFormView: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle(isEditMode ? "Edit Residence" : "Add Residence") + .navigationTitle(isEditMode ? L10n.Residences.editTitle : L10n.Residences.addTitle) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarLeading) { - Button("Cancel") { + Button(L10n.Common.cancel) { isPresented = false } .accessibilityIdentifier(AccessibilityIdentifiers.Residence.formCancelButton) } ToolbarItem(placement: .navigationBarTrailing) { - Button("Save") { + Button(L10n.Common.save) { submitForm() } .disabled(!canSave || viewModel.isLoading) @@ -244,7 +244,7 @@ struct ResidenceFormView: View { var isValid = true if name.isEmpty { - nameError = "Name is required" + nameError = L10n.Residences.nameRequired isValid = false } else { nameError = "" diff --git a/iosApp/iosApp/Subviews/Task/DynamicTaskColumnView.swift b/iosApp/iosApp/Subviews/Task/DynamicTaskColumnView.swift index dbdb898..92f5b54 100644 --- a/iosApp/iosApp/Subviews/Task/DynamicTaskColumnView.swift +++ b/iosApp/iosApp/Subviews/Task/DynamicTaskColumnView.swift @@ -53,7 +53,7 @@ struct DynamicTaskColumnView: View { .font(.system(size: 40)) .foregroundColor(columnColor.opacity(0.3)) - Text("No tasks") + Text(L10n.Tasks.noTasks) .font(.caption) .foregroundColor(Color.appTextSecondary) } diff --git a/iosApp/iosApp/Subviews/Task/TaskCard.swift b/iosApp/iosApp/Subviews/Task/TaskCard.swift index b5199a1..5e03bcf 100644 --- a/iosApp/iosApp/Subviews/Task/TaskCard.swift +++ b/iosApp/iosApp/Subviews/Task/TaskCard.swift @@ -89,7 +89,7 @@ struct TaskCard: View { .font(.system(size: 14, weight: .semibold)) .foregroundColor(Color.appAccent) } - Text("Completions (\(task.completions.count))") + Text("\(L10n.Tasks.completions.capitalized) (\(task.completions.count))") .font(.footnote.weight(.medium)) .fontWeight(.semibold) .foregroundColor(Color.appTextPrimary) @@ -121,7 +121,7 @@ struct TaskCard: View { HStack(spacing: AppSpacing.xs) { Image(systemName: "play.circle.fill") .font(.system(size: 16, weight: .semibold)) - Text("In Progress") + Text(L10n.Tasks.inProgress) .font(.subheadline.weight(.medium)) .fontWeight(.semibold) } @@ -138,7 +138,7 @@ struct TaskCard: View { HStack(spacing: AppSpacing.xs) { Image(systemName: "checkmark.circle.fill") .font(.system(size: 16, weight: .semibold)) - Text("Complete") + Text(L10n.Tasks.complete) .font(.subheadline.weight(.medium)) .fontWeight(.semibold) } @@ -159,7 +159,7 @@ struct TaskCard: View { HStack(spacing: AppSpacing.xxs) { Image(systemName: "pencil") .font(.system(size: 14, weight: .medium)) - Text("Edit") + Text(L10n.Tasks.edit) .font(.footnote.weight(.medium)) } .frame(maxWidth: .infinity) @@ -174,7 +174,7 @@ struct TaskCard: View { HStack(spacing: AppSpacing.xxs) { Image(systemName: "xmark.circle") .font(.system(size: 14, weight: .medium)) - Text("Cancel") + Text(L10n.Tasks.cancel) .font(.footnote.weight(.medium)) } .frame(maxWidth: .infinity) @@ -188,7 +188,7 @@ struct TaskCard: View { HStack(spacing: AppSpacing.xxs) { Image(systemName: "arrow.uturn.backward") .font(.system(size: 14, weight: .medium)) - Text("Restore") + Text(L10n.Tasks.restore) .font(.footnote.weight(.medium)) } .frame(maxWidth: .infinity) @@ -206,7 +206,7 @@ struct TaskCard: View { HStack(spacing: AppSpacing.xxs) { Image(systemName: "tray.and.arrow.up") .font(.system(size: 14, weight: .medium)) - Text("Unarchive") + Text(L10n.Tasks.unarchive) .font(.footnote.weight(.medium)) } .frame(maxWidth: .infinity) @@ -222,7 +222,7 @@ struct TaskCard: View { HStack(spacing: AppSpacing.xxs) { Image(systemName: "archivebox") .font(.system(size: 14, weight: .medium)) - Text("Archive") + Text(L10n.Tasks.archive) .font(.footnote.weight(.medium)) } .frame(maxWidth: .infinity) diff --git a/iosApp/iosApp/Task/AllTasksView.swift b/iosApp/iosApp/Task/AllTasksView.swift index e08164b..7e0672f 100644 --- a/iosApp/iosApp/Task/AllTasksView.swift +++ b/iosApp/iosApp/Task/AllTasksView.swift @@ -57,11 +57,11 @@ struct AllTasksView: View { .sheet(isPresented: $showingUpgradePrompt) { UpgradePromptView(triggerKey: "add_11th_task", isPresented: $showingUpgradePrompt) } - .alert("Archive Task", isPresented: $showArchiveConfirmation) { - Button("Cancel", role: .cancel) { + .alert(L10n.Tasks.archiveTask, isPresented: $showArchiveConfirmation) { + Button(L10n.Common.cancel, role: .cancel) { selectedTaskForArchive = nil } - Button("Archive", role: .destructive) { + Button(L10n.Tasks.archive, role: .destructive) { if let task = selectedTaskForArchive { taskViewModel.archiveTask(id: task.id) { _ in loadAllTasks() @@ -71,14 +71,14 @@ struct AllTasksView: View { } } message: { if let task = selectedTaskForArchive { - Text("Are you sure you want to archive \"\(task.title)\"? You can unarchive it later from archived tasks.") + Text(L10n.Tasks.archiveConfirm.replacingOccurrences(of: "this task", with: "\"\(task.title)\"")) } } - .alert("Delete Task", isPresented: $showCancelConfirmation) { - Button("Cancel", role: .cancel) { + .alert(L10n.Tasks.deleteTask, isPresented: $showCancelConfirmation) { + Button(L10n.Common.cancel, role: .cancel) { selectedTaskForCancel = nil } - Button("Archive", role: .destructive) { + Button(L10n.Tasks.archive, role: .destructive) { if let task = selectedTaskForCancel { taskViewModel.cancelTask(id: task.id) { _ in loadAllTasks() @@ -88,7 +88,7 @@ struct AllTasksView: View { } } message: { if let task = selectedTaskForCancel { - Text("Are you sure you want to archive \"\(task.title)\"? You can unarchive it later from archived tasks.") + Text(L10n.Tasks.archiveConfirm.replacingOccurrences(of: "this task", with: "\"\(task.title)\"")) } } .onChange(of: showAddTask) { isShowing in @@ -129,16 +129,16 @@ struct AllTasksView: View { .font(.system(size: 64)) .foregroundStyle(Color.appPrimary.opacity(0.6)) - Text("No tasks yet") + Text(L10n.Tasks.noTasksYet) .font(.title2) .fontWeight(.semibold) .foregroundColor(Color.appTextPrimary) - Text("Create your first task to get started") + Text(L10n.Tasks.createFirst) .font(.body) .foregroundColor(Color.appTextSecondary) .multilineTextAlignment(.center) - + Button(action: { // Check if we should show upgrade prompt before adding if subscriptionCache.shouldShowUpgradePrompt(currentCount: totalTaskCount, limitKey: "tasks") { @@ -149,7 +149,7 @@ struct AllTasksView: View { }) { HStack(spacing: 8) { Image(systemName: "plus") - Text("Add Task") + Text(L10n.Tasks.addButton) .fontWeight(.semibold) } .frame(maxWidth: .infinity) @@ -160,13 +160,13 @@ struct AllTasksView: View { .padding(.horizontal, 48) .disabled(residenceViewModel.myResidences?.residences.isEmpty ?? true) .accessibilityIdentifier(AccessibilityIdentifiers.Task.addButton) - + if residenceViewModel.myResidences?.residences.isEmpty ?? true { - Text("Add a property first from the Residences tab") + Text(L10n.Tasks.addPropertyFirst) .font(.caption) .foregroundColor(Color.appError) } - + Spacer() } .padding() @@ -235,7 +235,7 @@ struct AllTasksView: View { } .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle("All Tasks") + .navigationTitle(L10n.Tasks.allTasks) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { diff --git a/iosApp/iosApp/Task/CompleteTaskView.swift b/iosApp/iosApp/Task/CompleteTaskView.swift index 919dc2c..3f01695 100644 --- a/iosApp/iosApp/Task/CompleteTaskView.swift +++ b/iosApp/iosApp/Task/CompleteTaskView.swift @@ -51,7 +51,7 @@ struct CompleteTaskView: View { } } } header: { - Text("Task Details") + Text(L10n.Tasks.taskDetails) } .listRowBackground(Color.appBackgroundSecondary) @@ -61,7 +61,7 @@ struct CompleteTaskView: View { showContractorPicker = true }) { HStack { - Label("Select Contractor", systemImage: "wrench.and.screwdriver") + Label(L10n.Tasks.selectContractor, systemImage: "wrench.and.screwdriver") .foregroundStyle(.primary) Spacer() @@ -77,7 +77,7 @@ struct CompleteTaskView: View { } } } else { - Text("None") + Text(L10n.Tasks.none) .foregroundStyle(.tertiary) } @@ -87,20 +87,20 @@ struct CompleteTaskView: View { } } } header: { - Text("Contractor (Optional)") + Text(L10n.Tasks.contractorOptional) } footer: { - Text("Select a contractor if they completed this work, or leave blank for manual entry.") + Text(L10n.Tasks.contractorHelper) } .listRowBackground(Color.appBackgroundSecondary) // Completion Details Section Section { LabeledContent { - TextField("Your name", text: $completedByName) + TextField(L10n.Tasks.yourName, text: $completedByName) .multilineTextAlignment(.trailing) .disabled(selectedContractor != nil) } label: { - Label("Completed By", systemImage: "person") + Label(L10n.Tasks.completedBy, systemImage: "person") } LabeledContent { @@ -113,19 +113,19 @@ struct CompleteTaskView: View { } .padding(.leading, 12) } label: { - Label("Actual Cost", systemImage: "dollarsign.circle") + Label(L10n.Tasks.actualCost, systemImage: "dollarsign.circle") } } header: { - Text("Optional Information") + Text(L10n.Tasks.optionalInfo) } footer: { - Text("Add any additional details about completing this task.") + Text(L10n.Tasks.optionalDetails) } .listRowBackground(Color.appBackgroundSecondary) // Notes Section Section { VStack(alignment: .leading, spacing: 8) { - Label("Notes", systemImage: "note.text") + Label(L10n.Tasks.notes, systemImage: "note.text") .font(.subheadline) .foregroundStyle(.secondary) @@ -134,7 +134,7 @@ struct CompleteTaskView: View { .scrollContentBackground(.hidden) } } footer: { - Text("Optional notes about the work completed.") + Text(L10n.Tasks.optionalNotes) } .listRowBackground(Color.appBackgroundSecondary) @@ -142,7 +142,7 @@ struct CompleteTaskView: View { Section { VStack(spacing: 12) { HStack { - Label("Quality Rating", systemImage: "star") + Label(L10n.Tasks.qualityRating, systemImage: "star") .font(.subheadline) Spacer() @@ -168,7 +168,7 @@ struct CompleteTaskView: View { .frame(maxWidth: .infinity) } } footer: { - Text("Rate the quality of work from 1 to 5 stars.") + Text(L10n.Tasks.rateQuality) } .listRowBackground(Color.appBackgroundSecondary) @@ -179,7 +179,7 @@ struct CompleteTaskView: View { Button(action: { showCamera = true }) { - Label("Take Photo", systemImage: "camera") + Label(L10n.Tasks.takePhoto, systemImage: "camera") .frame(maxWidth: .infinity) .foregroundStyle(Color.appPrimary) } @@ -191,7 +191,7 @@ struct CompleteTaskView: View { matching: .images, photoLibrary: .shared() ) { - Label("Library", systemImage: "photo.on.rectangle.angled") + Label(L10n.Tasks.library, systemImage: "photo.on.rectangle.angled") .frame(maxWidth: .infinity) .foregroundStyle(Color.appPrimary) } @@ -230,9 +230,9 @@ struct CompleteTaskView: View { } } } header: { - Text("Photos (\(selectedImages.count)/5)") + Text("\(L10n.Tasks.photos) (\(selectedImages.count)/5)") } footer: { - Text("Add up to 5 photos documenting the completed work.") + Text(L10n.Tasks.addPhotos) } .listRowBackground(Color.appBackgroundSecondary) @@ -244,7 +244,7 @@ struct CompleteTaskView: View { ProgressView() .tint(.white) } else { - Label("Complete Task", systemImage: "checkmark.circle.fill") + Label(L10n.Tasks.completeTask, systemImage: "checkmark.circle.fill") } } .frame(maxWidth: .infinity) @@ -258,17 +258,17 @@ struct CompleteTaskView: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle("Complete Task") + .navigationTitle(L10n.Tasks.completeTask) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Cancel") { + Button(L10n.Common.cancel) { dismiss() } } } - .alert("Error", isPresented: $showError) { - Button("OK", role: .cancel) {} + .alert(L10n.Tasks.error, isPresented: $showError) { + Button(L10n.Common.ok, role: .cancel) {} } message: { Text(errorMessage) } @@ -386,9 +386,9 @@ struct ContractorPickerView: View { }) { HStack { VStack(alignment: .leading) { - Text("None (Manual Entry)") + Text(L10n.Tasks.noneManual) .foregroundStyle(.primary) - Text("Enter name manually") + Text(L10n.Tasks.enterManually) .font(.caption) .foregroundStyle(.secondary) } @@ -450,11 +450,11 @@ struct ContractorPickerView: View { } } } - .navigationTitle("Select Contractor") + .navigationTitle(L10n.Tasks.selectContractor) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Cancel") { + Button(L10n.Common.cancel) { dismiss() } } diff --git a/iosApp/iosApp/Task/CompletionHistorySheet.swift b/iosApp/iosApp/Task/CompletionHistorySheet.swift index ec75460..6507eaf 100644 --- a/iosApp/iosApp/Task/CompletionHistorySheet.swift +++ b/iosApp/iosApp/Task/CompletionHistorySheet.swift @@ -21,11 +21,11 @@ struct CompletionHistorySheet: View { completionsList } } - .navigationTitle("Completion History") + .navigationTitle(L10n.Tasks.completionHistory) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Done") { + Button(L10n.Common.done) { isPresented = false } } @@ -47,7 +47,7 @@ struct CompletionHistorySheet: View { ProgressView() .progressViewStyle(CircularProgressViewStyle(tint: Color.appPrimary)) .scaleEffect(1.5) - Text("Loading completions...") + Text(L10n.Tasks.loadingCompletions) .font(.subheadline) .foregroundColor(Color.appTextSecondary) } @@ -60,7 +60,7 @@ struct CompletionHistorySheet: View { .font(.system(size: 48)) .foregroundColor(Color.appError) - Text("Failed to load completions") + Text(L10n.Tasks.failedToLoad) .font(.headline) .foregroundColor(Color.appTextPrimary) @@ -73,7 +73,7 @@ struct CompletionHistorySheet: View { Button(action: { viewModel.loadCompletions(taskId: taskId) }) { - Label("Retry", systemImage: "arrow.clockwise") + Label(L10n.Common.retry, systemImage: "arrow.clockwise") .foregroundColor(Color.appPrimary) } .padding(.top, AppSpacing.sm) @@ -87,11 +87,11 @@ struct CompletionHistorySheet: View { .font(.system(size: 48)) .foregroundColor(Color.appTextSecondary.opacity(0.5)) - Text("No Completions Yet") + Text(L10n.Tasks.noCompletionsYet) .font(.headline) .foregroundColor(Color.appTextPrimary) - Text("This task has not been completed.") + Text(L10n.Tasks.notCompleted) .font(.subheadline) .foregroundColor(Color.appTextSecondary) } @@ -110,7 +110,7 @@ struct CompletionHistorySheet: View { .fontWeight(.semibold) .foregroundColor(Color.appTextPrimary) Spacer() - Text("\(viewModel.completions.count) \(viewModel.completions.count == 1 ? "completion" : "completions")") + Text("\(viewModel.completions.count) \(viewModel.completions.count == 1 ? L10n.Tasks.completion : L10n.Tasks.completions)") .font(.caption) .foregroundColor(Color.appTextSecondary) } @@ -146,7 +146,7 @@ struct CompletionHistoryCard: View { HStack(spacing: 4) { Image(systemName: "person.fill") .font(.caption2) - Text("Completed by \(completedBy)") + Text("\(L10n.Tasks.completedByName) \(completedBy)") .font(.caption) } .foregroundColor(Color.appTextSecondary) @@ -213,7 +213,7 @@ struct CompletionHistoryCard: View { // Notes if !completion.notes.isEmpty { VStack(alignment: .leading, spacing: 4) { - Text("Notes") + Text(L10n.Tasks.notes) .font(.caption) .fontWeight(.semibold) .foregroundColor(Color.appTextSecondary) @@ -233,7 +233,7 @@ struct CompletionHistoryCard: View { HStack { Image(systemName: "photo.on.rectangle.angled") .font(.subheadline) - Text("View Photos (\(completion.images.count))") + Text("\(L10n.Tasks.viewPhotos) (\(completion.images.count))") .font(.subheadline) .fontWeight(.semibold) } diff --git a/iosApp/iosApp/Task/TaskFormView.swift b/iosApp/iosApp/Task/TaskFormView.swift index fc9daa7..2b1b62a 100644 --- a/iosApp/iosApp/Task/TaskFormView.swift +++ b/iosApp/iosApp/Task/TaskFormView.swift @@ -97,8 +97,8 @@ struct TaskFormView: View { // Residence Picker (only if needed) if needsResidenceSelection, let residences = residences { Section { - Picker("Property", selection: $selectedResidence) { - Text("Select Property").tag(nil as ResidenceResponse?) + Picker(L10n.Tasks.property, selection: $selectedResidence) { + Text(L10n.Tasks.selectProperty).tag(nil as ResidenceResponse?) ForEach(residences, id: \.id) { residence in Text(residence.name).tag(residence as ResidenceResponse?) } @@ -110,9 +110,9 @@ struct TaskFormView: View { .foregroundColor(Color.appError) } } header: { - Text("Property") + Text(L10n.Tasks.property) } footer: { - Text("Required") + Text(L10n.Tasks.required) .font(.caption) .foregroundColor(Color.appError) } @@ -120,7 +120,7 @@ struct TaskFormView: View { } Section { - TextField("Title", text: $title) + TextField(L10n.Tasks.titleLabel, text: $title) .focused($focusedField, equals: .title) if !titleError.isEmpty { @@ -129,83 +129,83 @@ struct TaskFormView: View { .foregroundColor(Color.appError) } - TextField("Description (optional)", text: $description, axis: .vertical) + TextField(L10n.Tasks.descriptionOptional, text: $description, axis: .vertical) .lineLimit(3...6) .focused($focusedField, equals: .description) } header: { - Text("Task Details") + Text(L10n.Tasks.taskDetails) } footer: { - Text("Required: Title") + Text(L10n.Tasks.titleRequired) .font(.caption) .foregroundColor(Color.appError) } .listRowBackground(Color.appBackgroundSecondary) Section { - Picker("Category", selection: $selectedCategory) { - Text("Select Category").tag(nil as TaskCategory?) + Picker(L10n.Tasks.category, selection: $selectedCategory) { + Text(L10n.Tasks.selectCategory).tag(nil as TaskCategory?) ForEach(taskCategories, id: \.id) { category in Text(category.name.capitalized).tag(category as TaskCategory?) } } } header: { - Text("Category") + Text(L10n.Tasks.category) } footer: { - Text("Required") + Text(L10n.Tasks.required) .font(.caption) .foregroundColor(Color.appError) } .listRowBackground(Color.appBackgroundSecondary) Section { - Picker("Frequency", selection: $selectedFrequency) { - Text("Select Frequency").tag(nil as TaskFrequency?) + Picker(L10n.Tasks.frequency, selection: $selectedFrequency) { + Text(L10n.Tasks.selectFrequency).tag(nil as TaskFrequency?) ForEach(taskFrequencies, id: \.id) { frequency in Text(frequency.displayName).tag(frequency as TaskFrequency?) } } if selectedFrequency?.name != "once" { - TextField("Custom Interval (days, optional)", text: $intervalDays) + TextField(L10n.Tasks.customInterval, text: $intervalDays) .keyboardType(.numberPad) .focused($focusedField, equals: .intervalDays) } - DatePicker("Due Date", selection: $dueDate, displayedComponents: .date) + DatePicker(L10n.Tasks.dueDate, selection: $dueDate, displayedComponents: .date) } header: { - Text("Scheduling") + Text(L10n.Tasks.scheduling) } footer: { - Text("Required: Frequency") + Text(L10n.Tasks.required) .font(.caption) .foregroundColor(Color.appError) } .listRowBackground(Color.appBackgroundSecondary) Section { - Picker("Priority", selection: $selectedPriority) { - Text("Select Priority").tag(nil as TaskPriority?) + Picker(L10n.Tasks.priority, selection: $selectedPriority) { + Text(L10n.Tasks.selectPriority).tag(nil as TaskPriority?) ForEach(taskPriorities, id: \.id) { priority in Text(priority.displayName).tag(priority as TaskPriority?) } } - Picker("Status", selection: $selectedStatus) { - Text("Select Status").tag(nil as TaskStatus?) + Picker(L10n.Tasks.status, selection: $selectedStatus) { + Text(L10n.Tasks.selectStatus).tag(nil as TaskStatus?) ForEach(taskStatuses, id: \.id) { status in Text(status.displayName).tag(status as TaskStatus?) } } } header: { - Text("Priority & Status") + Text(L10n.Tasks.priorityAndStatus) } footer: { - Text("Required: Both Priority and Status") + Text(L10n.Tasks.bothRequired) .font(.caption) .foregroundColor(Color.appError) } .listRowBackground(Color.appBackgroundSecondary) - Section(header: Text("Cost")) { - TextField("Estimated Cost (optional)", text: $estimatedCost) + Section(header: Text(L10n.Tasks.cost)) { + TextField(L10n.Tasks.estimatedCost, text: $estimatedCost) .keyboardType(.decimalPad) .focused($focusedField, equals: .estimatedCost) } @@ -227,7 +227,7 @@ struct TaskFormView: View { VStack(spacing: 16) { ProgressView() .scaleEffect(1.5) - Text("Loading...") + Text(L10n.Tasks.loading) .foregroundColor(Color.appTextSecondary) } .frame(maxWidth: .infinity, maxHeight: .infinity) @@ -237,18 +237,18 @@ struct TaskFormView: View { .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) - .navigationTitle(isEditMode ? "Edit Task" : "Add Task") + .navigationTitle(isEditMode ? L10n.Tasks.editTitle : L10n.Tasks.addTitle) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarLeading) { - Button("Cancel") { + Button(L10n.Common.cancel) { isPresented = false } .disabled(isLoadingLookups) } ToolbarItem(placement: .navigationBarTrailing) { - Button("Save") { + Button(L10n.Common.save) { submitForm() } .disabled(!canSave || viewModel.isLoading || isLoadingLookups) diff --git a/iosApp/iosApp/VerifyEmail/VerifyEmailView.swift b/iosApp/iosApp/VerifyEmail/VerifyEmailView.swift index f9aa16e..13b02f8 100644 --- a/iosApp/iosApp/VerifyEmail/VerifyEmailView.swift +++ b/iosApp/iosApp/VerifyEmail/VerifyEmailView.swift @@ -23,12 +23,12 @@ struct VerifyEmailView: View { .foregroundStyle(Color.appPrimary.gradient) .padding(.bottom, 8) - Text("Verify Your Email") + Text(L10n.Auth.verifyYourEmail) .font(.title) .fontWeight(.bold) .foregroundColor(Color.appTextPrimary) - Text("You must verify your email address to continue") + Text(L10n.Auth.verifyMustVerify) .font(.subheadline) .foregroundColor(Color.appTextSecondary) .multilineTextAlignment(.center) @@ -42,7 +42,7 @@ struct VerifyEmailView: View { .foregroundColor(Color.appAccent) .font(.title2) - Text("Email verification is required. Check your inbox for a 6-digit code.") + Text(L10n.Auth.verifyCheckInbox) .font(.subheadline) .foregroundColor(Color.appTextPrimary) .fontWeight(.semibold) @@ -53,7 +53,7 @@ struct VerifyEmailView: View { // Code Input VStack(alignment: .leading, spacing: 12) { - Text("Verification Code") + Text(L10n.Auth.verifyCodeLabel) .font(.headline) .foregroundColor(Color.appTextPrimary) .padding(.horizontal) @@ -76,7 +76,7 @@ struct VerifyEmailView: View { viewModel.code = newValue.filter { $0.isNumber } } - Text("Code must be 6 digits") + Text(L10n.Auth.verifyCodeMustBe6) .font(.caption) .foregroundColor(Color.appTextSecondary) .padding(.horizontal) @@ -98,7 +98,7 @@ struct VerifyEmailView: View { .progressViewStyle(CircularProgressViewStyle(tint: .white)) } else { Image(systemName: "checkmark.shield.fill") - Text("Verify Email") + Text(L10n.Auth.verifyEmailButton) .fontWeight(.semibold) } } @@ -118,7 +118,7 @@ struct VerifyEmailView: View { Spacer().frame(height: 20) // Help Text - Text("Didn't receive the code? Check your spam folder or contact support.") + Text(L10n.Auth.verifyHelpText) .font(.caption) .foregroundColor(Color.appTextSecondary) .multilineTextAlignment(.center) @@ -133,7 +133,7 @@ struct VerifyEmailView: View { HStack(spacing: 4) { Image(systemName: "rectangle.portrait.and.arrow.right") .font(.system(size: 16)) - Text("Logout") + Text(L10n.Auth.logout) .font(.subheadline) } }